示例#1
0
static VALUE oci8_lob_do_initialize(int argc, VALUE *argv, VALUE self, ub1 csfrm, ub1 lobtype)
{
    oci8_lob_t *lob = TO_LOB(self);
    VALUE svc;
    VALUE val;
    oci8_svcctx_t *svcctx;
    sword rv;

    rb_scan_args(argc, argv, "11", &svc, &val);
    svcctx = oci8_get_svcctx(svc);
    rv = OCIDescriptorAlloc(oci8_envhp, &lob->base.hp.ptr, OCI_DTYPE_LOB, 0, NULL);
    if (rv != OCI_SUCCESS)
        oci8_env_raise(oci8_envhp, rv);
    lob->base.type = OCI_DTYPE_LOB;
    lob->pos = 0;
    lob->csfrm = csfrm;
    lob->lobtype = lobtype;
    lob->state = S_NO_OPEN_CLOSE;
    oci8_link_to_parent(&lob->base, &svcctx->base);
    lob->svcctx = svcctx;
    RB_OBJ_WRITTEN(self, Qundef, svc);
    if (!NIL_P(val)) {
        OCI8StringValue(val);
        chker2(OCILobCreateTemporary_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, 0, csfrm, lobtype, TRUE, OCI_DURATION_SESSION),
               &svcctx->base);
        oci8_lob_write(self, val);
        lob->pos = 0; /* reset the position */
    }
    return Qnil;
}
示例#2
0
/*
 *  Closes the lob.
 *
 *  @return [self]
 */
static VALUE oci8_lob_close(VALUE self)
{
    oci8_lob_t *lob = TO_LOB(self);
    lob_close(lob);
    oci8_base_free(&lob->base);
    return self;
}
示例#3
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);
    }
}
示例#4
0
/*
 * @overload initialize(conn, directory = nil, filename = nil)
 *
 *  Creates a BFILE object.
 *  This is correspond to {BFILENAME}[https://docs.oracle.com/database/121/SQLRF/functions020.htm].
 *
 *  @param [OCI8] conn
 *  @param [String] directory  a directory object created by
 *    {"CREATE DIRECTORY"}[http://docs.oracle.com/database/121/SQLRF/statements_5008.htm].
 *  @param [String] filename
 *  @return [OCI8::BFILE]
 */
static VALUE oci8_bfile_initialize(int argc, VALUE *argv, VALUE self)
{
    oci8_lob_t *lob = TO_LOB(self);
    VALUE svc;
    VALUE dir_alias;
    VALUE filename;
    oci8_svcctx_t *svcctx;
    int rv;

    rb_scan_args(argc, argv, "12", &svc, &dir_alias, &filename);
    svcctx = oci8_get_svcctx(svc);
    rv = OCIDescriptorAlloc(oci8_envhp, &lob->base.hp.ptr, OCI_DTYPE_LOB, 0, NULL);
    if (rv != OCI_SUCCESS) {
        oci8_env_raise(oci8_envhp, rv);
    }
    lob->base.type = OCI_DTYPE_LOB;
    lob->pos = 0;
    lob->csfrm = SQLCS_IMPLICIT;
    lob->lobtype = OCI_TEMP_BLOB;
    lob->state = S_BFILE_CLOSE;
    if (argc != 1) {
        OCI8SafeStringValue(dir_alias);
        OCI8SafeStringValue(filename);
        oci8_bfile_set_name(self, dir_alias, filename);
    }
    oci8_link_to_parent(&lob->base, &svcctx->base);
    lob->svcctx = svcctx;
    return Qnil;
}
示例#5
0
/*
 *  Returns true if the current offset is at end of lob.
 *
 *  @return [true or false]
 */
static VALUE oci8_lob_eof_p(VALUE self)
{
    oci8_lob_t *lob = TO_LOB(self);
    if (oci8_lob_get_length(lob) < lob->pos)
        return Qfalse;
    else
        return Qtrue;
}
示例#6
0
/*
 *  Returns +true+ when <i>self</i> is initialized.
 *
 *  @return [true or false]
 */
static VALUE oci8_lob_available_p(VALUE self)
{
    oci8_lob_t *lob = TO_LOB(self);
    boolean is_initialized;

    chker2(OCILobLocatorIsInit(oci8_envhp, oci8_errhp, lob->base.hp.lob, &is_initialized),
           &lob->base);
    return is_initialized ? Qtrue : Qfalse;
}
示例#7
0
文件: lob.c 项目: kubo/ruby-oci8
/*
 *  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;
}
示例#8
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);
}
示例#9
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;
}
示例#10
0
/*
 *  @deprecated I'm not sure that this is what the name indicates.
 *  @private
 */
