static void open_bfile(oci8_svcctx_t *svcctx, oci8_lob_t *lob, OCIError *errhp) { while (1) { sword rv = OCILobFileOpen_nb(svcctx, svcctx->base.hp.svc, 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) { chker2(OCILobFileClose_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, tmp->base.hp.lob), &svcctx->base); tmp->state = S_BFILE_CLOSE; } } } } else { chker2(rv, &svcctx->base); lob->state = S_BFILE_OPEN; return; } } }
static VALUE blocking_function_execute(blocking_region_arg_t *arg) { oci8_svcctx_t *svcctx = arg->svcctx; void *(*func)(void *) = arg->func; void *data = arg->data; struct timeval tv; sword rv; tv.tv_sec = 0; tv.tv_usec = 10000; svcctx->executing_thread = rb_thread_current(); while ((rv = (sword)(VALUE)func(data)) == OCI_STILL_EXECUTING) { rb_thread_wait_for(tv); if (tv.tv_usec < 500000) tv.tv_usec <<= 1; } if (rv == OCI_ERROR) { if (oci8_get_error_code(oci8_errhp) == 1013) { OCIReset(svcctx->base.hp.ptr, oci8_errhp); svcctx->executing_thread = Qnil; rb_raise(eOCIBreak, "Canceled by user request."); } } svcctx->executing_thread = Qnil; return rv; }
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; }
static VALUE protected_call(VALUE data) { struct protected_call_arg *parg = (struct protected_call_arg*)data; VALUE rv; if (!NIL_P(parg->svcctx->executing_thread)) { rb_raise(rb_eRuntimeError, "executing in another thread"); } RB_OBJ_WRITE(parg->svcctx->base.self, &parg->svcctx->executing_thread, rb_thread_current()); #ifdef HAVE_RB_THREAD_CALL_WITHOUT_GVL rv = (VALUE)rb_thread_call_without_gvl(parg->func, parg->data, oci8_unblock_func, parg->svcctx); #else rv = rb_thread_blocking_region((VALUE(*)(void*))parg->func, parg->data, oci8_unblock_func, parg->svcctx); #endif if ((sword)rv == OCI_ERROR) { if (oci8_get_error_code(oci8_errhp) == 1013) { rb_raise(eOCIBreak, "Canceled by user request."); } } return rv; }
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; } }
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; }
/* ruby 1.9 */ sword oci8_call_without_gvl(oci8_svcctx_t *svcctx, void *(*func)(void *), void *data) { OCIError *errhp = oci8_errhp; if (!NIL_P(svcctx->executing_thread)) { rb_raise(rb_eRuntimeError /* FIXME */, "executing in another thread"); } if (!svcctx->suppress_free_temp_lobs) { oci8_temp_lob_t *lob = svcctx->temp_lobs; while (lob != NULL) { oci8_temp_lob_t *lob_next = lob->next; if (svcctx->non_blocking) { free_temp_lob_arg_t arg; sword rv; arg.svcctx = svcctx; arg.svchp = svcctx->base.hp.svc; arg.errhp = errhp; arg.lob = lob->lob; svcctx->executing_thread = rb_thread_current(); #ifdef HAVE_RB_THREAD_CALL_WITHOUT_GVL rv = (sword)(VALUE)rb_thread_call_without_gvl(free_temp_lob, &arg, oci8_unblock_func, svcctx); #else rv = (sword)rb_thread_blocking_region((VALUE(*)(void*))free_temp_lob, &arg, oci8_unblock_func, svcctx); #endif if (rv == OCI_ERROR) { if (oci8_get_error_code(errhp) == 1013) { rb_raise(eOCIBreak, "Canceled by user request."); } } } else { OCILobFreeTemporary(svcctx->base.hp.svc, errhp, lob->lob); } OCIDescriptorFree(lob->lob, OCI_DTYPE_LOB); xfree(lob); svcctx->temp_lobs = lob = lob_next; } } if (svcctx->non_blocking) { sword rv; svcctx->executing_thread = rb_thread_current(); /* Note: executing_thread is cleard at the end of the blocking function. */ #ifdef HAVE_RB_THREAD_CALL_WITHOUT_GVL rv = (sword)(VALUE)rb_thread_call_without_gvl(func, data, oci8_unblock_func, svcctx); #else rv = (sword)rb_thread_blocking_region((VALUE(*)(void*))func, data, oci8_unblock_func, svcctx); #endif if (rv == OCI_ERROR) { if (oci8_get_error_code(errhp) == 1013) { rb_raise(eOCIBreak, "Canceled by user request."); } } return rv; } else { return (sword)(VALUE)func(data); } }