/* * call-seq: * server_attach(dbname, mode) * * <b>internal use only</b> * * Attachs to the server by the OCI function OCIServerAttach(). */ static VALUE oci8_server_attach(VALUE self, VALUE dbname, VALUE mode) { oci8_svcctx_t *svcctx = oci8_get_svcctx(self); if (svcctx->logoff_strategy != &complex_logoff) { rb_raise(rb_eRuntimeError, "Use this method only for the service context handle created by OCI8#server_handle()."); } if (svcctx->state & OCI8_STATE_SERVER_ATTACH_WAS_CALLED) { rb_raise(rb_eRuntimeError, "Could not use this method twice."); } /* check arguments */ if (!NIL_P(dbname)) { OCI8SafeStringValue(dbname); } Check_Type(mode, T_FIXNUM); /* attach to the server */ oci_lc(OCIServerAttach_nb(svcctx, svcctx->srvhp, oci8_errhp, NIL_P(dbname) ? NULL : RSTRING_ORATEXT(dbname), NIL_P(dbname) ? 0 : RSTRING_LEN(dbname), FIX2UINT(mode))); oci_lc(OCIAttrSet(svcctx->base.hp.ptr, OCI_HTYPE_SVCCTX, svcctx->srvhp, 0, OCI_ATTR_SERVER, oci8_errhp)); svcctx->state |= OCI8_STATE_SERVER_ATTACH_WAS_CALLED; return self; }
/* * call-seq: * client_info = string or nil * * <b>(new in 2.0.3)</b> * * Sets additional information about the client application. * This information is stored in the V$SESSION view. * * === Oracle 10g client or upper * * This doesn't perform network round trips. The change is reflected * to the server by the next round trip such as OCI8#exec, OCI8#ping, * etc. * * === Oracle 9i client or lower * * This executes the following PL/SQL block internally. * The change is reflected immediately by a network round trip. * * BEGIN * DBMS_APPLICATION_INFO.SET_CLIENT_INFO(:client_info); * END; * * See {Oracle Manual: Oracle Database PL/SQL Packages and Types Reference}[http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14258/d_appinf.htm#CHEJCFGG] */ static VALUE oci8_set_client_info(VALUE self, VALUE val) { char *ptr; ub4 size; if (!NIL_P(val)) { OCI8SafeStringValue(val); ptr = RSTRING_PTR(val); size = RSTRING_LEN(val); } else { ptr = ""; size = 0; } if (oracle_client_version >= ORAVER_10_1) { /* Oracle 10g or upper */ oci_lc(OCIAttrSet(oci8_get_oci_session(self), OCI_HTYPE_SESSION, ptr, size, OCI_ATTR_CLIENT_INFO, oci8_errhp)); } else { /* Oracle 9i or lower */ oci8_exec_sql_var_t bind_vars[1]; /* :client_info */ bind_vars[0].valuep = ptr; bind_vars[0].value_sz = size; bind_vars[0].dty = SQLT_CHR; bind_vars[0].indp = NULL; bind_vars[0].alenp = NULL; oci8_exec_sql(oci8_get_svcctx(self), "BEGIN\n" " DBMS_APPLICATION_INFO.SET_CLIENT_INFO(:client_info);\n" "END;\n", 0, NULL, 1, bind_vars, 1); } return val; }
/* * @overload initialize(conn, directory = nil, filename = nil) * * Creates a BFILE object. * This is correspond to {BFILENAME}[https://docs.oracle.com/database/121/SQLRF/functions020.htm]. * * @param [OCI8] conn * @param [String] directory a directory object created by * {"CREATE DIRECTORY"}[http://docs.oracle.com/database/121/SQLRF/statements_5008.htm]. * @param [String] filename * @return [OCI8::BFILE] */ static VALUE oci8_bfile_initialize(int argc, VALUE *argv, VALUE self) { oci8_lob_t *lob = TO_LOB(self); VALUE svc; VALUE dir_alias; VALUE filename; oci8_svcctx_t *svcctx; int rv; rb_scan_args(argc, argv, "12", &svc, &dir_alias, &filename); svcctx = oci8_get_svcctx(svc); rv = OCIDescriptorAlloc(oci8_envhp, &lob->base.hp.ptr, OCI_DTYPE_LOB, 0, NULL); if (rv != OCI_SUCCESS) { oci8_env_raise(oci8_envhp, rv); } lob->base.type = OCI_DTYPE_LOB; lob->pos = 0; lob->csfrm = SQLCS_IMPLICIT; lob->lobtype = OCI_TEMP_BLOB; lob->state = S_BFILE_CLOSE; if (argc != 1) { OCI8SafeStringValue(dir_alias); OCI8SafeStringValue(filename); oci8_bfile_set_name(self, dir_alias, filename); } oci8_link_to_parent(&lob->base, &svcctx->base); lob->svcctx = svcctx; return Qnil; }
static VALUE oci8_lob_do_initialize(int argc, VALUE *argv, VALUE self, ub1 csfrm, ub1 lobtype) { oci8_lob_t *lob = TO_LOB(self); VALUE svc; VALUE val; oci8_svcctx_t *svcctx; sword rv; rb_scan_args(argc, argv, "11", &svc, &val); svcctx = oci8_get_svcctx(svc); rv = OCIDescriptorAlloc(oci8_envhp, &lob->base.hp.ptr, OCI_DTYPE_LOB, 0, NULL); if (rv != OCI_SUCCESS) oci8_env_raise(oci8_envhp, rv); lob->base.type = OCI_DTYPE_LOB; lob->pos = 0; lob->csfrm = csfrm; lob->lobtype = lobtype; lob->state = S_NO_OPEN_CLOSE; oci8_link_to_parent(&lob->base, &svcctx->base); lob->svcctx = svcctx; RB_OBJ_WRITTEN(self, Qundef, svc); if (!NIL_P(val)) { OCI8StringValue(val); chker2(OCILobCreateTemporary_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, 0, csfrm, lobtype, TRUE, OCI_DURATION_SESSION), &svcctx->base); oci8_lob_write(self, val); lob->pos = 0; /* reset the position */ } return Qnil; }
static VALUE oci8_lob_do_initialize(int argc, VALUE *argv, VALUE self, ub1 csfrm, ub1 lobtype) { oci8_lob_t *lob = DATA_PTR(self); VALUE svc; VALUE val; sword rv; rb_scan_args(argc, argv, "11", &svc, &val); TO_SVCCTX(svc); /* check argument type */ rv = OCIDescriptorAlloc(oci8_envhp, &lob->base.hp.ptr, OCI_DTYPE_LOB, 0, NULL); if (rv != OCI_SUCCESS) oci8_env_raise(oci8_envhp, rv); lob->base.type = OCI_DTYPE_LOB; lob->svc = svc; lob->svchp = NULL; lob->pos = 0; lob->char_width = 1; lob->csfrm = csfrm; lob->lobtype = lobtype; lob->state = S_NO_OPEN_CLOSE; oci8_link_to_parent((oci8_base_t*)lob, (oci8_base_t*)DATA_PTR(svc)); if (!NIL_P(val)) { if (have_OCILobCreateTemporary_nb) { oci8_svcctx_t *svcctx = oci8_get_svcctx(svc); OCI8StringValue(val); oci_lc(OCILobCreateTemporary_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, 0, csfrm, lobtype, TRUE, OCI_DURATION_SESSION)); lob->svchp = oci8_get_oci_svcctx(svc); oci8_lob_write(self, val); } else { rb_raise(rb_eRuntimeError, "creating a temporary lob is not supported on this Oracle version"); } } return Qnil; }
static ub4 oci8_lob_get_length(oci8_lob_t *lob) { oci8_svcctx_t *svcctx = oci8_get_svcctx(lob->svc); ub4 len; oci_lc(OCILobGetLength_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, &len)); return len; }
static VALUE oci8_lob_truncate(VALUE self, VALUE len) { oci8_lob_t *lob = DATA_PTR(self); oci8_svcctx_t *svcctx = oci8_get_svcctx(lob->svc); lob_open(lob); oci_lc(OCILobTrim_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, NUM2UINT(len))); return self; }
static VALUE oci8_bfile_exists_p(VALUE self) { oci8_lob_t *lob = DATA_PTR(self); oci8_svcctx_t *svcctx = oci8_get_svcctx(lob->svc); boolean flag; oci_lc(OCILobFileExists_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, &flag)); return flag ? Qtrue : Qfalse; }
static void bfile_close(oci8_lob_t *lob) { if (lob->state == S_BFILE_OPEN) { oci8_svcctx_t *svcctx = oci8_get_svcctx(lob->svc); oci_lc(OCILobFileClose_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob)); lob->state = S_BFILE_CLOSE; } }
OCISession *oci8_get_oci_session(VALUE obj) { oci8_svcctx_t *svcctx = oci8_get_svcctx(obj); if (svcctx->authhp == NULL) { oci_lc(OCIAttrGet(svcctx->base.hp.ptr, OCI_HTYPE_SVCCTX, &svcctx->authhp, 0, OCI_ATTR_SESSION, oci8_errhp)); } return svcctx->authhp; }
static void lob_close(oci8_lob_t *lob) { if (lob->state == S_OPEN) { if (have_OCILobClose_nb) { oci8_svcctx_t *svcctx = oci8_get_svcctx(lob->svc); oci_lc(OCILobClose_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob)); } lob->state = S_CLOSE; } }
static void lob_open(oci8_lob_t *lob) { if (lob->state == S_CLOSE) { if (have_OCILobOpen_nb) { oci8_svcctx_t *svcctx = oci8_get_svcctx(lob->svc); oci_lc(OCILobOpen_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, OCI_DEFAULT)); } lob->state = S_OPEN; } }
static VALUE oci8_lob_get_chunk_size(VALUE self) { if (have_OCILobGetChunkSize_nb) { oci8_lob_t *lob = DATA_PTR(self); oci8_svcctx_t *svcctx = oci8_get_svcctx(lob->svc); ub4 len; oci_lc(OCILobGetChunkSize_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, &len)); return UINT2NUM(len); } else { rb_notimplement(); } }
/* * call-seq: * ping -> true or false * * <b>(new in 2.0.2)</b> * * Makes a round trip call to the server to confirm that the connection and * the server are active. * * OCI8#ping also can be used to flush all the pending OCI client-side calls * to the server if any exist. * * === Oracle 10.2 client or upper * A dummy round trip call is made by a newly added OCI function * OCIPing[http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14250/oci16msc007.htm#sthref3540] in Oracle 10.2. * * === Oracle 10.1 client or lower * A simple PL/SQL block "BEGIN NULL; END;" is executed to make a round trip call. */ static VALUE oci8_ping(VALUE self) { oci8_svcctx_t *svcctx = oci8_get_svcctx(self); sword rv; if (have_OCIPing_nb) { /* Oracle 10.2 or upper */ rv = OCIPing_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, OCI_DEFAULT); } else { /* Oracle 10.1 or lower */ rv = oci8_exec_sql(svcctx, "BEGIN NULL; END;", 0U, NULL, 0U, NULL, 0); } return rv == OCI_SUCCESS ? Qtrue : FALSE; }
/* * call-seq: * client_identifier = string or nil * * <b>(new in 2.0.3)</b> * * Sets the client ID. This information is stored in the V$SESSION * view. * * === Oracle 9i client or upper * * This doesn't perform network round trips. The change is reflected * to the server by the next round trip such as OCI8#exec, OCI8#ping, * etc. * * === Oracle 8i client or lower * * This executes the following PL/SQL block internally. * The change is reflected immediately by a network round trip. * * BEGIN * DBMS_SESSION.SET_IDENTIFIER(:client_id); * END; * * See {Oracle Manual: Oracle Database PL/SQL Packages and Types Reference}[http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14258/d_sessio.htm#i996935] * */ static VALUE oci8_set_client_identifier(VALUE self, VALUE val) { char *ptr; ub4 size; int use_attr_set = 1; if (!NIL_P(val)) { OCI8SafeStringValue(val); ptr = RSTRING_PTR(val); size = RSTRING_LEN(val); } else { ptr = ""; size = 0; } if (oracle_client_version < ORAVER_9_0) { use_attr_set = 0; } else if (oracle_client_version < ORAVERNUM(9, 2, 0, 3, 0) && size == 0) { /* Workaround for Bug 2449486 */ use_attr_set = 0; } if (use_attr_set) { if (size > 0 && ptr[0] == ':') { rb_raise(rb_eArgError, "client identifier should not start with ':'."); } oci_lc(OCIAttrSet(oci8_get_oci_session(self), OCI_HTYPE_SESSION, ptr, size, OCI_ATTR_CLIENT_IDENTIFIER, oci8_errhp)); } else { oci8_exec_sql_var_t bind_vars[1]; /* :client_id */ bind_vars[0].valuep = ptr; bind_vars[0].value_sz = size; bind_vars[0].dty = SQLT_CHR; bind_vars[0].indp = NULL; bind_vars[0].alenp = NULL; oci8_exec_sql(oci8_get_svcctx(self), "BEGIN\n" " DBMS_SESSION.SET_IDENTIFIER(:client_id);\n" "END;\n", 0, NULL, 1, bind_vars, 1); } return val; }
static VALUE oci8_lob_write(VALUE self, VALUE data) { oci8_lob_t *lob = DATA_PTR(self); oci8_svcctx_t *svcctx = oci8_get_svcctx(lob->svc); ub4 amt; lob_open(lob); if (TYPE(data) != T_STRING) { data = rb_obj_as_string(data); } if (lob->lobtype == OCI_TEMP_CLOB) { data = rb_str_export_to_enc(data, oci8_encoding); } RB_GC_GUARD(data); amt = RSTRING_LEN(data); oci_lc(OCILobWrite_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, &amt, lob->pos + 1, RSTRING_PTR(data), amt, OCI_ONE_PIECE, NULL, NULL, 0, lob->csfrm)); lob->pos += amt; return UINT2NUM(amt); }
/* * call-seq: * module = string or nil * * <b>(new in 2.0.3)</b> * * Sets the name of the current module. This information is * stored in the V$SESSION view and is also stored in the V$SQL view * and the V$SQLAREA view when a SQL statement is executed and the SQL * statement is first parsed in the Oracle server. * * === Oracle 10g client or upper * * This doesn't perform network round trips. The change is reflected * to the server by the next round trip such as OCI8#exec, OCI8#ping, * etc. * * === Oracle 9i client or lower * * This executes the following PL/SQL block internally. * The change is reflected immediately by a network round trip. * * DECLARE * action VARCHAR2(32); * BEGIN * -- retrieve action name. * SELECT SYS_CONTEXT('USERENV','ACTION') INTO action FROM DUAL; * -- change module name without modifying the action name. * DBMS_APPLICATION_INFO.SET_MODULE(:module, action); * END; * * See {Oracle Manual: Oracle Database PL/SQL Packages and Types Reference}[http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14258/d_appinf.htm#i999254] * */ static VALUE oci8_set_module(VALUE self, VALUE val) { const char *ptr; ub4 size; if (!NIL_P(val)) { OCI8SafeStringValue(val); ptr = RSTRING_PTR(val); size = RSTRING_LEN(val); } else { ptr = ""; size = 0; } if (oracle_client_version >= ORAVER_10_1) { /* Oracle 10g or upper */ chker2(OCIAttrSet(oci8_get_oci_session(self), OCI_HTYPE_SESSION, (dvoid*)ptr, size, OCI_ATTR_MODULE, oci8_errhp), DATA_PTR(self)); } else { /* Oracle 9i or lower */ oci8_exec_sql_var_t bind_vars[1]; /* :module */ bind_vars[0].valuep = (dvoid*)ptr; bind_vars[0].value_sz = size; bind_vars[0].dty = SQLT_CHR; bind_vars[0].indp = NULL; bind_vars[0].alenp = NULL; oci8_exec_sql(oci8_get_svcctx(self), "DECLARE\n" " action VARCHAR2(32);\n" "BEGIN\n" " SELECT SYS_CONTEXT('USERENV','ACTION') INTO action FROM DUAL;\n" " DBMS_APPLICATION_INFO.SET_MODULE(:module, action);\n" "END;\n", 0, NULL, 1, bind_vars, 1); } return self; }
static VALUE oci8_lob_clone(VALUE self) { oci8_lob_t *lob = DATA_PTR(self); oci8_lob_t *newlob; VALUE newobj; sword rv; boolean is_temporary; newobj = rb_funcall(CLASS_OF(self), oci8_id_new, 1, lob->svc); newlob = DATA_PTR(newobj); if (have_OCILobLocatorAssign_nb && have_OCILobIsTemporary && OCILobIsTemporary(oci8_envhp, oci8_errhp, lob->base.hp.lob, &is_temporary) == OCI_SUCCESS && is_temporary) { oci8_svcctx_t *svcctx = oci8_get_svcctx(lob->svc); rv = OCILobLocatorAssign_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, &newlob->base.hp.lob); } else { rv = OCILobAssign(oci8_envhp, oci8_errhp, lob->base.hp.lob, &newlob->base.hp.lob); } if (rv != OCI_SUCCESS) { oci8_raise(oci8_errhp, rv, NULL); } return newobj; }
static void bind_ocitimestamp_tz_init(oci8_bind_t *obind, VALUE svc, VALUE val, VALUE length) { oci8_link_to_parent((oci8_base_t*)obind, (oci8_base_t*)oci8_get_svcctx(svc)); obind->value_sz = sizeof(OCIDateTime *); obind->alloc_sz = sizeof(OCIDateTime *); }
OCISession *oci8_get_oci_session(VALUE obj) { oci8_svcctx_t *svcctx = oci8_get_svcctx(obj); return svcctx->usrhp; }
OCISvcCtx *oci8_get_oci_svcctx(VALUE obj) { oci8_svcctx_t *svcctx = oci8_get_svcctx(obj); return svcctx->base.hp.svc; }
/* * call-seq: * server_handle -> a server handle * * <b>internal use only</b> * * Returns a server handle associated with the service context handle. */ static VALUE oci8_get_server_handle(VALUE self) { oci8_svcctx_t *svcctx = oci8_get_svcctx(self); return svcctx->server->self; }
static VALUE oci8_lob_read(int argc, VALUE *argv, VALUE self) { oci8_lob_t *lob = DATA_PTR(self); oci8_svcctx_t *svcctx = oci8_get_svcctx(lob->svc); ub4 length; ub4 nchar; ub4 amt; sword rv; char buf[8192]; size_t buf_size_in_char; VALUE size; VALUE v = rb_ary_new(); rb_scan_args(argc, argv, "01", &size); length = oci8_lob_get_length(lob); if (length <= lob->pos) /* EOF */ return Qnil; length -= lob->pos; if (NIL_P(size)) { nchar = length; /* read until EOF */ } else { nchar = NUM2UINT(size); if (nchar > length) nchar = length; } amt = nchar; buf_size_in_char = sizeof(buf) / lob->char_width; do { if (lob->state == S_BFILE_CLOSE) { rv = OCILobFileOpen_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, OCI_FILE_READONLY); if (rv == OCI_ERROR && oci8_get_error_code(oci8_errhp) == 22290) { /* ORA-22290: operation would exceed the maximum number of opened files or LOBs */ /* close all opened BFILE implicitly. */ oci8_base_t *base; for (base = &lob->base; base != &lob->base; base = base->next) { if (base->type == OCI_DTYPE_LOB) { oci8_lob_t *tmp = (oci8_lob_t *)base; if (tmp->state == S_BFILE_OPEN) { tmp->state = S_BFILE_CLOSE; } } } oci_lc(OCILobFileCloseAll_nb(svcctx, svcctx->base.hp.svc, oci8_errhp)); continue; } if (rv != OCI_SUCCESS) oci8_raise(oci8_errhp, rv, NULL); lob->state = S_BFILE_OPEN; } /* initialize buf in zeros everytime to check a nul characters. */ memset(buf, 0, sizeof(buf)); rv = OCILobRead_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, &amt, lob->pos + 1, buf, sizeof(buf), NULL, NULL, 0, lob->csfrm); if (rv == OCI_ERROR && oci8_get_error_code(oci8_errhp) == 22289) { /* ORA-22289: cannot perform FILEREAD operation on an unopened file or LOB */ if (lob->state == S_BFILE_CLOSE) continue; } if (rv != OCI_SUCCESS && rv != OCI_NEED_DATA) oci8_raise(oci8_errhp, rv, NULL); /* Workaround when using Oracle 10.2.0.4 or 11.1.0.6 client and * variable-length character set (e.g. AL32UTF8). * * When the above mentioned condition, amt may be shorter. So * amt is increaded until a nul character to know the actually * read size. */ while (amt < sizeof(buf) && buf[amt] != '\0') { amt++; } if (amt == 0) break; /* for fixed size charset, amt is the number of characters stored in buf. */ if (amt > buf_size_in_char) rb_raise(eOCIException, "Too large buffer fetched or you set too large size of a character."); amt *= lob->char_width; rb_ary_push(v, rb_str_new(buf, amt)); } while (rv == OCI_NEED_DATA); lob->pos += nchar; if (nchar == length) { lob_close(lob); bfile_close(lob); } if (RARRAY_LEN(v) == 0) { return Qnil; } v = rb_ary_join(v, Qnil); OBJ_TAINT(v); if (lob->lobtype == OCI_TEMP_CLOB) { /* set encoding */ rb_enc_associate(v, oci8_encoding); return rb_str_conv_enc(v, oci8_encoding, rb_default_internal_encoding()); } else { /* ASCII-8BIT */ return v; } }