Beispiel #1
0
/*
 * @overload write(data)
 *
 *  Writes +data+ to LOB.
 *
 *  @param [String] data
 *  @return [Integer] number of characters written if +self+ is a {CLOB} or a {NCLOB}.
 *    number of bytes written if +self+ is a {BLOB} or a {BFILE}.
 */
static VALUE oci8_lob_write(VALUE self, VALUE data)
{
    oci8_lob_t *lob = TO_LOB(self);
    oci8_svcctx_t *svcctx = check_svcctx(lob);
    volatile VALUE str;
    ub8 byte_amt;
    ub8 char_amt;

    lob_open(lob);
    if (TYPE(data) != T_STRING) {
        str = rb_obj_as_string(data);
    } else {
        str = data;
    }
    if (lob->lobtype == OCI_TEMP_CLOB) {
        str = rb_str_export_to_enc(str, oci8_encoding);
    }
    byte_amt = RSTRING_LEN(str);
    if (byte_amt == 0) {
        /* to avoid ORA-24801: illegal parameter value in OCI lob function */
        return INT2FIX(0);
    }
    char_amt = 0;
    chker2(OCILobWrite2_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, &byte_amt, &char_amt, lob->pos + 1, RSTRING_PTR(str), byte_amt, OCI_ONE_PIECE, NULL, NULL, 0, lob->csfrm),
           &svcctx->base);
    RB_GC_GUARD(str);
    if (lob->lobtype == OCI_TEMP_CLOB) {
        lob->pos += char_amt;
        return UINT2NUM(char_amt);
    } else {
        lob->pos += byte_amt;
        return UINT2NUM(byte_amt);
    }
}
Beispiel #2
0
static ub8 oci8_lob_get_length(oci8_lob_t *lob)
{
    oci8_svcctx_t *svcctx = check_svcctx(lob);
    ub8 len;

    chker2(OCILobGetLength2_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, &len),
           &svcctx->base);
    return len;
}
Beispiel #3
0
/*
 *  call-seq:
 *    truncate(length)
 *
 *  @param [Integer] length length in characters if +self+ is a {CLOB} or a {NCLOB}.
 *    length in bytes if +self+ is a {BLOB} or a {BFILE}.
 *  @return [self]
 *  @see #size=
 */
static VALUE oci8_lob_truncate(VALUE self, VALUE len)
{
    oci8_lob_t *lob = TO_LOB(self);
    oci8_svcctx_t *svcctx = check_svcctx(lob);

    chker2(OCILobTrim2_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, NUM2ULL(len)),
           &svcctx->base);
    return self;
}
Beispiel #4
0
/*
 *  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);
}
Beispiel #5
0
static void bfile_close(oci8_lob_t *lob)
{
    if (lob->state == S_BFILE_OPEN) {
        oci8_svcctx_t *svcctx = check_svcctx(lob);

        chker2(OCILobFileClose_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob),
               &svcctx->base);
        lob->state = S_BFILE_CLOSE;
    }
}
Beispiel #6
0
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;
    }
}
Beispiel #7
0
/*
 * @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;
}
Beispiel #8
0
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;
}
Beispiel #9
0
/*
 * @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;
    }
}