ruby-oci8 2.2.6.1 → 2.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -11,6 +11,7 @@
11
11
  #endif
12
12
 
13
13
  static ID id_bind_type;
14
+ static ID id_charset_form;
14
15
  static VALUE sym_length;
15
16
  static VALUE sym_length_semantics;
16
17
  static VALUE sym_char;
@@ -25,6 +26,29 @@ typedef struct {
25
26
  ub1 csfrm;
26
27
  } oci8_bind_string_t;
27
28
 
29
+ static ub4 initial_chunk_size = 32 * 1024;
30
+ static ub4 max_chunk_size = 8 * 1024 * 1024;
31
+
32
+ typedef struct chunk {
33
+ struct chunk *next;
34
+ ub4 alloc_len;
35
+ ub4 used_len;
36
+ char buf[1];
37
+ } chunk_t;
38
+
39
+ typedef struct {
40
+ chunk_t *head;
41
+ chunk_t **tail;
42
+ chunk_t **inpos;
43
+ } chunk_buf_t;
44
+
45
+ typedef struct {
46
+ oci8_bind_t obind;
47
+ ub1 csfrm;
48
+ } oci8_bind_long_t;
49
+
50
+ #define IS_BIND_LONG(obind) (((oci8_bind_data_type_t*)obind->base.data_type)->dty == SQLT_CHR)
51
+
28
52
  const oci8_handle_data_type_t oci8_bind_data_type = {
29
53
  {
30
54
  "OCI8::BindType::Base",
@@ -306,6 +330,296 @@ static VALUE bind_boolean_alloc(VALUE klass)
306
330
  return oci8_allocate_typeddata(klass, &bind_boolean_data_type.base);
307
331
  }
308
332
 
333
+ /*
334
+ * bind_long
335
+ */
336
+ static chunk_t *next_chunk(chunk_buf_t *cb)
337
+ {
338
+ chunk_t *chunk;
339
+
340
+ if (*cb->tail != NULL) {
341
+ chunk = *cb->tail;
342
+ } else {
343
+ ub4 alloc_len;
344
+ if (cb->head == NULL) {
345
+ alloc_len = initial_chunk_size;
346
+ } else {
347
+ alloc_len = ((chunk_t*)((size_t)cb->tail - offsetof(chunk_t, next)))->alloc_len * 2;
348
+ if (alloc_len > max_chunk_size) {
349
+ alloc_len = max_chunk_size;
350
+ }
351
+ }
352
+ chunk = xmalloc(offsetof(chunk_t, buf) + alloc_len);
353
+ chunk->next = NULL;
354
+ chunk->alloc_len = alloc_len;
355
+ *cb->tail = chunk;
356
+ }
357
+ cb->tail = &chunk->next;
358
+ return chunk;
359
+ }
360
+
361
+ static sb4 define_callback(void *octxp, OCIDefine *defnp, ub4 iter, void **bufpp, ub4 **alenp, ub1 *piecep, void **indp, ub2 **rcodep)
362
+ {
363
+ oci8_bind_t *obind = (oci8_bind_t *)octxp;
364
+ chunk_buf_t *cb = ((chunk_buf_t*)obind->valuep) + iter;
365
+ chunk_t *chunk;
366
+
367
+ if (*piecep == OCI_FIRST_PIECE) {
368
+ cb->tail = &cb->head;
369
+ }
370
+ chunk = next_chunk(cb);
371
+ chunk->used_len = chunk->alloc_len;
372
+ *bufpp = chunk->buf;
373
+ *alenp = &chunk->used_len;
374
+ *indp = (void*)&obind->u.inds[iter];
375
+ *rcodep = NULL;
376
+ return OCI_CONTINUE;
377
+ }
378
+
379
+ static sb4 in_bind_callback(void *ictxp, OCIBind *bindp, ub4 iter, ub4 index, void **bufpp, ub4 *alenp, ub1 *piecep, void **indp)
380
+ {
381
+ oci8_bind_t *obind = (oci8_bind_t *)ictxp;
382
+ chunk_buf_t *cb = ((chunk_buf_t*)obind->valuep) + iter;
383
+
384
+ if (cb->tail == &cb->head) {
385
+ /* empty string */
386
+ *bufpp = "";
387
+ *alenp = 0;
388
+ *piecep = OCI_ONE_PIECE;
389
+ } else {
390
+ chunk_t *chunk = *cb->inpos;
391
+ *bufpp = chunk->buf;
392
+ *alenp = chunk->used_len;
393
+ if (cb->tail == &cb->head->next) {
394
+ *piecep = OCI_ONE_PIECE;
395
+ } else if (cb->inpos == &cb->head) {
396
+ *piecep = OCI_FIRST_PIECE;
397
+ cb->inpos = &chunk->next;
398
+ } else if (&chunk->next != cb->tail) {
399
+ *piecep = OCI_NEXT_PIECE;
400
+ cb->inpos = &chunk->next;
401
+ } else {
402
+ *piecep = OCI_LAST_PIECE;
403
+ cb->inpos = &cb->head;
404
+ }
405
+ }
406
+ *indp = (void*)&obind->u.inds[iter];
407
+ return OCI_CONTINUE;
408
+ }
409
+
410
+ static sb4 out_bind_callback(void *octxp, OCIBind *bindp, ub4 iter, ub4 index, void **bufpp, ub4 **alenp, ub1 *piecep, void **indp, ub2 **rcodep)
411
+ {
412
+ oci8_bind_t *obind = (oci8_bind_t *)octxp;
413
+ chunk_buf_t *cb = ((chunk_buf_t*)obind->valuep) + iter;
414
+ chunk_t *chunk;
415
+
416
+ if (*piecep == OCI_ONE_PIECE) {
417
+ *piecep = OCI_FIRST_PIECE;
418
+ cb->tail = &cb->head;
419
+ }
420
+ chunk = next_chunk(cb);
421
+ chunk->used_len = chunk->alloc_len;
422
+ *bufpp = chunk->buf;
423
+ *alenp = &chunk->used_len;
424
+ *indp = (void*)&obind->u.inds[iter];
425
+ *rcodep = NULL;
426
+ return OCI_CONTINUE;
427
+ }
428
+
429
+ static void bind_long_free(oci8_base_t *base)
430
+ {
431
+ oci8_bind_t *obind = (oci8_bind_t *)base;
432
+ chunk_buf_t *cb = (chunk_buf_t *)obind->valuep;
433
+
434
+ if (cb != NULL) {
435
+ ub4 idx = 0;
436
+ do {
437
+ chunk_t *chunk, *chunk_next;
438
+ for (chunk = cb[idx].head; chunk != NULL; chunk = chunk_next) {
439
+ chunk_next = chunk->next;
440
+ xfree(chunk);
441
+ }
442
+ } while (++idx < obind->maxar_sz);
443
+ }
444
+ oci8_bind_free(base);
445
+ }
446
+
447
+ static VALUE bind_long_get(oci8_bind_t *obind, void *data, void *null_struct)
448
+ {
449
+ chunk_buf_t *cb = (chunk_buf_t *)data;
450
+ chunk_t *chunk;
451
+ long len = 0;
452
+ VALUE str;
453
+ char *buf;
454
+
455
+ for (chunk = cb->head; chunk != *cb->tail; chunk = chunk->next) {
456
+ len += chunk->used_len;
457
+ }
458
+ str = rb_str_buf_new(len);
459
+ buf = RSTRING_PTR(str);
460
+ for (chunk = cb->head; chunk != *cb->tail; chunk = chunk->next) {
461
+ memcpy(buf, chunk->buf, chunk->used_len);
462
+ buf += chunk->used_len;
463
+ }
464
+ rb_str_set_len(str, len);
465
+ if (IS_BIND_LONG(obind)) {
466
+ rb_encoding *enc = rb_default_internal_encoding();
467
+
468
+ rb_enc_associate(str, oci8_encoding);
469
+ if (enc != NULL) {
470
+ str = rb_str_conv_enc(str, oci8_encoding, enc);
471
+ }
472
+ }
473
+ OBJ_TAINT(str);
474
+ return str;
475
+ }
476
+
477
+ static void bind_long_set(oci8_bind_t *obind, void *data, void **null_structp, VALUE val)
478
+ {
479
+ chunk_buf_t *cb = (chunk_buf_t *)data;
480
+ long len;
481
+ const char *buf;
482
+
483
+ if (IS_BIND_LONG(obind)) {
484
+ OCI8StringValue(val);
485
+ } else {
486
+ StringValue(val);
487
+ }
488
+ len = RSTRING_LEN(val);
489
+ buf = RSTRING_PTR(val);
490
+ cb->tail = &cb->head;
491
+ while (1) {
492
+ chunk_t *chunk = next_chunk(cb);
493
+ if (len <= chunk->alloc_len) {
494
+ memcpy(chunk->buf, buf, len);
495
+ chunk->used_len = len;
496
+ break;
497
+ }
498
+ memcpy(chunk->buf, buf, chunk->alloc_len);
499
+ chunk->used_len = chunk->alloc_len;
500
+ len -= chunk->alloc_len;
501
+ buf += chunk->alloc_len;
502
+ }
503
+ }
504
+
505
+ static void bind_long_init(oci8_bind_t *obind, VALUE svc, VALUE val, VALUE param)
506
+ {
507
+ if (IS_BIND_LONG(obind)) {
508
+ oci8_bind_long_t *obl = (oci8_bind_long_t *)obind;
509
+ VALUE nchar;
510
+
511
+ if (rb_respond_to(param, id_charset_form)) {
512
+ VALUE csfrm = rb_funcall(param, id_charset_form, 0);
513
+ nchar = (csfrm == sym_nchar) ? Qtrue : Qfalse;
514
+ } else {
515
+ Check_Type(param, T_HASH);
516
+ nchar = rb_hash_aref(param, sym_nchar);
517
+ }
518
+
519
+ if (RTEST(nchar)) {
520
+ obl->csfrm = SQLCS_NCHAR; /* bind as NCHAR/NVARCHAR2 */
521
+ } else {
522
+ obl->csfrm = SQLCS_IMPLICIT; /* bind as CHAR/VARCHAR2 */
523
+ }
524
+ }
525
+ obind->value_sz = SB4MAXVAL;
526
+ obind->alloc_sz = sizeof(chunk_buf_t);
527
+ }
528
+
529
+ static void bind_long_init_elem(oci8_bind_t *obind, VALUE svc)
530
+ {
531
+ chunk_buf_t *cb = (chunk_buf_t *)obind->valuep;
532
+ ub4 idx = 0;
533
+
534
+ do {
535
+ cb[idx].tail = &cb[idx].head;
536
+ cb[idx].inpos = &cb[idx].head;
537
+ } while (++idx < obind->maxar_sz);
538
+ }
539
+
540
+ static void bind_long_post_bind_hook(oci8_bind_t *obind)
541
+ {
542
+ oci8_bind_long_t *ds = (oci8_bind_long_t *)obind;
543
+
544
+ if (IS_BIND_LONG(obind)) {
545
+ chker2(OCIAttrSet(obind->base.hp.ptr, obind->base.type, (void*)&ds->csfrm, 0, OCI_ATTR_CHARSET_FORM, oci8_errhp),
546
+ &obind->base);
547
+ }
548
+ switch (obind->base.type) {
549
+ case OCI_HTYPE_DEFINE:
550
+ chker2(OCIDefineDynamic(obind->base.hp.dfn, oci8_errhp, obind, define_callback),
551
+ &obind->base);
552
+ break;
553
+ case OCI_HTYPE_BIND:
554
+ chker2(OCIBindDynamic(obind->base.hp.bnd, oci8_errhp, obind, in_bind_callback,
555
+ obind, out_bind_callback),
556
+ &obind->base);
557
+ break;
558
+ }
559
+ }
560
+
561
+ static const oci8_bind_data_type_t bind_long_data_type = {
562
+ {
563
+ {
564
+ "OCI8::BindType::Long",
565
+ {
566
+ NULL,
567
+ oci8_handle_cleanup,
568
+ oci8_handle_size,
569
+ },
570
+ &oci8_bind_data_type.rb_data_type, NULL,
571
+ #ifdef RUBY_TYPED_WB_PROTECTED
572
+ RUBY_TYPED_WB_PROTECTED,
573
+ #endif
574
+ },
575
+ bind_long_free,
576
+ sizeof(oci8_bind_long_t)
577
+ },
578
+ bind_long_get,
579
+ bind_long_set,
580
+ bind_long_init,
581
+ bind_long_init_elem,
582
+ NULL,
583
+ SQLT_CHR,
584
+ bind_long_post_bind_hook,
585
+ };
586
+
587
+ static VALUE bind_long_alloc(VALUE klass)
588
+ {
589
+ return oci8_allocate_typeddata(klass, &bind_long_data_type.base);
590
+ }
591
+
592
+ static const oci8_bind_data_type_t bind_long_raw_data_type = {
593
+ {
594
+ {
595
+ "OCI8::BindType::LongRaw",
596
+ {
597
+ NULL,
598
+ oci8_handle_cleanup,
599
+ oci8_handle_size,
600
+ },
601
+ &oci8_bind_data_type.rb_data_type, NULL,
602
+ #ifdef RUBY_TYPED_WB_PROTECTED
603
+ RUBY_TYPED_WB_PROTECTED,
604
+ #endif
605
+ },
606
+ bind_long_free,
607
+ sizeof(oci8_bind_long_t)
608
+ },
609
+ bind_long_get,
610
+ bind_long_set,
611
+ bind_long_init,
612
+ bind_long_init_elem,
613
+ NULL,
614
+ SQLT_BIN,
615
+ bind_long_post_bind_hook,
616
+ };
617
+
618
+ static VALUE bind_long_raw_alloc(VALUE klass)
619
+ {
620
+ return oci8_allocate_typeddata(klass, &bind_long_raw_data_type.base);
621
+ }
622
+
309
623
  static VALUE oci8_bind_get(VALUE self)
310
624
  {
311
625
  oci8_bind_t *obind = TO_BIND(self);
@@ -320,11 +634,20 @@ static VALUE oci8_bind_get(VALUE self)
320
634
  return data_type->get(obind, (void*)((size_t)obind->valuep + obind->alloc_sz * idx), null_structp);
321
635
  }
322
636
 
323
- static VALUE oci8_bind_get_data(VALUE self)
637
+ static VALUE oci8_bind_get_data(int argc, VALUE *argv, VALUE self)
324
638
  {
325
639
  oci8_bind_t *obind = TO_BIND(self);
640
+ VALUE index;
326
641
 
327
- if (obind->maxar_sz == 0) {
642
+ rb_scan_args(argc, argv, "01", &index);
643
+ if (!NIL_P(index)) {
644
+ ub4 idx = NUM2UINT(index);
645
+ if (idx >= obind->maxar_sz) {
646
+ rb_raise(rb_eRuntimeError, "data index is too big. (%u for %u)", idx, obind->maxar_sz);
647
+ }
648
+ obind->curar_idx = idx;
649
+ return rb_funcall(self, oci8_id_get, 0);
650
+ } else if (obind->maxar_sz == 0) {
328
651
  obind->curar_idx = 0;
329
652
  return rb_funcall(self, oci8_id_get, 0);
330
653
  } else {
@@ -391,6 +714,36 @@ static VALUE oci8_bind_set_data(VALUE self, VALUE val)
391
714
  return self;
392
715
  }
393
716
 
717
+ static VALUE get_initial_chunk_size(VALUE klass)
718
+ {
719
+ return UINT2NUM(initial_chunk_size);
720
+ }
721
+
722
+ static VALUE set_initial_chunk_size(VALUE klass, VALUE arg)
723
+ {
724
+ ub4 size = NUM2UINT(arg);
725
+ if (size == 0) {
726
+ rb_raise(rb_eArgError, "Could not set zero");
727
+ }
728
+ initial_chunk_size = size;
729
+ return arg;
730
+ }
731
+
732
+ static VALUE get_max_chunk_size(VALUE klass)
733
+ {
734
+ return UINT2NUM(max_chunk_size);
735
+ }
736
+
737
+ static VALUE set_max_chunk_size(VALUE klass, VALUE arg)
738
+ {
739
+ ub4 size = NUM2UINT(arg);
740
+ if (size == 0) {
741
+ rb_raise(rb_eArgError, "Could not set zero");
742
+ }
743
+ max_chunk_size = size;
744
+ return arg;
745
+ }
746
+
394
747
  static VALUE oci8_bind_initialize(VALUE self, VALUE svc, VALUE val, VALUE length, VALUE max_array_size)
395
748
  {
396
749
  oci8_bind_t *obind = TO_BIND(self);
@@ -456,6 +809,7 @@ void Init_oci8_bind(VALUE klass)
456
809
  {
457
810
  cOCI8BindTypeBase = klass;
458
811
  id_bind_type = rb_intern("bind_type");
812
+ id_charset_form = rb_intern("charset_form");
459
813
  sym_length = ID2SYM(rb_intern("length"));
460
814
  sym_length_semantics = ID2SYM(rb_intern("length_semantics"));
461
815
  sym_char = ID2SYM(rb_intern("char"));
@@ -464,9 +818,14 @@ void Init_oci8_bind(VALUE klass)
464
818
  rb_define_method(cOCI8BindTypeBase, "initialize", oci8_bind_initialize, 4);
465
819
  rb_define_method(cOCI8BindTypeBase, "get", oci8_bind_get, 0);
466
820
  rb_define_method(cOCI8BindTypeBase, "set", oci8_bind_set, 1);
467
- rb_define_private_method(cOCI8BindTypeBase, "get_data", oci8_bind_get_data, 0);
821
+ rb_define_private_method(cOCI8BindTypeBase, "get_data", oci8_bind_get_data, -1);
468
822
  rb_define_private_method(cOCI8BindTypeBase, "set_data", oci8_bind_set_data, 1);
469
823
 
824
+ rb_define_singleton_method(klass, "initial_chunk_size", get_initial_chunk_size, 0);
825
+ rb_define_singleton_method(klass, "initial_chunk_size=", set_initial_chunk_size, 1);
826
+ rb_define_singleton_method(klass, "max_chunk_size", get_max_chunk_size, 0);
827
+ rb_define_singleton_method(klass, "max_chunk_size=", set_max_chunk_size, 1);
828
+
470
829
  /* register primitive data types. */
471
830
  oci8_define_bind_class("String", &bind_string_data_type, bind_string_alloc);
472
831
  oci8_define_bind_class("RAW", &bind_raw_data_type, bind_raw_alloc);
@@ -474,4 +833,6 @@ void Init_oci8_bind(VALUE klass)
474
833
  if (oracle_client_version >= ORAVER_12_1) {
475
834
  oci8_define_bind_class("Boolean", &bind_boolean_data_type, bind_boolean_alloc);
476
835
  }
836
+ klass = oci8_define_bind_class("Long", &bind_long_data_type, bind_long_alloc);
837
+ klass = oci8_define_bind_class("LongRaw", &bind_long_data_type, bind_long_raw_alloc);
477
838
  }
@@ -639,10 +639,9 @@ static VALUE oci8_lob_read(int argc, VALUE *argv, VALUE self)
639
639
  {
640
640
  oci8_lob_t *lob = TO_LOB(self);
641
641
  oci8_svcctx_t *svcctx = check_svcctx(lob);
642
- ub8 lob_length;
643
- ub8 read_len;
644
642
  ub8 pos = lob->pos;
645
- long strbufsiz;
643
+ long strbufsiz = 512;
644
+ ub8 sz;
646
645
  ub8 byte_amt;
647
646
  ub8 char_amt;
648
647
  sword rv;
@@ -652,36 +651,21 @@ static VALUE oci8_lob_read(int argc, VALUE *argv, VALUE self)
652
651
  ub1 piece = OCI_FIRST_PIECE;
653
652
 
654
653
  rb_scan_args(argc, argv, "01", &size);
655
- lob_length = oci8_lob_get_length(lob);
656
- if (lob_length == 0 && NIL_P(size)) {
657
- return rb_usascii_str_new("", 0);
658
- }
659
- if (lob_length <= pos) /* EOF */
660
- return Qnil;
661
654
  if (NIL_P(size)) {
662
- read_len = lob_length - pos;
655
+ sz = UB4MAXVAL;
663
656
  } else {
664
- ub8 sz = NUM2ULL(size);
665
- read_len = MIN(sz, lob_length - pos);
657
+ sz = NUM2ULL(size);
658
+ }
659
+ if (lob->state == S_BFILE_CLOSE) {
660
+ open_bfile(svcctx, lob, errhp);
666
661
  }
662
+ read_more_data:
667
663
  if (lob->lobtype == OCI_TEMP_CLOB) {
668
664
  byte_amt = 0;
669
- char_amt = read_len;
670
- if (oci8_nls_ratio == 1) {
671
- strbufsiz = MIN(read_len, ULONG_MAX);
672
- } else {
673
- strbufsiz = MIN(read_len + read_len / 8, ULONG_MAX);
674
- }
675
- if (strbufsiz <= 10) {
676
- strbufsiz = 10;
677
- }
665
+ char_amt = sz;
678
666
  } else {
679
- byte_amt = read_len;
667
+ byte_amt = sz;
680
668
  char_amt = 0;
681
- strbufsiz = MIN(read_len, ULONG_MAX);
682
- }
683
- if (lob->state == S_BFILE_CLOSE) {
684
- open_bfile(svcctx, lob, errhp);
685
669
  }
686
670
  do {
687
671
  VALUE strbuf = rb_str_buf_new(strbufsiz);
@@ -711,15 +695,24 @@ static VALUE oci8_lob_read(int argc, VALUE *argv, VALUE self)
711
695
  }
712
696
  rb_str_set_len(strbuf, byte_amt);
713
697
  rb_ary_push(v, strbuf);
698
+ if (strbufsiz < 128 * 1024 * 1024) {
699
+ strbufsiz *= 2;
700
+ }
714
701
  } while (rv == OCI_NEED_DATA);
715
702
 
716
- if (pos >= lob_length) {
717
- bfile_close(lob);
703
+ if (NIL_P(size) && pos - lob->pos == sz) {
704
+ lob->pos = pos;
705
+ piece = OCI_FIRST_PIECE;
706
+ goto read_more_data;
718
707
  }
719
708
  lob->pos = pos;
720
709
  switch (RARRAY_LEN(v)) {
721
710
  case 0:
722
- return Qnil;
711
+ if (NIL_P(size) && pos == 0) {
712
+ return rb_usascii_str_new("", 0);
713
+ } else {
714
+ return Qnil;
715
+ }
723
716
  case 1:
724
717
  v = RARRAY_AREF(v, 0);
725
718
  break;