ruby-oci8 2.2.6.1 → 2.2.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -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;