static VALUE oci8_lob_set_sync(VALUE self, VALUE b)
{
    oci8_lob_t *lob = TO_LOB(self);
    if (RTEST(b)) {
        lob_close(lob);
        lob->state = S_NO_OPEN_CLOSE;
    } else {
        if (lob->state == S_NO_OPEN_CLOSE)
            lob->state = S_CLOSE;
    }
    return b;
}
示例#11
0
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);
}
示例#12
0
static VALUE oci8_make_lob(VALUE klass, oci8_svcctx_t *svcctx, OCILobLocator *s)
{
    oci8_lob_t *lob;
    boolean is_temp;
    VALUE lob_obj;

    lob_obj = rb_class_new_instance(1, &svcctx->base.self, klass);
    lob = TO_LOB(lob_obj);
    /* If 's' is a temporary lob, use OCILobLocatorAssign instead. */
    chker2(OCILobIsTemporary(oci8_envhp, oci8_errhp, s, &is_temp), &svcctx->base);
    if (is_temp)
        chker2(OCILobLocatorAssign_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, s, &lob->base.hp.lob),
               &svcctx->base);
    else
        chker2(OCILobAssign(oci8_envhp, oci8_errhp, s, &lob->base.hp.lob),
               &svcctx->base);
    return lob_obj;
}
示例#13
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;
}
示例#14
0
/*
 *  call-seq:
 *     seek(amount, whence=IO::SEEK_SET)
 *
 *  Seeks to the given offset in the stream. The new position, measured in characters,
 *  is obtained by adding offset <i>amount</i> to the position specified by <i>whence</i>.
 *  If <i>whence</i> is set to IO::SEEK_SET, IO::SEEK_CUR, or IO::SEEK_END,
 *  the offset is relative to the start of the file, the current position
 *  indicator, or end-of-file, respectively.
 *
 *  @param [Integer] amount
 *  @param [IO::SEEK_SET, IO::SEEK_CUR or IO::SEEK_END] whence
 *  @return [self]
 */
static VALUE oci8_lob_seek(int argc, VALUE *argv, VALUE self)
{
    oci8_lob_t *lob = TO_LOB(self);
    VALUE position, whence;

    rb_scan_args(argc, argv, "11", &position, &whence);
    if (argc == 2 && (whence != seek_set && whence != seek_cur && whence != seek_end)) {
        if (FIXNUM_P(whence)) {
            rb_raise(rb_eArgError, "expect IO::SEEK_SET, IO::SEEK_CUR or IO::SEEK_END but %d",
                     FIX2INT(whence));
        } else {
            rb_raise(rb_eArgError, "expect IO::SEEK_SET, IO::SEEK_CUR or IO::SEEK_END but %s",
                     rb_class2name(CLASS_OF(whence)));
        }
    }
    if (whence == seek_cur) {
        position = rb_funcall(ULL2NUM(lob->pos), id_plus, 1, position);
    } else if (whence == seek_end) {
        position = rb_funcall(ULL2NUM(oci8_lob_get_length(lob)), id_plus, 1, position);
    }
    lob->pos = NUM2ULL(position);
    return self;
}
示例#15
0
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;
        }
    }
}
示例#16
0
/*
 *  Sets the current offset at the beginning.
 *
 *  @return [true or false]
 */
static VALUE oci8_lob_rewind(VALUE self)
{
    oci8_lob_t *lob = TO_LOB(self);
    lob->pos = 0;
    return self;
}
示例#17
0
/*
 *  @deprecated I'm not sure that this is what the name indicates.
 *  @private
 */
static VALUE oci8_lob_flush(VALUE self)
{
    oci8_lob_t *lob = TO_LOB(self);
    lob_close(lob);
    return self;
}
示例#18
0
/*
 *  @deprecated I'm not sure that this is what the name indicates.
 *  @private
 */
static VALUE oci8_lob_get_sync(VALUE self)
{
    oci8_lob_t *lob = TO_LOB(self);
    return (lob->state == S_NO_OPEN_CLOSE) ? Qtrue : Qfalse;
}
示例#19
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;
    }
}
示例#20
0
/*
 *  Returns the size.
 *  For CLOB and NCLOB it is the number of characters,
 *  for BLOB and BFILE it is the number of bytes.
 *
 *  @return [Integer]
 */
static VALUE oci8_lob_get_size(VALUE self)
{
    return ULL2NUM(oci8_lob_get_length(TO_LOB(self)));
}
示例#21
0
/*
 *  Returns the current offset.
 *  For CLOB and NCLOB it is the number of characters,
 *  for BLOB and BFILE it is the number of bytes.
 *
 *  @return [Integer]
 */
static VALUE oci8_lob_get_pos(VALUE self)
{
    oci8_lob_t *lob = TO_LOB(self);
    return ULL2NUM(lob->pos);
}