Пример #1
0
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;
        }
    }
}
Пример #2
0
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;
}
Пример #3
0
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;
}
Пример #4
0
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;
}
Пример #5
0
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;
    }
}
Пример #6
0
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;
}
Пример #7
0
/* 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);
    }
}