static void lob_close(oci8_lob_t *lob) { if (lob->state == S_OPEN) { oci8_svcctx_t *svcctx = check_svcctx(lob); chker2(OCILobClose_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob), &svcctx->base); lob->state = S_CLOSE; } }
/* * @overload exists? * * Returns <code>true</code> when the BFILE exists on the server's operating system. */ static VALUE oci8_bfile_exists_p(VALUE self) { oci8_lob_t *lob = TO_LOB(self); oci8_svcctx_t *svcctx = check_svcctx(lob); boolean flag; chker2(OCILobFileExists_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, &flag), &svcctx->base); return flag ? Qtrue : Qfalse; }
/* * call-seq: * non_blocking = true or false * * Sets +true+ to enable non-blocking mode, +false+ otherwise. * The default setting depends on the ruby version and ruby-oci8 * version. * * When the connection is in blocking mode (non_blocking = false), * SQL executions block not only the thread, but also the ruby * process. It makes the whole application stop while a SQL execution * needs long time. * * When in non-blocking mode (non_blocking = true), SQL executions * block only the thread. It does't prevent other threads. * A SQL execution which blocks a thread can be canceled by * OCI8#break. * * === ruby 1.9 * The default setting is +true+ if the ruby-oci8 version is 2.0.3 or * upper, +false+ otherwise. * * Ruby-oci8 makes the connection non-blocking by releasing ruby * interpreter's GVL (Global VM Lock or Giant VM Lock) while OCI * functions which may need more than one network round trips are in * execution. * * === ruby 1.8 * The default setting is +false+. * * Ruby-oci8 makes the connection non-blocking by polling the return * values of OCI functions. When an OCI function returns * OCI_STILL_EXECUTING, the thread sleeps for 10 milli seconds to make * a time for other threads to run. The sleep time is doubled up to * 640 milli seconds as the function returns the same value. * */ static VALUE oci8_set_non_blocking(VALUE self, VALUE val) { oci8_svcctx_t *svcctx = DATA_PTR(self); #ifdef HAVE_RB_THREAD_BLOCKING_REGION svcctx->non_blocking = RTEST(val); #else sb1 non_blocking; if (svcctx->state & OCI8_STATE_CPOOL) { rb_raise(rb_eRuntimeError, "Could not set non-blocking mode to a connection allocated from OCI8::ConnectionPool."); } chker2(OCIAttrGet(svcctx->srvhp, OCI_HTYPE_SERVER, &non_blocking, 0, OCI_ATTR_NONBLOCKING_MODE, oci8_errhp), &svcctx->base); if ((RTEST(val) && !non_blocking) || (!RTEST(val) && non_blocking)) { /* toggle blocking / non-blocking. */ chker2(OCIAttrSet(svcctx->srvhp, OCI_HTYPE_SERVER, 0, 0, OCI_ATTR_NONBLOCKING_MODE, oci8_errhp), &svcctx->base); } #endif return val; }
/* * Returns the chunk size of a LOB. * * @see http://docs.oracle.com/database/121/ARPLS/d_lob.htm#ARPLS66706 DBMS_LOB.GETCHUNKSIZE * @return [Integer] */ static VALUE oci8_lob_get_chunk_size(VALUE self) { oci8_lob_t *lob = TO_LOB(self); oci8_svcctx_t *svcctx = check_svcctx(lob); ub4 len; chker2(OCILobGetChunkSize_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, &len), &svcctx->base); return UINT2NUM(len); }
static void lob_open(oci8_lob_t *lob) { if (lob->state == S_CLOSE) { oci8_svcctx_t *svcctx = check_svcctx(lob); chker2(OCILobOpen_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, OCI_DEFAULT), &svcctx->base); lob->state = S_OPEN; } }
static VALUE oci8_lob_clone(VALUE self) { oci8_lob_t *lob = TO_LOB(self); oci8_lob_t *newlob; VALUE newobj = lob->svcctx ? lob->svcctx->base.self : Qnil; boolean is_temporary; newobj = rb_class_new_instance(1, &newobj, CLASS_OF(self)); newlob = DATA_PTR(newobj); if (OCILobIsTemporary(oci8_envhp, oci8_errhp, lob->base.hp.lob, &is_temporary) == OCI_SUCCESS && is_temporary) { oci8_svcctx_t *svcctx = check_svcctx(lob); chker2(OCILobLocatorAssign_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, &newlob->base.hp.lob), &svcctx->base); } else { chker2(OCILobAssign(oci8_envhp, oci8_errhp, lob->base.hp.lob, &newlob->base.hp.lob), &lob->base); } return newobj; }
/* * call-seq: * attr_set_binary(attr_type, attr_value) * * Sets the value of an attribute as `ub1 *' datatype. * * @param [Fixnum] attr_type * @param [String] attr_value * @return [self] * * @since 2.0.4 * @private */ static VALUE attr_set_binary(VALUE self, VALUE attr_type, VALUE val) { oci8_base_t *base = DATA_PTR(self); /* validate arguments */ Check_Type(attr_type, T_FIXNUM); SafeStringValue(val); /* set attribute */ chker2(OCIAttrSet(base->hp.ptr, base->type, RSTRING_PTR(val), RSTRING_LEN(val), FIX2INT(attr_type), oci8_errhp), base); return self; }
/* * call-seq: * attr_set_integer(attr_type, number) * * Sets the value of an attribute as `ub1 *' datatype. * +number+ is converted to internal Oracle NUMBER format before * it is set. * * @param [Fixnum] attr_type * @param [Numeric] number * @return [self] * * @since 2.0.4 * @private */ static VALUE attr_set_integer(VALUE self, VALUE attr_type, VALUE val) { oci8_base_t *base = DATA_PTR(self); OCINumber value; /* validate arguments */ Check_Type(attr_type, T_FIXNUM); oci8_set_integer(&value, val, oci8_errhp); /* set attribute */ chker2(OCIAttrSet(base->hp.ptr, base->type, &value, sizeof(value), FIX2INT(attr_type), oci8_errhp), base); return self; }
/* * call-seq: * attr_set_boolean(attr_type, attr_value) * * Sets the value of an attribute as `boolean' datatype. * * @note If the specified attr_type's datatype is a * pointer type, it causes a segmentation fault. * * @param [Fixnum] attr_type * @param [true or false] attr_value * @return [self] * * @since 2.0.4 * @private */ static VALUE attr_set_boolean(VALUE self, VALUE attr_type, VALUE val) { oci8_base_t *base = DATA_PTR(self); boolean value; /* validate arguments */ Check_Type(attr_type, T_FIXNUM); value = RTEST(val) ? TRUE : FALSE; /* set attribute */ chker2(OCIAttrSet(base->hp.ptr, base->type, &value, sizeof(value), FIX2INT(attr_type), oci8_errhp), base); return self; }
/* * call-seq: * attr_set_sb2(attr_type, attr_value) * * Sets the value of an attribute as `sb2' datatype. * * @note If the specified attr_type's datatype is a * pointer type, it causes a segmentation fault. * * @param [Fixnum] attr_type * @param [Fixnum] attr_value * @return [self] * * @since 2.0.4 * @private */ static VALUE attr_set_sb2(VALUE self, VALUE attr_type, VALUE val) { oci8_base_t *base = DATA_PTR(self); sb2 value; /* validate arguments */ Check_Type(attr_type, T_FIXNUM); value = (sb2)check_data_range(val, SHRT_MIN, SHRT_MAX, "sb2"); /* set attribute */ chker2(OCIAttrSet(base->hp.ptr, base->type, &value, sizeof(value), FIX2INT(attr_type), oci8_errhp), base); return self; }
/* * call-seq: * attr_set_ub8(attr_type, attr_value) * * Sets the value of an attribute as `ub8' datatype. * * @note If the specified attr_type's datatype is a * pointer type, it causes a segmentation fault. * * @param [Fixnum] attr_type * @param [Integer] attr_value * @return [self] * * @since 2.0.4 * @private */ static VALUE attr_set_ub8(VALUE self, VALUE attr_type, VALUE val) { oci8_base_t *base = DATA_PTR(self); ub8 value; /* validate arguments */ Check_Type(attr_type, T_FIXNUM); value = NUM2ULL(val); /* set attribute */ chker2(OCIAttrSet(base->hp.ptr, base->type, &value, sizeof(value), FIX2INT(attr_type), oci8_errhp), base); return self; }
/* * call-seq: * non_blocking? -> true or false * * Returns +true+ if the connection is in non-blocking mode, +false+ * otherwise. * * See also #non_blocking=. */ static VALUE oci8_non_blocking_p(VALUE self) { oci8_svcctx_t *svcctx = DATA_PTR(self); #ifdef HAVE_RB_THREAD_BLOCKING_REGION return svcctx->non_blocking ? Qtrue : Qfalse; #else sb1 non_blocking; chker2(OCIAttrGet(svcctx->srvhp, OCI_HTYPE_SERVER, &non_blocking, 0, OCI_ATTR_NONBLOCKING_MODE, oci8_errhp), &svcctx->base); return non_blocking ? Qtrue : Qfalse; #endif }
/* * call-seq: * break * * Cancels the executing SQL. * * See also #non_blocking=. */ static VALUE oci8_break(VALUE self) { oci8_svcctx_t *svcctx = DATA_PTR(self); if (NIL_P(svcctx->executing_thread)) { return Qfalse; } #ifndef HAVE_RB_THREAD_BLOCKING_REGION chker2(OCIBreak(svcctx->base.hp.ptr, oci8_errhp), &svcctx->base); #endif rb_thread_wakeup(svcctx->executing_thread); return Qtrue; }
/* * call-seq: * attr_get_boolean(attr_type) * * Gets the value of an attribute as `boolean' datatype. * * @param [Fixnum] attr_type * @return [true of false] * * @since 2.0.4 * @private */ static VALUE attr_get_boolean(VALUE self, VALUE attr_type) { oci8_base_t *base = DATA_PTR(self); union { boolean value; ub8 dummy; /* padding for incorrect attrtype to protect the stack */ } v; v.dummy = MAGIC_NUMBER; Check_Type(attr_type, T_FIXNUM); chker2(OCIAttrGet(base->hp.ptr, base->type, &v.value, NULL, FIX2INT(attr_type), oci8_errhp), base); return v.value ? Qtrue : Qfalse; }
/* * call-seq: * attr_get_sb4(attr_type) * * Gets the value of an attribute as `sb4' datatype. * * @param [Fixnum] attr_type * @return [Integer] * * @since 2.0.4 * @private */ static VALUE attr_get_sb4(VALUE self, VALUE attr_type) { oci8_base_t *base = DATA_PTR(self); union { sb4 value; ub8 dummy; } v; v.dummy = MAGIC_NUMBER; Check_Type(attr_type, T_FIXNUM); chker2(OCIAttrGet(base->hp.ptr, base->type, &v.value, NULL, FIX2INT(attr_type), oci8_errhp), base); return INT2NUM(v.value); }
/* * call-seq: * attr_get_binary(attr_type) * * Gets the value of an attribute as `ub1 *' datatype. * The return value is tagged with ASCII-8BIT when the ruby version is 1.9. * * @note If the specified attr_type's datatype is not a * pointer type, it causes a segmentation fault. * * @param [Fixnum] attr_type * @return [String] * * @since 2.0.4 * @private */ static VALUE attr_get_binary(VALUE self, VALUE attr_type) { oci8_base_t *base = DATA_PTR(self); union { char *value; ub8 dummy; /* padding for incorrect attrtype to protect the stack */ } v; ub4 size = 0; v.dummy = 0; Check_Type(attr_type, T_FIXNUM); chker2(OCIAttrGet(base->hp.ptr, base->type, &v.value, &size, FIX2INT(attr_type), oci8_errhp), base); return rb_tainted_str_new(v.value, size); }
/* * call-seq: * attr_get_string(attr_type) * * Gets the value of an attribute as `oratext *' datatype. * The return value is converted to Encoding.default_internal or * tagged with {OCI8.encoding} when the ruby version is 1.9. * * @note If the specified attr_type's datatype is not a * pointer type, it causes a segmentation fault. * * @param [Fixnum] attr_type * @return [String] * * @since 2.0.4 * @private */ static VALUE attr_get_string(VALUE self, VALUE attr_type) { oci8_base_t *base = DATA_PTR(self); union { char *value; ub8 dummy; /* padding for incorrect attrtype to protect the stack */ } v; ub4 size = 0; v.dummy = MAGIC_NUMBER; Check_Type(attr_type, T_FIXNUM); chker2(OCIAttrGet(base->hp.ptr, base->type, &v.value, &size, FIX2INT(attr_type), oci8_errhp), base); return rb_external_str_new_with_enc(v.value, size, oci8_encoding); }
/* * call-seq: * logon2(username, password, dbname, mode) -> connection * * <b>internal use only</b> * * Creates a simple logon session by the OCI function OCILogon2(). */ static VALUE oci8_logon2(VALUE self, VALUE username, VALUE password, VALUE dbname, VALUE mode) { oci8_svcctx_t *svcctx = DATA_PTR(self); if (svcctx->logoff_strategy != NULL) { rb_raise(rb_eRuntimeError, "Could not reuse the session."); } /* check arugmnets */ OCI8SafeStringValue(username); OCI8SafeStringValue(password); if (!NIL_P(dbname)) { OCI8SafeStringValue(dbname); } /* logon */ svcctx->base.type = OCI_HTYPE_SVCCTX; chker2(OCILogon2_nb(svcctx, oci8_envhp, oci8_errhp, &svcctx->base.hp.svc, RSTRING_ORATEXT(username), RSTRING_LEN(username), RSTRING_ORATEXT(password), RSTRING_LEN(password), NIL_P(dbname) ? NULL : RSTRING_ORATEXT(dbname), NIL_P(dbname) ? 0 : RSTRING_LEN(dbname), NUM2UINT(mode)), &svcctx->base); svcctx->logoff_strategy = &simple_logoff; /* setup the session handle */ chker2(OCIAttrGet(svcctx->base.hp.ptr, OCI_HTYPE_SVCCTX, &svcctx->usrhp, 0, OCI_ATTR_SESSION, oci8_errhp), &svcctx->base); copy_session_handle(svcctx); /* setup the server handle */ chker2(OCIAttrGet(svcctx->base.hp.ptr, OCI_HTYPE_SVCCTX, &svcctx->srvhp, 0, OCI_ATTR_SERVER, oci8_errhp), &svcctx->base); copy_server_handle(svcctx); return Qnil; }
static void oci8_bfile_set_name(VALUE self, VALUE dir_alias, VALUE filename) { oci8_lob_t *lob = TO_LOB(self); bfile_close(lob); if (RSTRING_LEN(dir_alias) > UB2MAXVAL) { rb_raise(rb_eRuntimeError, "dir_alias is too long."); } if (RSTRING_LEN(filename) > UB2MAXVAL) { rb_raise(rb_eRuntimeError, "filename is too long."); } chker2(OCILobFileSetName(oci8_envhp, oci8_errhp, &lob->base.hp.lob, RSTRING_ORATEXT(dir_alias), (ub2)RSTRING_LEN(dir_alias), RSTRING_ORATEXT(filename), (ub2)RSTRING_LEN(filename)), &lob->base); }
/* * call-seq: * logoff * * Disconnects from the Oracle server. The uncommitted transaction is * rollbacked. */ static VALUE oci8_svcctx_logoff(VALUE self) { oci8_svcctx_t *svcctx = (oci8_svcctx_t *)DATA_PTR(self); while (svcctx->base.children != NULL) { oci8_base_free(svcctx->base.children); } if (svcctx->logoff_strategy != NULL) { const oci8_logoff_strategy_t *strategy = svcctx->logoff_strategy; void *data = strategy->prepare(svcctx); svcctx->base.type = 0; svcctx->logoff_strategy = NULL; chker2(oci8_blocking_region(svcctx, strategy->execute, data), &svcctx->base); } return Qtrue; }
static VALUE exec_sql(cb_arg_t *arg) { ub4 pos; sword rv; rv = OCIHandleAlloc(oci8_envhp, (dvoid*)&arg->stmtp, OCI_HTYPE_STMT, 0, NULL); if (rv != OCI_SUCCESS) { oci8_env_raise(oci8_envhp, rv); } chker2(OCIStmtPrepare(arg->stmtp, oci8_errhp, (text*)arg->sql_text, strlen(arg->sql_text), OCI_NTV_SYNTAX, OCI_DEFAULT), &arg->svcctx->base); for (pos = 0; pos < arg->num_define_vars; pos++) { arg->define_vars[pos].hp = NULL; chker3(OCIDefineByPos(arg->stmtp, (OCIDefine**)&arg->define_vars[pos].hp, oci8_errhp, pos + 1, arg->define_vars[pos].valuep, arg->define_vars[pos].value_sz, arg->define_vars[pos].dty, arg->define_vars[pos].indp, arg->define_vars[pos].alenp, NULL, OCI_DEFAULT), &arg->svcctx->base, arg->stmtp); } for (pos = 0; pos < arg->num_bind_vars; pos++) { arg->bind_vars[pos].hp = NULL; chker3(OCIBindByPos(arg->stmtp, (OCIBind**)&arg->bind_vars[pos].hp, oci8_errhp, pos + 1, arg->bind_vars[pos].valuep, arg->bind_vars[pos].value_sz, arg->bind_vars[pos].dty, arg->bind_vars[pos].indp, arg->bind_vars[pos].alenp, NULL, 0, NULL, OCI_DEFAULT), &arg->svcctx->base, arg->stmtp); } rv = OCIStmtExecute_nb(arg->svcctx, arg->svcctx->base.hp.svc, arg->stmtp, oci8_errhp, 1, 0, NULL, NULL, OCI_DEFAULT); if (rv == OCI_ERROR) { if (oci8_get_error_code(oci8_errhp) == 1000) { /* run GC to close unreferred cursors * when ORA-01000 (maximum open cursors exceeded). */ rb_gc(); rv = OCIStmtExecute_nb(arg->svcctx, arg->svcctx->base.hp.svc, arg->stmtp, oci8_errhp, 1, 0, NULL, NULL, OCI_DEFAULT); } } if (arg->raise_on_error) { chker3(rv, &arg->svcctx->base, arg->stmtp); } return (VALUE)rv; }
/* * call-seq: * attr_get_integer(attr_type) -> integer * * Gets the value of an attribute as `ub1 *' datatype. * The return value is converted to Integer from internal Oracle NUMBER format. * * @note If the specified attr_type's datatype is not a * pointer type, it causes a segmentation fault. * * @param [Fixnum] attr_type * @return [Fixnum] * * @since 2.0.4 * @private */ static VALUE attr_get_integer(VALUE self, VALUE attr_type) { oci8_base_t *base = DATA_PTR(self); OCINumber onum; union { void *value; ub8 dummy; /* padding for incorrect attrtype to protect the stack */ } v; ub4 size = 0; v.dummy = 0; Check_Type(attr_type, T_FIXNUM); chker2(OCIAttrGet(base->hp.ptr, base->type, &v.value, &size, FIX2INT(attr_type), oci8_errhp), base); memset(&onum, 0, sizeof(onum)); onum.OCINumberPart[0] = size; memcpy(&onum.OCINumberPart[1], v.value, size); return oci8_make_integer(&onum, oci8_errhp); }
/* * 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; }
/* * 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) { 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 >= ORAVERNUM(9, 2, 0, 3, 0) || size > 0) { if (size > 0 && ptr[0] == ':') { rb_raise(rb_eArgError, "client identifier should not start with ':'."); } chker2(OCIAttrSet(oci8_get_oci_session(self), OCI_HTYPE_SESSION, (dvoid*)ptr, size, OCI_ATTR_CLIENT_IDENTIFIER, oci8_errhp), DATA_PTR(self)); } else { /* Workaround for Bug 2449486 */ oci8_exec_sql_var_t bind_vars[1]; /* :client_id */ 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), "BEGIN\n" " DBMS_SESSION.SET_IDENTIFIER(:client_id);\n" "END;\n", 0, NULL, 1, bind_vars, 1); } return val; }
/* * call-seq: * attr_get_oradate(attr_type) -> an OraDate * * Gets the value of an attribute as `ub1 *' datatype. * The return value is converted to OraDate. * * @note If the specified attr_type's datatype is not a * pointer type, it causes a segmentation fault. * * @param [Fixnum] attr_type * @return [OraDate] * * @since 2.0.4 * @private */ static VALUE attr_get_oradate(VALUE self, VALUE attr_type) { oci8_base_t *base = DATA_PTR(self); union { ub1 *value; ub8 dummy; /* padding for incorrect attrtype to protect the stack */ } v; ub4 size = 0; static VALUE cOraDate = RB_QNIL; v.dummy = 0; Check_Type(attr_type, T_FIXNUM); chker2(OCIAttrGet(base->hp.ptr, base->type, &v.value, &size, FIX2INT(attr_type), oci8_errhp), base); if (NIL_P(cOraDate)) cOraDate = RB_CLASS("OraDate"); return rb_funcall(cOraDate, oci8_id_new, 6, INT2FIX((v.value[0] - 100) * 100 + (v.value[1] - 100)), INT2FIX(v.value[2]), INT2FIX(v.value[3]), INT2FIX(v.value[4] - 1), INT2FIX(v.value[5] - 1), INT2FIX(v.value[6] - 1)); }
static void oci8_bfile_get_name(VALUE self, VALUE *dir_alias_p, VALUE *filename_p) { int need_get = 0; if (dir_alias_p != NULL) { *dir_alias_p = rb_ivar_get(self, id_dir_alias); if (NIL_P(*dir_alias_p)) need_get = 1; } if (filename_p != NULL) { *filename_p = rb_ivar_get(self, id_filename); if (NIL_P(*filename_p)) need_get = 1; } if (need_get) { oci8_lob_t *lob = TO_LOB(self); char d_buf[31]; ub2 d_length = sizeof(d_buf); char f_buf[256]; ub2 f_length = sizeof(f_buf); VALUE dir_alias; VALUE filename; chker2(OCILobFileGetName(oci8_envhp, oci8_errhp, lob->base.hp.lob, TO_ORATEXT(d_buf), &d_length, TO_ORATEXT(f_buf), &f_length), &lob->base); dir_alias = rb_external_str_new_with_enc(d_buf, d_length, oci8_encoding); filename = rb_external_str_new_with_enc(f_buf, f_length, oci8_encoding); rb_ivar_set(self, id_dir_alias, dir_alias); rb_ivar_set(self, id_filename, filename); if (dir_alias_p != NULL) { *dir_alias_p = dir_alias; } if (filename_p != NULL) { *filename_p = filename; } } }
/* * call-seq: * action = string or nil * * <b>(new in 2.0.3)</b> * * Sets the name of the current action within 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. * * BEGIN * DBMS_APPLICATION_INFO.SET_ACTION(: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_action(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_ACTION, oci8_errhp), DATA_PTR(self)); } else { /* Oracle 9i or lower */ oci8_exec_sql_var_t bind_vars[1]; /* :action */ 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), "BEGIN\n" " DBMS_APPLICATION_INFO.SET_ACTION(:action);\n" "END;\n", 0, NULL, 1, bind_vars, 1); } return val; }
/* * @overload read * * * * @param [Integer] length number of characters if +self+ is a {CLOB} or a {NCLOB}. * number of bytes if +self+ is a {BLOB} or a {BFILE}. * @return [String or nil] data read. <code>nil</code> means it * met EOF at beginning. It returns an empty string '' as a special exception * when <i>length</i> is <code>nil</code> and the lob is empty. * * @overload read(length) * * Reads <i>length</i> characters for {CLOB} and {NCLOB} or <i>length</i> * bytes for {BLOB} and {BFILE} from the current position. * If <i>length</i> is <code>nil</code>, it reads data until EOF. * * @param [Integer] length number of characters if +self+ is a {CLOB} or a {NCLOB}. * number of bytes if +self+ is a {BLOB} or a {BFILE}. * @return [String or nil] data read. <code>nil</code> means it * met EOF at beginning. It returns an empty string '' as a special exception * when <i>length</i> is <code>nil</code> and the lob is empty. */ static VALUE oci8_lob_read(int argc, VALUE *argv, VALUE self) { oci8_lob_t *lob = TO_LOB(self); oci8_svcctx_t *svcctx = check_svcctx(lob); ub8 lob_length; ub8 read_len; ub8 pos = lob->pos; long strbufsiz; ub8 byte_amt; ub8 char_amt; sword rv; VALUE size; VALUE v = rb_ary_new(); OCIError *errhp = oci8_errhp; ub1 piece = OCI_FIRST_PIECE; rb_scan_args(argc, argv, "01", &size); lob_length = oci8_lob_get_length(lob); if (lob_length == 0 && NIL_P(size)) { return rb_usascii_str_new("", 0); } if (lob_length <= pos) /* EOF */ return Qnil; if (NIL_P(size)) { read_len = lob_length - pos; } else { ub8 sz = NUM2ULL(size); read_len = MIN(sz, lob_length - pos); } if (lob->lobtype == OCI_TEMP_CLOB) { byte_amt = 0; char_amt = read_len; if (oci8_nls_ratio == 1) { strbufsiz = MIN(read_len, ULONG_MAX); } else { strbufsiz = MIN(read_len + read_len / 8, ULONG_MAX); } if (strbufsiz <= 10) { strbufsiz = 10; } } else { byte_amt = read_len; char_amt = 0; strbufsiz = MIN(read_len, ULONG_MAX); } if (lob->state == S_BFILE_CLOSE) { open_bfile(svcctx, lob, errhp); } do { VALUE strbuf = rb_str_buf_new(strbufsiz); char *buf = RSTRING_PTR(strbuf); rv = OCILobRead2_nb(svcctx, svcctx->base.hp.svc, errhp, lob->base.hp.lob, &byte_amt, &char_amt, pos + 1, buf, strbufsiz, piece, NULL, NULL, 0, lob->csfrm); svcctx->suppress_free_temp_lobs = 0; switch (rv) { case OCI_SUCCESS: break; case OCI_NEED_DATA: /* prevent OCILobFreeTemporary() from being called. * See: https://github.com/kubo/ruby-oci8/issues/20 */ svcctx->suppress_free_temp_lobs = 1; piece = OCI_NEXT_PIECE; break; default: chker2(rv, &svcctx->base); } if (byte_amt == 0) break; if (lob->lobtype == OCI_TEMP_CLOB) { pos += char_amt; } else { pos += byte_amt; } rb_str_set_len(strbuf, byte_amt); rb_ary_push(v, strbuf); } while (rv == OCI_NEED_DATA); if (pos >= lob_length) { lob_close(lob); bfile_close(lob); } lob->pos = pos; switch (RARRAY_LEN(v)) { case 0: return Qnil; case 1: v = RARRAY_AREF(v, 0); break; default: 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; } }
static VALUE attr_get_common(int argc, VALUE *argv, VALUE self, enum datatype datatype) { oci8_base_t *base = DATA_PTR(self); VALUE attr_type; VALUE strict; union { ub1 ub1val; ub2 ub2val; ub4 ub4val; ub8 ub8val; sb1 sb1val; sb2 sb2val; sb4 sb4val; sb8 sb8val; boolean booleanval; char *charptr; ub1 *ub1ptr; } v; ub4 size = 0; sword rv; v.ub8val = MAGIC_NUMBER; rb_scan_args(argc, argv, "11", &attr_type, &strict); if (argc == 1) { strict = Qtrue; } Check_Type(attr_type, T_FIXNUM); rv = OCIAttrGet(base->hp.ptr, base->type, &v, &size, FIX2INT(attr_type), oci8_errhp); if (!RTEST(strict)) { if (rv == OCI_ERROR && oci8_get_error_code(oci8_errhp) == 24328) { /* ignore ORA-24328: illegal attribute value */ return Qnil; } } chker2(rv, base); switch (datatype) { OCINumber onum; static VALUE cOraDate = Qnil; case DATATYPE_UB1: return INT2FIX(v.ub1val); case DATATYPE_UB2: return INT2FIX(v.ub2val); case DATATYPE_UB4: return UINT2NUM(v.ub4val); case DATATYPE_UB8: return ULL2NUM(v.ub8val); case DATATYPE_SB1: return INT2FIX(v.sb1val); case DATATYPE_SB2: return INT2FIX(v.sb2val); case DATATYPE_SB4: return INT2NUM(v.sb4val); case DATATYPE_SB8: return LL2NUM(v.sb8val); case DATATYPE_BOOLEAN: return v.booleanval ? Qtrue : Qfalse; case DATATYPE_STRING: if (size == 0 && !RTEST(strict)) { return Qnil; } return rb_external_str_new_with_enc(v.charptr, size, oci8_encoding); case DATATYPE_BINARY: return rb_tainted_str_new(v.charptr, size); case DATATYPE_INTEGER: if (size > sizeof(onum.OCINumberPart) - 1) { rb_raise(rb_eRuntimeError, "Too long size %u", size); } memset(&onum, 0, sizeof(onum)); onum.OCINumberPart[0] = size; memcpy(&onum.OCINumberPart[1], v.ub1ptr, size); return oci8_make_integer(&onum, oci8_errhp); case DATATYPE_ORADATE: if (NIL_P(cOraDate)) cOraDate = rb_eval_string("OraDate"); return rb_funcall(cOraDate, oci8_id_new, 6, INT2FIX((v.ub1ptr[0] - 100) * 100 + (v.ub1ptr[1] - 100)), INT2FIX(v.ub1ptr[2]), INT2FIX(v.ub1ptr[3]), INT2FIX(v.ub1ptr[4] - 1), INT2FIX(v.ub1ptr[5] - 1), INT2FIX(v.ub1ptr[6] - 1)); } return Qnil; }
/* * call-seq: * rollback * * Rollbacks the transaction. */ static VALUE oci8_rollback(VALUE self) { oci8_svcctx_t *svcctx = DATA_PTR(self); chker2(OCITransRollback_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, OCI_DEFAULT), &svcctx->base); return self; }