/* * 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); sword rv; while (svcctx->base.children != NULL) { oci8_base_free(svcctx->base.children); } switch (svcctx->logon_type) { case T_IMPLICIT: oci_lc(OCITransRollback_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, OCI_DEFAULT)); rv = OCILogoff_nb(svcctx, svcctx->base.hp.svc, oci8_errhp); svcctx->base.type = 0; svcctx->logon_type = T_NOT_LOGIN; if (rv != OCI_SUCCESS) oci8_raise(oci8_errhp, rv, NULL); svcctx->authhp = NULL; svcctx->srvhp = NULL; break; case T_EXPLICIT: oci_lc(OCITransRollback_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, OCI_DEFAULT)); rv = OCISessionEnd_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, svcctx->authhp, OCI_DEFAULT); if (rv == OCI_SUCCESS) { rv = OCIServerDetach_nb(svcctx, svcctx->srvhp, oci8_errhp, OCI_DEFAULT); } svcctx->logon_type = T_NOT_LOGIN; if (rv != OCI_SUCCESS) oci8_raise(oci8_errhp, rv, NULL); break; case T_NOT_LOGIN: break; } return Qtrue; }
static VALUE get_rowid_attr(rowid_arg_t *arg) { oci8_base_t *base = arg->base; ub4 attrtype = arg->attrtype; char buf[MAX_ROWID_LEN]; ub2 buflen; sword rv; /* get a rowid descriptor from OCIHandle */ rv = OCIDescriptorAlloc(oci8_envhp, (dvoid*)&arg->ridp, OCI_DTYPE_ROWID, 0, NULL); if (rv != OCI_SUCCESS) oci8_env_raise(oci8_envhp, rv); rv = OCIAttrGet(base->hp.ptr, base->type, arg->ridp, 0, attrtype, oci8_errhp); if (rv != OCI_SUCCESS) { oci8_raise(oci8_errhp, rv, NULL); } /* convert the rowid descriptor to a string. */ if (have_OCIRowidToChar) { /* If OCIRowidToChar is available, use it. */ buflen = MAX_ROWID_LEN; rv = OCIRowidToChar(arg->ridp, TO_ORATEXT(buf), &buflen, oci8_errhp); if (rv != OCI_SUCCESS) { oci8_raise(oci8_errhp, rv, NULL); } } else { /* If OCIRowidToChar is not available, convert it on * Oracle Server. */ oci8_base_t *svc; oci8_exec_sql_var_t define_var; oci8_exec_sql_var_t bind_var; /* search a connection from the handle */ svc = base; while (svc->type != OCI_HTYPE_SVCCTX) { svc = svc->parent; if (svc == NULL) { rb_raise(rb_eRuntimeError, "No connection is found!!"); } } /* :strval */ define_var.valuep = buf; define_var.value_sz = sizeof(buf); define_var.dty = SQLT_CHR; define_var.indp = NULL; define_var.alenp = &buflen; /* :rowid */ bind_var.valuep = &arg->ridp; bind_var.value_sz = sizeof(void *); bind_var.dty = SQLT_RDD; bind_var.indp = NULL; bind_var.alenp = NULL; /* convert the rowid descriptor to a string value by querying Oracle server. */ oci8_exec_sql((oci8_svcctx_t*)svc, "SELECT :rid FROM dual", 1, &define_var, 1, &bind_var, 1); if (buflen == 0) { return Qnil; } } return rb_external_str_new_with_enc(buf, buflen, rb_usascii_encoding()); }
/* =begin --- OCIStmt#execute(svc [, iters [, mode]]) execute statement at the ((<service context handle|OCISvcCtx>)). :svc ((<service context handle|OCISvcCtx>)) :iters the number of iterations to execute. For select statement, if there are columns which is not defined by ((<OCIStmt#defineByPos>)) and this value is positive, it raises exception. If zero, no exception. In any case you must define all columns before you call ((<OCIStmt#fetch>)). For non-select statement, use positive value. Default value is 0 for select statement, 1 for non-select statement. note: Current implemantation doesn't support array fetch and batch mode, so valid value is 0 or 1. :mode ((|OCI_DEFAULT|)), ((|OCI_BATCH_ERRORS|)), ((|OCI_COMMIT_ON_SUCCESS|)), ((|OCI_DESCRIBE_ONLY|)), ((|OCI_EXACT_FETCH|)), ((|OCI_PARSE_ONLY|)), any combinations of previous values, or ((|OCI_STMT_SCROLLABLE_READONLY|)). Default value is ((|OCI_DEFAULT|)). ((|OCI_BATCH_ERRORS|)) and ((|OCI_STMT_SCROLLABLE_READONLY|)) are not supported by current implementation. correspond native OCI function: ((|OCIStmtExecute|)) =end */ static VALUE oci8_stmt_execute(int argc, VALUE *argv, VALUE self) { VALUE vsvc; VALUE viters; VALUE vmode; oci8_handle_t *h; oci8_handle_t *svch; ub4 mode; ub4 iters; ub2 stmt_type; sword rv; rb_scan_args(argc, argv, "12", &vsvc, &viters, &vmode); Get_Handle(self, h); /* 0 */ Check_Handle(vsvc, OCISvcCtx, svch); /* 1 */ if (argc >= 2) { iters = NUM2UINT(viters); /* 2 */ } else { rv = OCIAttrGet(h->hp, OCI_HTYPE_STMT, &stmt_type, 0, OCI_ATTR_STMT_TYPE, h->errhp); if (rv != OCI_SUCCESS) { oci8_raise(h->errhp, rv, h->hp); } if (stmt_type == OCI_STMT_SELECT) { /* for select statement, default value 0. */ iters = 0; } else { /* for non-select statement, default value 0. */ iters = 1; } } Get_Int_With_Default(argc, 3, vmode, mode, OCI_DEFAULT); /* 3 */ if (iters > 1) { rb_raise(rb_eArgError, "current implementation doesn't support array fatch or batch mode"); } rv = OCIStmtExecute(svch->hp, h->hp, h->errhp, iters, 0, NULL, NULL, mode); if (rv == OCI_ERROR) { sb4 errcode; OCIErrorGet(h->errhp, 1, NULL, &errcode, NULL, 0, OCI_HTYPE_ERROR); if (errcode == 1000) { /* run GC to close unreferred cursors when ORA-01000 (maximum open cursors exceeded). */ rb_gc(); rv = OCIStmtExecute(svch->hp, h->hp, h->errhp, iters, 0, NULL, NULL, mode); } } if (IS_OCI_ERROR(rv)) { oci8_raise(h->errhp, rv, h->hp); } return self; }
/* =begin --- OCIStmt#fetch([nrows [, orientation [, mode]]]) fetch data from select statement. fetched data are stored to previously defined ((<define handle|OCIDefine>)). :nrows number of rows to fetch. If zero, cancel the cursor. The default value is 1. Because array fetch is not supported, valid value is 0 or 1. :orientation orientation to fetch. ((|OCI_FETCH_NEXT|)) only valid. The default value is ((|OCI_FETCH_NEXT|)). :mode ((|OCI_DEFULT|)) only valid. The default value is ((|OCI_DEFAULT|)). :return value array of define handles, which are defined previously, or nil when end of data. correspond native OCI function: ((|OCIStmtFetch|)) =end */ static VALUE oci8_stmt_fetch(int argc, VALUE *argv, VALUE self) { VALUE vnrows; VALUE vorientation; VALUE vmode; oci8_handle_t *h; ub4 nrows; ub2 orientation; ub4 mode; sword rv; rb_scan_args(argc, argv, "03", &vnrows, &vorientation, &vmode); Get_Handle(self, h); /* 0 */ Get_Int_With_Default(argc, 1, vnrows, nrows, 1); /* 1 */ Get_Int_With_Default(argc, 2, vorientation, orientation, OCI_FETCH_NEXT); /* 2 */ Get_Int_With_Default(argc, 3, vmode, mode, OCI_DEFAULT); /* 3 */ rv = OCIStmtFetch(h->hp, h->errhp, nrows, orientation, mode); if (rv == OCI_NO_DATA) { return Qnil; } if (IS_OCI_ERROR(rv)) { oci8_raise(h->errhp, rv, h->hp); } return rb_ivar_get(self, oci8_id_define_array); }
VALUE oci8_get_sb2_attr(oci8_base_t *base, ub4 attrtype) { sb2 val; sword rv; rv = OCIAttrGet(base->hp.ptr, base->type, &val, NULL, attrtype, oci8_errhp); if (rv != OCI_SUCCESS) oci8_raise(oci8_errhp, rv, NULL); return INT2FIX(val); }
VALUE oci8_reset(VALUE self) { oci8_handle_t *h; sword rv; Get_Handle(self, h); /* 0 */ rv = OCIReset(h->hp, h->errhp); if (rv != OCI_SUCCESS) oci8_raise(h->errhp, rv, NULL); return self; }
VALUE oci8_get_string_attr(oci8_base_t *base, ub4 attrtype) { text *val; ub4 size; sword rv; rv = OCIAttrGet(base->hp.ptr, base->type, &val, &size, attrtype, oci8_errhp); if (rv != OCI_SUCCESS) oci8_raise(oci8_errhp, rv, NULL); return rb_external_str_new_with_enc(TO_CHARPTR(val), size, oci8_encoding); }
/* =begin --- OCIServer#version() get server version. :return value string of server version. For example Oracle8 Release 8.0.5.0.0 - Production PL/SQL Release 8.0.5.0.0 - Production correspond native OCI function: ((|OCIServerVersion|)) =end */ VALUE oci8_server_version(VALUE self) { oci8_handle_t *h; OraText buf[1024]; sword rv; Get_Handle(self, h); /* 0 */ rv = OCIServerVersion(h->hp, h->errhp, buf, sizeof(buf), h->type); if (rv != OCI_SUCCESS) oci8_raise(h->errhp, rv, NULL); return rb_str_new2(TO_CHARPTR(buf)); }
/* =begin --- OCISvcCtx#logoff() disconnect from Oracle. If you use ((<OCIServer#attach>)) and ((<OCISession#begin>)) to logon, use ((<OCIServer#detach>)) and ((<OCISession#end>)) instead. See also ((<Simplified Logon>)) and ((<Explicit Attach and Begin Session>)). correspond native OCI function: ((|OCILogoff|)) =end */ static VALUE oci8_svcctx_logoff(VALUE self) { oci8_handle_t *h; sword rv; Get_Handle(self, h); /* 0 */ rv = OCILogoff(h->hp, h->errhp); if (rv != OCI_SUCCESS) oci8_raise(h->errhp, rv, NULL); return self; }
static VALUE oci8_close_all_files(VALUE self) { oci8_handle_t *h; sword rv; Get_Handle(self, h); /* 0 */ rv = OCILobFileCloseAll(h->hp, h->errhp); if (rv != OCI_SUCCESS) { oci8_raise(h->errhp, rv, NULL); } return self; }
VALUE oci8_server_release(VALUE self) { oci8_handle_t *h; OraText buf[1024]; ub4 version = 0; sword rv; Get_Handle(self, h); /* 0 */ rv = OCIServerRelease(h->hp, h->errhp, buf, sizeof(buf), h->type, &version); if (rv != OCI_SUCCESS) oci8_raise(h->errhp, rv, NULL); return rb_ary_new3(2, INT2FIX(version), rb_str_new2(buf)); }
/* =begin --- OCIStmt#bindByName(name, type [, length [, mode]]) define the datatype of the bind variable by name. :name the name of the bind variable including colon. :type the type of the bind variable. ((|String|)), ((|Fixnum|)), ((|Integer|)), ((|Float|)), ((|Time|)), ((<OraDate>)), ((<OraNumber>)), or ((|OCI_TYPECODE_RAW|)) :length When the 2nd argument is * ((|String|)) or ((|OCI_TYPECODE_RAW|)), the max length of fetched data. * otherwise, its value is ignored. :mode ((|OCI_DEFAULT|)), or ((|OCI_DATA_AT_EXEC|)). But now available value is ((|OCI_DEFAULT|)) only. Default value is ((|OCI_DEFAULT|)) :return value newly created ((<bind handle|OCIBind>)) for example stmt = env.alloc(OCIStmt) stmt.prepare("SELECT * FROM EMP WHERE ename = :ENAME AND sal > :SAL AND hiredate >= :HIREDATE") b_ename = stmt.bindByName(":ENAME", String, 10) b_sal = stmt.bindByName(":SAL", Fixnum) b_hiredate = stmt.bindByName(":HIREDATE", OraDate) correspond native OCI function: ((|OCIBindByName|)) =end */ static VALUE oci8_bind_by_name(int argc, VALUE *argv, VALUE self) { VALUE vplaceholder; VALUE vtype; VALUE vlength; VALUE vmode; oci8_handle_t *h; oci8_string_t placeholder; oci8_bind_handle_t *bh; ub2 dty; ub4 mode; dvoid *indp; ub2 *rlenp; dvoid *valuep; OCIBind *bindhp = NULL; sword status; VALUE hash; VALUE obj; rb_scan_args(argc, argv, "22", &vplaceholder, &vtype, &vlength, &vmode); Get_Handle(self, h); /* 0 */ Get_String(vplaceholder, placeholder); /* 1 */ check_bind_type(OCI_HTYPE_BIND, h, vtype, vlength, &bh, &dty); /* 2, 3 */ Get_Int_With_Default(argc, 4, vmode, mode, OCI_DEFAULT); /* 4 */ if (mode & OCI_DATA_AT_EXEC) { indp = NULL; rlenp = NULL; } else { indp = &(bh->ind); rlenp = (bh->bind_type == BIND_STRING) ? NULL : &bh->rlen; } valuep = &bh->value; status = OCIBindByName(h->hp, &bindhp, h->errhp, placeholder.ptr, placeholder.len, valuep, bh->value_sz, dty, indp, rlenp, 0, 0, 0, mode); if (status != OCI_SUCCESS) { oci8_unlink((oci8_handle_t *)bh); bh->type = 0; oci8_raise(h->errhp, status, h->hp); } bh->type = OCI_HTYPE_BIND; bh->hp = bindhp; bh->errhp = h->errhp; obj = bh->self; hash = rb_ivar_get(self, oci8_id_bind_hash); if (hash == Qnil) { hash = rb_hash_new(); rb_ivar_set(self, oci8_id_bind_hash, hash); } rb_hash_aset(hash, vplaceholder, obj); return obj; }
/* =begin --- OCIStmt#defineByPos(position, type [, length [, mode]]) define the datatype of fetched column. You must define all column's datatype, before you fetch data. :position the position of the column. It starts from 1. :type the type of column. ((|String|)), ((|Fixnum|)), ((|Integer|)), ((|Float|)), ((|Time|)), ((<OraDate>)), ((<OraNumber>)), or ((|OCI_TYPECODE_RAW|)) :length When the 2nd argument is * ((|String|)) or ((|OCI_TYPECODE_RAW|)), the max length of fetched data. * otherwise, its value is ignored. :mode ((|OCI_DEFAULT|)), or ((|OCI_DYNAMIC_FETCH|)). But now available value is ((|OCI_DEFAULT|)) only. Default value is ((|OCI_DEFAULT|)) :return value newly created ((<define handle|OCIDefine>)) correspond native OCI function: ((|OCIDefineByPos|)) =end */ static VALUE oci8_define_by_pos(int argc, VALUE *argv, VALUE self) { VALUE vposition; VALUE vtype; VALUE vlength; VALUE vmode; oci8_handle_t *h; ub4 position; oci8_bind_handle_t *bh; ub2 dty; ub4 mode; dvoid *indp; ub2 *rlenp; dvoid *valuep; OCIDefine *dfnhp = NULL; sword status; VALUE ary; VALUE obj; rb_scan_args(argc, argv, "22", &vposition, &vtype, &vlength, &vmode); Get_Handle(self, h); /* 0 */ position = NUM2INT(vposition); /* 1 */ check_bind_type(OCI_HTYPE_DEFINE, h, vtype, vlength, &bh, &dty); /* 2, 3 */ Get_Int_With_Default(argc, 4, vmode, mode, OCI_DEFAULT); /* 4 */ if (mode & OCI_DYNAMIC_FETCH) { indp = NULL; rlenp = NULL; } else { indp = &(bh->ind); rlenp = (bh->bind_type == BIND_STRING) ? NULL : &bh->rlen; } valuep = &bh->value; status = OCIDefineByPos(h->hp, &dfnhp, h->errhp, position, valuep, bh->value_sz, dty, indp, rlenp, 0, mode); if (status != OCI_SUCCESS) { oci8_unlink((oci8_handle_t *)bh); bh->type = 0; oci8_raise(h->errhp, status, h->hp); } bh->type = OCI_HTYPE_DEFINE; bh->hp = dfnhp; bh->errhp = h->errhp; obj = bh->self; ary = rb_ivar_get(self, oci8_id_define_array); if (ary == Qnil) { ary = rb_ary_new(); rb_ivar_set(self, oci8_id_define_array, ary); } rb_ary_store(ary, position - 1, obj); return obj; }
VALUE oci8_get_ub4_attr(oci8_base_t *base, ub4 attrtype) { ub4 val; sword rv; rv = OCIAttrGet(base->hp.ptr, base->type, &val, NULL, attrtype, oci8_errhp); if (rv != OCI_SUCCESS) oci8_raise(oci8_errhp, rv, NULL); #if SIZEOF_LONG > 4 return LONG2FIX(val); #else return ULONG2NUM(val); #endif }
/* * call-seq: * onum.to_char(fmt = nil, nls_params = nil) -> string * * Returns a string containing a representation of self. * <i>fmt</i> and <i>nls_params</i> are same meanings with * <code>TO_CHAR</code> of Oracle function. */ static VALUE onum_to_char(int argc, VALUE *argv, VALUE self) { OCIError *errhp = oci8_errhp; VALUE fmt; VALUE nls_params; char buf[512]; ub4 buf_size = sizeof(buf); oratext *fmt_ptr; oratext *nls_params_ptr; ub4 fmt_len; ub4 nls_params_len; sword rv; rb_scan_args(argc, argv, "02", &fmt /* nil */, &nls_params /* nil */); if (NIL_P(fmt)) { rv = oranumber_to_str(_NUMBER(self), buf, sizeof(buf)); if (rv > 0) { return rb_usascii_str_new(buf, rv); } oranumber_dump(_NUMBER(self), buf); rb_raise(eOCIException, "Invalid internal number format: %s", buf); } StringValue(fmt); fmt_ptr = RSTRING_ORATEXT(fmt); fmt_len = RSTRING_LEN(fmt); if (NIL_P(nls_params)) { nls_params_ptr = NULL; nls_params_len = 0; } else { StringValue(nls_params); nls_params_ptr = RSTRING_ORATEXT(nls_params); nls_params_len = RSTRING_LEN(nls_params); } rv = OCINumberToText(errhp, _NUMBER(self), fmt_ptr, fmt_len, nls_params_ptr, nls_params_len, &buf_size, TO_ORATEXT(buf)); if (rv == OCI_ERROR) { sb4 errcode; OCIErrorGet(errhp, 1, NULL, &errcode, NULL, 0, OCI_HTYPE_ERROR); if (errcode == 22065) { /* OCI-22065: number to text translation for the given format causes overflow */ if (NIL_P(fmt)) /* implicit conversion */ return rb_usascii_str_new_cstr("overflow"); } oci8_raise(errhp, rv, NULL); } return rb_usascii_str_new(buf, buf_size); }
static VALUE get_param(oci8_handle_t *hp, ub4 attr) { OCIParam *parmhp; ub4 as = 0; oci8_handle_t *parmh; oci8_handle_t *parenth; sword rv; rv = OCIAttrGet(hp->hp, hp->type, &parmhp, &as, attr, hp->errhp); if (rv != OCI_SUCCESS) oci8_raise(hp->errhp, rv, NULL); for (parenth = hp; parenth->type == OCI_DTYPE_PARAM; parenth = parenth->parent); parmh = oci8_make_handle(OCI_DTYPE_PARAM, parmhp, hp->errhp, parenth, 0); return parmh->self; }
static void call_session_end(oci8_svcctx_t *svcctx) { sword rv = OCI_SUCCESS; if (svcctx->state & OCI8_STATE_SESSION_BEGIN_WAS_CALLED) { rv = OCISessionEnd_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, svcctx->session->hp.authhp, OCI_DEFAULT); svcctx->state &= ~OCI8_STATE_SESSION_BEGIN_WAS_CALLED; } if (svcctx->state & OCI8_STATE_SERVER_ATTACH_WAS_CALLED) { rv = OCIServerDetach_nb(svcctx, svcctx->server->hp.srvhp, oci8_errhp, OCI_DEFAULT); svcctx->state &= ~OCI8_STATE_SERVER_ATTACH_WAS_CALLED; } svcctx->logoff_method = NULL; if (rv != OCI_SUCCESS) { oci8_raise(oci8_errhp, rv, NULL); } }
/* =begin --- OCIServer#detach([mode]) detach from the database. :mode ((|OCI_DEFAULT|)) only valid. Default value is ((|OCI_DEFAULT|)). correspond native OCI function: ((|OCIServerDetach|)) =end */ static VALUE oci8_server_detach(int argc, VALUE *argv, VALUE self) { VALUE vmode; oci8_handle_t *h; ub4 mode; sword rv; rb_scan_args(argc, argv, "01", &vmode); Get_Handle(self, h); /* 0 */ Get_Int_With_Default(argc, 1, vmode, mode, OCI_DEFAULT); /* 1 */ rv = OCIServerDetach(h->hp, h->errhp, mode); if (rv != OCI_SUCCESS) oci8_raise(h->errhp, rv, NULL); return self; }
/* =begin --- OCISvcCtx#rollback([flags]) rollback the transaction. :flags ((|OCI_DEFAULT|)) only valid. Default value is ((|OCI_DEFAULT|)). correspond native OCI function: ((|OCITransRollback|)) =end */ static VALUE oci8_trans_rollback(int argc, VALUE *argv, VALUE self) { VALUE vflags; oci8_handle_t *h; ub4 flags; sword rv; rb_scan_args(argc, argv, "01", &vflags); Get_Handle(self, h); /* 0 */ Get_Int_With_Default(argc, 1, vflags, flags, OCI_DEFAULT); /* 1 */ rv = OCITransRollback(h->hp, h->errhp, flags); if (rv != OCI_SUCCESS) { oci8_raise(h->errhp, rv, NULL); } return self; }
/* =begin --- OCISession#end(svc [, vmode]) terminate user Authentication Context :svc ((<OCISvcCtx>)). :mode ((|OCI_DEFAULT|)) only valid. Defalt value is ((|OCI_DEFAULT|)). correspond native OCI function: ((|OCISessionEnd|)) =end */ static VALUE oci8_session_end(int argc, VALUE *argv, VALUE self) { VALUE vsvc, vmode; oci8_handle_t *h; oci8_handle_t *svch; ub4 mode; sword rv; rb_scan_args(argc, argv, "11", &vsvc, &vmode); Get_Handle(self, h); /* 0 */ Check_Handle(vsvc, OCISvcCtx, svch); /* 1 */ Get_Int_With_Default(argc, 2, vmode, mode, OCI_DEFAULT); /* 2 */ rv = OCISessionEnd(svch->hp, h->errhp, h->hp, mode); if (rv != OCI_SUCCESS) oci8_raise(h->errhp, rv, NULL); return self; }
/* * call-seq: * break * * Cancels the executing SQL. * * See also #non_blocking=. */ static VALUE oci8_break(VALUE self) { oci8_svcctx_t *svcctx = DATA_PTR(self); #ifndef HAVE_RB_THREAD_BLOCKING_REGION sword rv; #endif if (NIL_P(svcctx->executing_thread)) { return Qfalse; } #ifndef HAVE_RB_THREAD_BLOCKING_REGION rv = OCIBreak(svcctx->base.hp.ptr, oci8_errhp); if (rv != OCI_SUCCESS) oci8_raise(oci8_errhp, rv, NULL); #endif rb_thread_wakeup(svcctx->executing_thread); return Qtrue; }
/* =begin --- OCIServer#attach(dbname [, mode]) attach to the database. :dbname the name of database. :mode ((|OCI_DEFAULT|)) or ((|OCI_CPOOL|))(Oracle 9i). Default value is ((|OCI_DEFAULT|)). This ruby module doesn't support the connection pooling provided by OCI, so ((|OCI_CPOOL|)) is invalid value for now. correspond native OCI function: ((|OCIServerAttach|)) =end */ static VALUE oci8_server_attach(int argc, VALUE *argv, VALUE self) { VALUE vdbname, vmode; oci8_handle_t *h; oci8_string_t d; ub4 mode; sword rv; rb_scan_args(argc, argv, "11", &vdbname, &vmode); Get_Handle(self, h); /* 0 */ Get_String(vdbname, d); /* 1 */ Get_Int_With_Default(argc, 2, vmode, mode, OCI_DEFAULT); /* 2 */ rv = OCIServerAttach(h->hp, h->errhp, d.ptr, d.len, mode); if (rv != OCI_SUCCESS) oci8_raise(h->errhp, rv, NULL); return self; }
/* =begin --- OCIStmt#prepare(stmt [, language [, mode]]) set and prepare SQL statement. :stmt SQL or PL/SQL statement :language ((|OCI_NTV_SYNTAX|)), ((|OCI_V7_SYNTAX|)), or ((|OCI_V8_SYNTAX|)). Default value is ((|OCI_NTV_SYNTAX|)) :mode ((|OCI_DEFAULT|)) or ((|OCI_NO_SHARING|)). Default value is ((|OCI_DEFAULT|)). ((|OCI_NO_SHARING|)) disables ((<Shared Data Mode>)) for this statement. correspond native OCI function: ((|OCIStmtPrepare|)) =end */ static VALUE oci8_stmt_prepare(int argc, VALUE *argv, VALUE self) { VALUE vsql, vlanguage, vmode; oci8_handle_t *h; oci8_string_t s; ub4 language; ub4 mode; sword rv; VALUE ary; VALUE hash; int i; rb_scan_args(argc, argv, "12", &vsql, &vlanguage, &vmode); Get_Handle(self, h); /* 0 */ Get_String(vsql, s); /* 1 */ Get_Int_With_Default(argc, 2, vlanguage, language, OCI_NTV_SYNTAX); /* 2 */ Get_Int_With_Default(argc, 3, vmode, mode, OCI_DEFAULT); /* 3 */ /* when a new statement is prepared, OCI implicitly free the previous * statement's define and bind handles. * But ruby's object don't know it. So free these handles in advance. */ /* free define handles */ ary = rb_ivar_get(self, oci8_id_define_array); if (ary != Qnil) { for (i = 0;i < RARRAY_LEN(ary);i++) { if (RARRAY_PTR(ary)[i] != Qnil) oci8_handle_free(RARRAY_PTR(ary)[i]); } rb_ivar_set(self, oci8_id_define_array, Qnil); } /* free bind handles */ hash = rb_ivar_get(self, oci8_id_bind_hash); if (hash != Qnil) { rb_iterate(oci8_each_value, hash, oci8_handle_free, Qnil); rb_ivar_set(self, oci8_id_bind_hash, Qnil); } rv = OCIStmtPrepare(h->hp, h->errhp, s.ptr, s.len, language, mode); if (IS_OCI_ERROR(rv)) { oci8_raise(h->errhp, rv, h->hp); } return self; }
/* THIS WILL BE DELETED IN FUTURE RELEASE. */ static VALUE oci8_describe_any(VALUE self, VALUE vdsc, VALUE vname, VALUE vtype) { oci8_handle_t *h; oci8_handle_t *dsch; oci8_string_t name; ub1 type; sword rv; Get_Handle(self, h); /* 0 */ Check_Handle(vdsc, OCIDescribe, dsch); /* 1 */ Get_String(vname, name); /* 2 */ type = FIX2INT(vtype); /* 3 */ rv = OCIDescribeAny(h->hp, h->errhp, name.ptr, name.len, OCI_OTYPE_NAME, OCI_DEFAULT, type, dsch->hp); if (rv != OCI_SUCCESS) { oci8_raise(h->errhp, rv, NULL); } return self; }
/* =begin --- OCISvcCtx#passwordChange(username, old_password, new_password [, mode]) :username the username. :old_password old password of the user. :new_password new password of the user. :mode ((|OCI_DEFAULT|)) or ((|OCI_AUTH|)). Default value is ((|OCI_DEFAULT|)). For most cases, use default value. If you want to know detail, see "Oracle Call Interface Programmer's Guide". correspond native OCI function: ((|OCIPasswordChange|)) =end */ static VALUE oci8_password_change(int argc, VALUE *argv, VALUE self) { VALUE vusername, vopasswd, vnpasswd, vmode; oci8_handle_t *h; oci8_string_t username, opasswd, npasswd; ub4 mode; sword rv; rb_scan_args(argc, argv, "31", &vusername, &vopasswd, &vnpasswd, &vmode); Get_Handle(self, h); /* 0 */ Get_String(vusername, username); /* 1 */ Get_String(vopasswd, opasswd); /* 2 */ Get_String(vnpasswd, npasswd); /* 3 */ Get_Int_With_Default(argc, 4, vmode, mode, OCI_DEFAULT); /* 4 */ rv = OCIPasswordChange(h->hp, h->errhp, username.ptr, username.len, opasswd.ptr, opasswd.len, npasswd.ptr, npasswd.len, mode); if (rv != OCI_SUCCESS) { oci8_raise(h->errhp, rv, NULL); } 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 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; } }
/* * call-seq: * new(username, password, dbname = nil, privilege = nil) * * Connects to an Oracle database server by +username+ and +password+ * at +dbname+ as +privilege+. * * === connecting to the local server * * Set +username+ and +password+ or pass "username/password" as a * single argument. * * OCI8.new('scott', 'tiger') * or * OCI8.new('scott/tiger') * * === connecting to a remote server * * Set +username+, +password+ and +dbname+ or pass * "username/password@dbname" as a single argument. * * OCI8.new('scott', 'tiger', 'orcl.world') * or * OCI8.new('scott/[email protected]') * * The +dbname+ is a net service name or an easy connectection * identifier. The former is a name listed in the file tnsnames.ora. * Ask to your DBA if you don't know what it is. The latter has the * syntax as "//host:port/service_name". * * OCI8.new('scott', 'tiger', '//remote-host:1521/XE') * or * OCI8.new('scott/tiger@//remote-host:1521/XE') * * === connecting as a privileged user * * Set :SYSDBA or :SYSOPER to +privilege+, otherwise * "username/password as sysdba" or "username/password as sysoper" * as a single argument. * * OCI8.new('sys', 'change_on_install', nil, :SYSDBA) * or * OCI8.new('sys/change_on_install as sysdba') * * === external OS authentication * * Set nil to +username+ and +password+, or "/" as a single argument. * * OCI8.new(nil, nil) * or * OCI8.new('/') * * To connect to a remote host: * * OCI8.new(nil, nil, 'dbname') * or * OCI8.new('/@dbname') * * === proxy authentication * * Enclose end user's username with square brackets and add it at the * end of proxy user's username. * * OCI8.new('proxy_user_name[end_user_name]', 'proxy_password') * or * OCI8.new('proxy_user_name[end_user_name]/proxy_password') * */ static VALUE oci8_svcctx_initialize(int argc, VALUE *argv, VALUE self) { VALUE vusername; VALUE vpassword; VALUE vdbname; VALUE vmode; oci8_svcctx_t *svcctx = DATA_PTR(self); sword rv; enum logon_type_t logon_type = T_IMPLICIT; ub4 cred = OCI_CRED_RDBMS; ub4 mode = OCI_DEFAULT; OCISvcCtx *svchp = NULL; svcctx->executing_thread = Qnil; if (argc == 1) { oci8_do_parse_connect_string(argv[0], &vusername, &vpassword, &vdbname, &vmode); } else { rb_scan_args(argc, argv, "22", &vusername, &vpassword, &vdbname, &vmode); } rb_ivar_set(self, id_at_prefetch_rows, Qnil); rb_ivar_set(self, id_at_username, Qnil); if (NIL_P(vusername) && NIL_P(vpassword)) { /* external credential */ logon_type = T_EXPLICIT; cred = OCI_CRED_EXT; } else { /* RDBMS credential */ OCI8SafeStringValue(vusername); /* 1 */ OCI8SafeStringValue(vpassword); /* 2 */ } if (!NIL_P(vdbname)) { OCI8SafeStringValue(vdbname); /* 3 */ } if (!NIL_P(vmode)) { /* 4 */ logon_type = T_EXPLICIT; Check_Type(vmode, T_SYMBOL); if (vmode == sym_SYSDBA) { mode = OCI_SYSDBA; } else if (vmode == sym_SYSOPER) { mode = OCI_SYSOPER; } else { rb_raise(rb_eArgError, "invalid privilege name %s (expect :SYSDBA or :SYSOPER)", rb_id2name(SYM2ID(vmode))); } } switch (logon_type) { case T_IMPLICIT: rv = OCILogon_nb(svcctx, oci8_envhp, oci8_errhp, &svchp, RSTRING_ORATEXT(vusername), RSTRING_LEN(vusername), RSTRING_ORATEXT(vpassword), RSTRING_LEN(vpassword), NIL_P(vdbname) ? NULL : RSTRING_ORATEXT(vdbname), NIL_P(vdbname) ? 0 : RSTRING_LEN(vdbname)); svcctx->base.hp.svc = svchp; svcctx->base.type = OCI_HTYPE_SVCCTX; svcctx->logon_type = T_IMPLICIT; if (rv != OCI_SUCCESS) { oci8_raise(oci8_errhp, rv, NULL); } break; case T_EXPLICIT: /* allocate OCI handles. */ rv = OCIHandleAlloc(oci8_envhp, &svcctx->base.hp.ptr, OCI_HTYPE_SVCCTX, 0, 0); if (rv != OCI_SUCCESS) oci8_env_raise(oci8_envhp, rv); svcctx->base.type = OCI_HTYPE_SVCCTX; rv = OCIHandleAlloc(oci8_envhp, (void*)&svcctx->authhp, OCI_HTYPE_SESSION, 0, 0); if (rv != OCI_SUCCESS) oci8_env_raise(oci8_envhp, rv); rv = OCIHandleAlloc(oci8_envhp, (void*)&svcctx->srvhp, OCI_HTYPE_SERVER, 0, 0); if (rv != OCI_SUCCESS) oci8_env_raise(oci8_envhp, rv); /* set username and password to OCISession. */ if (cred == OCI_CRED_RDBMS) { oci_lc(OCIAttrSet(svcctx->authhp, OCI_HTYPE_SESSION, RSTRING_PTR(vusername), RSTRING_LEN(vusername), OCI_ATTR_USERNAME, oci8_errhp)); oci_lc(OCIAttrSet(svcctx->authhp, OCI_HTYPE_SESSION, RSTRING_PTR(vpassword), RSTRING_LEN(vpassword), OCI_ATTR_PASSWORD, oci8_errhp)); } /* attach to server and set to OCISvcCtx. */ rv = OCIServerAttach_nb(svcctx, svcctx->srvhp, oci8_errhp, NIL_P(vdbname) ? NULL : RSTRING_ORATEXT(vdbname), NIL_P(vdbname) ? 0 : RSTRING_LEN(vdbname), OCI_DEFAULT); if (rv != OCI_SUCCESS) oci8_raise(oci8_errhp, rv, NULL); oci_lc(OCIAttrSet(svcctx->base.hp.ptr, OCI_HTYPE_SVCCTX, svcctx->srvhp, 0, OCI_ATTR_SERVER, oci8_errhp)); /* begin session. */ rv = OCISessionBegin_nb(svcctx, svcctx->base.hp.ptr, oci8_errhp, svcctx->authhp, cred, mode); if (rv != OCI_SUCCESS) oci8_raise(oci8_errhp, rv, NULL); oci_lc(OCIAttrSet(svcctx->base.hp.ptr, OCI_HTYPE_SVCCTX, svcctx->authhp, 0, OCI_ATTR_SESSION, oci8_errhp)); svcctx->logon_type = T_EXPLICIT; break; default: break; } svcctx->pid = getpid(); svcctx->is_autocommit = 0; #ifdef RUBY_VM svcctx->non_blocking = 1; #endif svcctx->long_read_len = INT2FIX(65535); return Qnil; }