ruby-oci8 2.2.0.2 → 2.2.12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +1 -6
  3. data/ChangeLog +600 -0
  4. data/NEWS +426 -35
  5. data/README.md +27 -9
  6. data/dist-files +13 -2
  7. data/docs/bind-array-to-in_cond.md +38 -0
  8. data/docs/conflicts-local-connections-and-processes.md +98 -0
  9. data/docs/hanging-after-inactivity.md +63 -0
  10. data/docs/install-binary-package.md +15 -11
  11. data/docs/install-full-client.md +18 -21
  12. data/docs/install-instant-client.md +45 -27
  13. data/docs/install-on-osx.md +31 -117
  14. data/docs/ldap-auth-and-function-interposition.md +123 -0
  15. data/docs/number-type-mapping.md +79 -0
  16. data/docs/platform-specific-issues.md +17 -50
  17. data/docs/report-installation-issue.md +11 -8
  18. data/docs/timeout-parameters.md +94 -0
  19. data/ext/oci8/apiwrap.c.tmpl +2 -5
  20. data/ext/oci8/apiwrap.rb +6 -1
  21. data/ext/oci8/apiwrap.yml +39 -143
  22. data/ext/oci8/attr.c +4 -2
  23. data/ext/oci8/bind.c +421 -9
  24. data/ext/oci8/connection_pool.c +3 -3
  25. data/ext/oci8/encoding.c +5 -5
  26. data/ext/oci8/env.c +8 -2
  27. data/ext/oci8/error.c +24 -16
  28. data/ext/oci8/extconf.rb +35 -63
  29. data/ext/oci8/hook_funcs.c +274 -61
  30. data/ext/oci8/lob.c +31 -75
  31. data/ext/oci8/metadata.c +8 -6
  32. data/ext/oci8/object.c +119 -29
  33. data/ext/oci8/oci8.c +46 -133
  34. data/ext/oci8/oci8.h +40 -123
  35. data/ext/oci8/oci8lib.c +178 -46
  36. data/ext/oci8/ocihandle.c +37 -37
  37. data/ext/oci8/ocinumber.c +24 -35
  38. data/ext/oci8/oraconf.rb +168 -337
  39. data/ext/oci8/oradate.c +19 -19
  40. data/ext/oci8/plthook.h +10 -0
  41. data/ext/oci8/plthook_elf.c +433 -268
  42. data/ext/oci8/plthook_osx.c +40 -9
  43. data/ext/oci8/plthook_win32.c +16 -1
  44. data/ext/oci8/stmt.c +52 -17
  45. data/ext/oci8/win32.c +4 -22
  46. data/lib/oci8/bindtype.rb +10 -17
  47. data/lib/oci8/check_load_error.rb +57 -10
  48. data/lib/oci8/compat.rb +5 -1
  49. data/lib/oci8/connection_pool.rb +74 -3
  50. data/lib/oci8/cursor.rb +70 -31
  51. data/lib/oci8/metadata.rb +9 -1
  52. data/lib/oci8/object.rb +14 -1
  53. data/lib/oci8/oci8.rb +184 -58
  54. data/lib/oci8/ocihandle.rb +0 -16
  55. data/lib/oci8/oracle_version.rb +11 -1
  56. data/lib/oci8/properties.rb +55 -0
  57. data/lib/oci8/version.rb +1 -1
  58. data/lib/oci8.rb +48 -4
  59. data/lib/ruby-oci8.rb +1 -0
  60. data/pre-distclean.rb +1 -3
  61. data/ruby-oci8.gemspec +4 -9
  62. data/setup.rb +11 -2
  63. data/test/README.md +37 -0
  64. data/test/config.rb +8 -1
  65. data/test/setup_test_object.sql +42 -14
  66. data/test/setup_test_package.sql +59 -0
  67. data/test/test_all.rb +4 -0
  68. data/test/test_bind_array.rb +70 -0
  69. data/test/test_bind_boolean.rb +99 -0
  70. data/test/test_bind_integer.rb +47 -0
  71. data/test/test_break.rb +11 -9
  72. data/test/test_clob.rb +5 -17
  73. data/test/test_connstr.rb +142 -0
  74. data/test/test_datetime.rb +8 -3
  75. data/test/test_metadata.rb +2 -1
  76. data/test/test_object.rb +99 -18
  77. data/test/test_oci8.rb +170 -46
  78. data/test/test_oranumber.rb +12 -6
  79. data/test/test_package_type.rb +17 -3
  80. data/test/test_properties.rb +17 -0
  81. metadata +45 -55
  82. data/docs/osx-install-dev-tools.png +0 -0
  83. data/test/README +0 -42
data/ext/oci8/lob.c CHANGED
@@ -26,8 +26,6 @@ static VALUE seek_end;
26
26
 
27
27
  enum state {
28
28
  S_NO_OPEN_CLOSE,
29
- S_OPEN,
30
- S_CLOSE,
31
29
  S_BFILE_CLOSE,
32
30
  S_BFILE_OPEN,
33
31
  };
@@ -266,28 +264,6 @@ static ub8 oci8_lob_get_length(oci8_lob_t *lob)
266
264
  return len;
267
265
  }
268
266
 
269
- static void lob_open(oci8_lob_t *lob)
270
- {
271
- if (lob->state == S_CLOSE) {
272
- oci8_svcctx_t *svcctx = check_svcctx(lob);
273
-
274
- chker2(OCILobOpen_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, OCI_DEFAULT),
275
- &svcctx->base);
276
- lob->state = S_OPEN;
277
- }
278
- }
279
-
280
- static void lob_close(oci8_lob_t *lob)
281
- {
282
- if (lob->state == S_OPEN) {
283
- oci8_svcctx_t *svcctx = check_svcctx(lob);
284
-
285
- chker2(OCILobClose_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob),
286
- &svcctx->base);
287
- lob->state = S_CLOSE;
288
- }
289
- }
290
-
291
267
  static void bfile_close(oci8_lob_t *lob)
292
268
  {
293
269
  if (lob->state == S_BFILE_OPEN) {
@@ -368,7 +344,6 @@ static void bfile_close(oci8_lob_t *lob)
368
344
  static VALUE oci8_lob_close(VALUE self)
369
345
  {
370
346
  oci8_lob_t *lob = TO_LOB(self);
371
- lob_close(lob);
372
347
  oci8_base_free(&lob->base);
373
348
  return self;
374
349
  }
@@ -591,7 +566,6 @@ static VALUE oci8_lob_truncate(VALUE self, VALUE len)
591
566
  oci8_lob_t *lob = TO_LOB(self);
592
567
  oci8_svcctx_t *svcctx = check_svcctx(lob);
593
568
 
594
- lob_open(lob);
595
569
  chker2(OCILobTrim2_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, NUM2ULL(len)),
596
570
  &svcctx->base);
597
571
  return self;
@@ -665,10 +639,9 @@ static VALUE oci8_lob_read(int argc, VALUE *argv, VALUE self)
665
639
  {
666
640
  oci8_lob_t *lob = TO_LOB(self);
667
641
  oci8_svcctx_t *svcctx = check_svcctx(lob);
668
- ub8 lob_length;
669
- ub8 read_len;
670
642
  ub8 pos = lob->pos;
671
- long strbufsiz;
643
+ long strbufsiz = 512;
644
+ ub8 sz;
672
645
  ub8 byte_amt;
673
646
  ub8 char_amt;
674
647
  sword rv;
@@ -678,36 +651,21 @@ static VALUE oci8_lob_read(int argc, VALUE *argv, VALUE self)
678
651
  ub1 piece = OCI_FIRST_PIECE;
679
652
 
680
653
  rb_scan_args(argc, argv, "01", &size);
681
- lob_length = oci8_lob_get_length(lob);
682
- if (lob_length == 0 && NIL_P(size)) {
683
- return rb_usascii_str_new("", 0);
684
- }
685
- if (lob_length <= pos) /* EOF */
686
- return Qnil;
687
654
  if (NIL_P(size)) {
688
- read_len = lob_length - pos;
655
+ sz = UB4MAXVAL;
689
656
  } else {
690
- ub8 sz = NUM2ULL(size);
691
- 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);
692
661
  }
662
+ read_more_data:
693
663
  if (lob->lobtype == OCI_TEMP_CLOB) {
694
664
  byte_amt = 0;
695
- char_amt = read_len;
696
- if (oci8_nls_ratio == 1) {
697
- strbufsiz = MIN(read_len, ULONG_MAX);
698
- } else {
699
- strbufsiz = MIN(read_len + read_len / 8, ULONG_MAX);
700
- }
701
- if (strbufsiz <= 10) {
702
- strbufsiz = 10;
703
- }
665
+ char_amt = sz;
704
666
  } else {
705
- byte_amt = read_len;
667
+ byte_amt = sz;
706
668
  char_amt = 0;
707
- strbufsiz = MIN(read_len, ULONG_MAX);
708
- }
709
- if (lob->state == S_BFILE_CLOSE) {
710
- open_bfile(svcctx, lob, errhp);
711
669
  }
712
670
  do {
713
671
  VALUE strbuf = rb_str_buf_new(strbufsiz);
@@ -737,23 +695,30 @@ static VALUE oci8_lob_read(int argc, VALUE *argv, VALUE self)
737
695
  }
738
696
  rb_str_set_len(strbuf, byte_amt);
739
697
  rb_ary_push(v, strbuf);
698
+ if (strbufsiz < 128 * 1024 * 1024) {
699
+ strbufsiz *= 2;
700
+ }
740
701
  } while (rv == OCI_NEED_DATA);
741
702
 
742
- if (pos >= lob_length) {
743
- lob_close(lob);
744
- 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;
745
707
  }
746
708
  lob->pos = pos;
747
709
  switch (RARRAY_LEN(v)) {
748
710
  case 0:
749
- return Qnil;
711
+ if (NIL_P(size) && pos == 0) {
712
+ return rb_usascii_str_new("", 0);
713
+ } else {
714
+ return Qnil;
715
+ }
750
716
  case 1:
751
717
  v = RARRAY_AREF(v, 0);
752
718
  break;
753
719
  default:
754
720
  v = rb_ary_join(v, Qnil);
755
721
  }
756
- OBJ_TAINT(v);
757
722
  if (lob->lobtype == OCI_TEMP_CLOB) {
758
723
  /* set encoding */
759
724
  rb_enc_associate(v, oci8_encoding);
@@ -781,7 +746,6 @@ static VALUE oci8_lob_write(VALUE self, VALUE data)
781
746
  ub8 byte_amt;
782
747
  ub8 char_amt;
783
748
 
784
- lob_open(lob);
785
749
  if (TYPE(data) != T_STRING) {
786
750
  str = rb_obj_as_string(data);
787
751
  } else {
@@ -801,48 +765,40 @@ static VALUE oci8_lob_write(VALUE self, VALUE data)
801
765
  RB_GC_GUARD(str);
802
766
  if (lob->lobtype == OCI_TEMP_CLOB) {
803
767
  lob->pos += char_amt;
804
- return UINT2NUM(char_amt);
768
+ return ULL2NUM(char_amt);
805
769
  } else {
806
770
  lob->pos += byte_amt;
807
- return UINT2NUM(byte_amt);
771
+ return ULL2NUM(byte_amt);
808
772
  }
809
773
  }
810
774
 
811
775
  /*
812
- * @deprecated I'm not sure that this is what the name indicates.
776
+ * @deprecated LOB#sync had not worked by mistake. Do nothing now.
813
777
  * @private
814
778
  */
815
779
  static VALUE oci8_lob_get_sync(VALUE self)
816
780
  {
817
- oci8_lob_t *lob = TO_LOB(self);
818
- return (lob->state == S_NO_OPEN_CLOSE) ? Qtrue : Qfalse;
781
+ rb_warning("LOB#sync had not worked by mistake. Do nothing now.");
782
+ return Qfalse;
819
783
  }
820
784
 
821
785
  /*
822
- * @deprecated I'm not sure that this is what the name indicates.
786
+ * @deprecated LOB#sync had not worked by mistake. Do nothing now.
823
787
  * @private
824
788
  */
825
789
  static VALUE oci8_lob_set_sync(VALUE self, VALUE b)
826
790
  {
827
- oci8_lob_t *lob = TO_LOB(self);
828
- if (RTEST(b)) {
829
- lob_close(lob);
830
- lob->state = S_NO_OPEN_CLOSE;
831
- } else {
832
- if (lob->state == S_NO_OPEN_CLOSE)
833
- lob->state = S_CLOSE;
834
- }
791
+ rb_warning("LOB#sync had not worked by mistake. Do nothing now.");
835
792
  return b;
836
793
  }
837
794
 
838
795
  /*
839
- * @deprecated I'm not sure that this is what the name indicates.
796
+ * @deprecated LOB#flush had not worked by mistake. Do nothing now.
840
797
  * @private
841
798
  */
842
799
  static VALUE oci8_lob_flush(VALUE self)
843
800
  {
844
- oci8_lob_t *lob = TO_LOB(self);
845
- lob_close(lob);
801
+ rb_warning("LOB#flush had not worked by mistake. Do nothing now.");
846
802
  return self;
847
803
  }
848
804
 
data/ext/oci8/metadata.c CHANGED
@@ -2,7 +2,7 @@
2
2
  /*
3
3
  * metadata.c
4
4
  *
5
- * Copyright (C) 2006-2015 Kubo Takehiro <kubo@jiubao.org>
5
+ * Copyright (C) 2006-2016 Kubo Takehiro <kubo@jiubao.org>
6
6
  *
7
7
  * implement private methods of classes in OCI8::Metadata module.
8
8
  *
@@ -145,7 +145,7 @@ static VALUE metadata_is_implicit_p(VALUE self)
145
145
  return md->is_implicit ? Qtrue : Qfalse;
146
146
  }
147
147
 
148
- static VALUE oci8_do_describe(VALUE self, void *objptr, ub4 objlen, ub1 objtype, VALUE klass, VALUE check_public)
148
+ VALUE oci8_do_describe(VALUE self, void *objptr, ub4 objlen, ub1 objtype, VALUE klass, VALUE check_public)
149
149
  {
150
150
  oci8_svcctx_t *svcctx = oci8_get_svcctx(self);
151
151
  OCIParam *parmhp;
@@ -195,7 +195,7 @@ static VALUE oci8_do_describe(VALUE self, void *objptr, ub4 objlen, ub1 objtype,
195
195
  static VALUE oci8_describe(VALUE self, VALUE name, VALUE klass, VALUE check_public)
196
196
  {
197
197
  char *str;
198
- size_t idx, len;
198
+ int idx, len;
199
199
  VALUE metadata;
200
200
  VALUE obj_link = Qnil;
201
201
 
@@ -204,7 +204,7 @@ static VALUE oci8_describe(VALUE self, VALUE name, VALUE klass, VALUE check_publ
204
204
  rb_raise(rb_eArgError, "empty string is set.");
205
205
  }
206
206
  str = RSTRING_PTR(name);
207
- len = RSTRING_LEN(name);
207
+ len = RSTRING_LENINT(name);
208
208
  for (idx = 0; idx < len; idx++) {
209
209
  if (str[idx] == '@') {
210
210
  obj_link = rb_enc_str_new(str + idx + 1, len - idx - 1, oci8_encoding);
@@ -259,10 +259,10 @@ void Init_oci8_metadata(VALUE cOCI8)
259
259
  {
260
260
  mOCI8Metadata = rb_define_module_under(cOCI8, "Metadata");
261
261
  cOCI8MetadataBase = oci8_define_class_under(mOCI8Metadata, "Base", &oci8_metadata_base_data_type, oci8_metadata_alloc);
262
- ptype_to_class = rb_hash_new();
263
- class_to_ptype = rb_hash_new();
264
262
  rb_global_variable(&ptype_to_class);
265
263
  rb_global_variable(&class_to_ptype);
264
+ ptype_to_class = rb_hash_new();
265
+ class_to_ptype = rb_hash_new();
266
266
  id_at_obj_link = rb_intern("@obj_link");
267
267
 
268
268
  rb_define_singleton_method(cOCI8MetadataBase, "register_ptype", metadata_s_register_ptype, 1);
@@ -274,4 +274,6 @@ void Init_oci8_metadata(VALUE cOCI8)
274
274
  rb_define_private_method(cOCI8, "__describe", oci8_describe, 3);
275
275
  rb_define_private_method(cOCI8MetadataBase, "__type_metadata", metadata_get_type_metadata, 1);
276
276
  rb_define_method(cOCI8MetadataBase, "tdo_id", metadata_get_tdo_id, 0);
277
+
278
+ rb_define_class_under(mOCI8Metadata, "Type", cOCI8MetadataBase);
277
279
  }
data/ext/oci8/object.c CHANGED
@@ -1,6 +1,6 @@
1
1
  /* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
2
2
  /*
3
- * Copyright (C) 2002-2014 Kubo Takehiro <kubo@jiubao.org>
3
+ * Copyright (C) 2002-2016 Kubo Takehiro <kubo@jiubao.org>
4
4
  */
5
5
 
6
6
  /*
@@ -20,8 +20,11 @@ static VALUE cOCI8TDO;
20
20
  static VALUE cOCI8NamedType;
21
21
  static VALUE cOCI8NamedCollection;
22
22
  static VALUE cOCI8BindNamedType;
23
+ static VALUE cOCI8MetadataType;
23
24
  static ID id_to_value;
24
25
  static ID id_set_attributes;
26
+ static ID id_get_tdo_by_metadata;
27
+ static ID id_at_is_final_type;
25
28
 
26
29
  #define TO_TDO(obj) ((oci8_base_t *)oci8_check_typeddata((obj), &oci8_tdo_data_type, 1))
27
30
  #define CHECK_TDO(obj) ((void)oci8_check_typeddata((obj), &oci8_tdo_data_type, 1))
@@ -41,6 +44,8 @@ enum {
41
44
  ATTR_FLOAT,
42
45
  ATTR_INTEGER,
43
46
  ATTR_OCIDATE,
47
+ ATTR_TIMESTAMP,
48
+ ATTR_TIMESTAMP_TZ,
44
49
  ATTR_BINARY_DOUBLE,
45
50
  ATTR_BINARY_FLOAT,
46
51
  ATTR_NAMED_TYPE,
@@ -137,10 +142,49 @@ static VALUE oci8_named_type_initialize(VALUE self)
137
142
  return Qnil;
138
143
  }
139
144
 
145
+ typedef struct get_tdo_by_instance_arg {
146
+ VALUE svc;
147
+ void *instance;
148
+ void *typeref;
149
+ } get_tdo_by_instance_arg_t;
150
+
151
+ static VALUE get_tdo_by_instance(VALUE data)
152
+ {
153
+ get_tdo_by_instance_arg_t *arg = (get_tdo_by_instance_arg_t *)data;
154
+ VALUE metadata;
155
+
156
+ chkerr(OCIObjectGetTypeRef(oci8_envhp, oci8_errhp, arg->instance, arg->typeref));
157
+ metadata = oci8_do_describe(arg->svc, arg->typeref, 0, OCI_OTYPE_REF, cOCI8MetadataType, Qfalse);
158
+ return rb_funcall(arg->svc, id_get_tdo_by_metadata, 1, metadata);
159
+ }
160
+
140
161
  static VALUE oci8_named_type_tdo(VALUE self)
141
162
  {
142
163
  oci8_named_type_t *obj = DATA_PTR(self);
143
- return obj->tdo;
164
+ VALUE tdo = obj->tdo;
165
+
166
+ if (!RTEST(rb_ivar_get(tdo, id_at_is_final_type))) {
167
+ /* The type of the instance may be a subtype. */
168
+ oci8_base_t *svcctx;
169
+ get_tdo_by_instance_arg_t arg;
170
+ int state = 0;
171
+
172
+ /* search svcctx */
173
+ svcctx = DATA_PTR(obj->tdo);
174
+ while (svcctx->type != OCI_HTYPE_SVCCTX) {
175
+ svcctx = svcctx->parent;
176
+ }
177
+
178
+ arg.svc = svcctx->self;
179
+ arg.instance = *obj->instancep;
180
+ chkerr(OCIObjectNew(oci8_envhp, oci8_errhp, svcctx->hp.svc, OCI_TYPECODE_REF, NULL, NULL, OCI_DURATION_DEFAULT, TRUE, &arg.typeref));
181
+ tdo = rb_protect(get_tdo_by_instance, (VALUE)&arg, &state);
182
+ chkerr(OCIObjectFree(oci8_envhp, oci8_errhp, arg.typeref, OCI_OBJECTFREE_FORCE));
183
+ if (state != 0) {
184
+ rb_jump_tag(state);
185
+ }
186
+ }
187
+ return tdo;
144
188
  }
145
189
 
146
190
  static void oci8_named_type_check_offset(VALUE self, VALUE val_offset, VALUE ind_offset, size_t val_size, void **instancep, OCIInd **indp)
@@ -193,6 +237,10 @@ static VALUE get_attribute(VALUE self, VALUE datatype, VALUE typeinfo, void *dat
193
237
  return oci8_make_integer((OCINumber *)data, oci8_errhp);
194
238
  case ATTR_OCIDATE:
195
239
  return oci8_make_ocidate((OCIDate *)data);
240
+ case ATTR_TIMESTAMP:
241
+ return oci8_make_ocitimestamp(*(OCIDateTime**)data, FALSE);
242
+ case ATTR_TIMESTAMP_TZ:
243
+ return oci8_make_ocitimestamp(*(OCIDateTime**)data, TRUE);
196
244
  case ATTR_BINARY_DOUBLE:
197
245
  return rb_float_new(*(double*)data);
198
246
  case ATTR_BINARY_FLOAT:
@@ -371,6 +419,18 @@ static VALUE oci8_named_coll_set_coll_element(VALUE self, VALUE datatype, VALUE
371
419
  case ATTR_OCIDATE:
372
420
  cb_data.indp = &cb_data.ind;
373
421
  break;
422
+ case ATTR_TIMESTAMP:
423
+ chker2(OCIObjectNew(oci8_envhp, oci8_errhp, svcctx->hp.svc, OCI_TYPECODE_TIMESTAMP, NULL, NULL, OCI_DURATION_SESSION, TRUE, &cb_data.data.ptr),
424
+ svcctx);
425
+ chker2(OCIObjectGetInd(oci8_envhp, oci8_errhp, cb_data.data.ptr, (dvoid**)&cb_data.indp),
426
+ svcctx);
427
+ break;
428
+ case ATTR_TIMESTAMP_TZ:
429
+ chker2(OCIObjectNew(oci8_envhp, oci8_errhp, svcctx->hp.svc, OCI_TYPECODE_TIMESTAMP_TZ, NULL, NULL, OCI_DURATION_SESSION, TRUE, &cb_data.data.ptr),
430
+ svcctx);
431
+ chker2(OCIObjectGetInd(oci8_envhp, oci8_errhp, cb_data.data.ptr, (dvoid**)&cb_data.indp),
432
+ svcctx);
433
+ break;
374
434
  case ATTR_BINARY_DOUBLE:
375
435
  cb_data.data.dbl = 0.0;
376
436
  cb_data.indp = &cb_data.ind;
@@ -425,7 +485,7 @@ static VALUE set_coll_element_func(set_coll_element_cb_data_t *cb_data)
425
485
 
426
486
  chkerr(OCICollSize(oci8_envhp, oci8_errhp, coll, &size));
427
487
  if (RARRAY_LEN(val) < size) {
428
- chkerr(OCICollTrim(oci8_envhp, oci8_errhp, size - RARRAY_LEN(val), coll));
488
+ chkerr(OCICollTrim(oci8_envhp, oci8_errhp, (sb4)(size - RARRAY_LEN(val)), coll));
429
489
  }
430
490
  for (idx = 0; idx < RARRAY_LEN(val); idx++) {
431
491
  switch (FIX2INT(datatype)) {
@@ -465,6 +525,8 @@ static VALUE set_coll_element_ensure(set_coll_element_cb_data_t *cb_data)
465
525
  switch (FIX2INT(datatype)) {
466
526
  case ATTR_STRING:
467
527
  case ATTR_RAW:
528
+ case ATTR_TIMESTAMP:
529
+ case ATTR_TIMESTAMP_TZ:
468
530
  case ATTR_NAMED_TYPE:
469
531
  case ATTR_NAMED_COLLECTION:
470
532
  if (cb_data->data.ptr != NULL) {
@@ -497,13 +559,13 @@ static void set_attribute(VALUE self, VALUE datatype, VALUE typeinfo, void *data
497
559
  case ATTR_STRING:
498
560
  OCI8StringValue(val);
499
561
  chkerr(OCIStringAssignText(oci8_envhp, oci8_errhp,
500
- RSTRING_ORATEXT(val), RSTRING_LEN(val),
562
+ RSTRING_ORATEXT(val), RSTRING_LENINT(val),
501
563
  (OCIString **)data));
502
564
  break;
503
565
  case ATTR_RAW:
504
566
  StringValue(val);
505
567
  chkerr(OCIRawAssignBytes(oci8_envhp, oci8_errhp,
506
- RSTRING_ORATEXT(val), RSTRING_LEN(val),
568
+ RSTRING_ORATEXT(val), RSTRING_LENINT(val),
507
569
  (OCIRaw **)data));
508
570
  break;
509
571
  case ATTR_OCINUMBER:
@@ -516,6 +578,12 @@ static void set_attribute(VALUE self, VALUE datatype, VALUE typeinfo, void *data
516
578
  case ATTR_OCIDATE:
517
579
  oci8_set_ocidate((OCIDate*)data, val);
518
580
  break;
581
+ case ATTR_TIMESTAMP:
582
+ oci8_set_ocitimestamp_tz(*(OCIDateTime **)data, val, Qnil);
583
+ break;
584
+ case ATTR_TIMESTAMP_TZ:
585
+ oci8_set_ocitimestamp_tz(*(OCIDateTime **)data, val, Qnil);
586
+ break;
519
587
  case ATTR_BINARY_DOUBLE:
520
588
  *(double*)data = NUM2DBL(val);
521
589
  break;
@@ -612,45 +680,57 @@ static VALUE oci8_named_collection_alloc(VALUE klass)
612
680
  return oci8_allocate_typeddata(klass, &oci8_named_collection_data_type);
613
681
  }
614
682
 
683
+ typedef struct {
684
+ oci8_bind_t bind;
685
+ VALUE *obj;
686
+ } bind_named_type_t;
687
+
615
688
  static void bind_named_type_mark(oci8_base_t *base)
616
689
  {
617
- oci8_bind_t *obind = (oci8_bind_t *)base;
618
- oci8_hp_obj_t *oho = (oci8_hp_obj_t *)obind->valuep;
690
+ bind_named_type_t *bnt = (bind_named_type_t *)base;
619
691
 
620
- if (oho != NULL) {
692
+ if (bnt->obj != NULL) {
621
693
  ub4 idx = 0;
622
694
 
623
695
  do {
624
- rb_gc_mark(oho[idx].obj);
625
- } while (++idx < obind->maxar_sz);
696
+ rb_gc_mark(bnt->obj[idx]);
697
+ } while (++idx < bnt->bind.maxar_sz);
626
698
  }
627
- rb_gc_mark(obind->tdo);
699
+ rb_gc_mark(bnt->bind.tdo);
628
700
  }
629
701
 
630
702
  static void bind_named_type_free(oci8_base_t *base)
631
703
  {
632
- oci8_bind_t *obind = (oci8_bind_t *)base;
633
- oci8_hp_obj_t *oho = (oci8_hp_obj_t *)obind->valuep;
704
+ bind_named_type_t *bnt = (bind_named_type_t *)base;
705
+ void **hp = (void **)bnt->bind.valuep;
634
706
 
635
- if (oho != NULL) {
707
+ if (hp != NULL) {
636
708
  ub4 idx = 0;
637
709
 
638
710
  do {
639
- if (oho[idx].hp != NULL) {
640
- OCIObjectFree(oci8_envhp, oci8_errhp, oho[idx].hp, OCI_DEFAULT);
641
- oho[idx].hp = NULL;
711
+ if (hp[idx] != NULL) {
712
+ OCIObjectFree(oci8_envhp, oci8_errhp, hp[idx], OCI_DEFAULT);
713
+ hp[idx] = NULL;
642
714
  }
643
- } while (++idx < obind->maxar_sz);
715
+ } while (++idx < bnt->bind.maxar_sz);
716
+ }
717
+ if (bnt->obj != NULL) {
718
+ xfree(bnt->obj);
719
+ bnt->obj = NULL;
644
720
  }
645
721
  oci8_bind_free(base);
646
722
  }
647
723
 
648
724
  static VALUE bind_named_type_get(oci8_bind_t *obind, void *data, void *null_struct)
649
725
  {
650
- oci8_hp_obj_t *oho = (oci8_hp_obj_t *)data;
651
- return oho->obj;
726
+ bind_named_type_t *bnt = (bind_named_type_t *)obind;
727
+ ub4 idx = obind->curar_idx;
728
+
729
+ return bnt->obj[idx];
652
730
  }
653
731
 
732
+ NORETURN(static void bind_named_type_set(oci8_bind_t *obind, void *data, void **null_structp, VALUE val));
733
+
654
734
  static void bind_named_type_set(oci8_bind_t *obind, void *data, void **null_structp, VALUE val)
655
735
  {
656
736
  rb_raise(rb_eRuntimeError, "not supported");
@@ -658,10 +738,12 @@ static void bind_named_type_set(oci8_bind_t *obind, void *data, void **null_stru
658
738
 
659
739
  static void bind_named_type_init(oci8_bind_t *obind, VALUE svc, VALUE val, VALUE length)
660
740
  {
741
+ bind_named_type_t *bnt = (bind_named_type_t *)obind;
661
742
  VALUE tdo_obj = length;
662
743
 
663
744
  obind->value_sz = sizeof(void*);
664
- obind->alloc_sz = sizeof(oci8_hp_obj_t);
745
+ obind->alloc_sz = sizeof(void*);
746
+ bnt->obj = xcalloc(sizeof(VALUE), obind->maxar_sz ? obind->maxar_sz : 1);
665
747
 
666
748
  CHECK_TDO(tdo_obj);
667
749
  RB_OBJ_WRITE(obind->base.self, &obind->tdo, tdo_obj);
@@ -669,7 +751,8 @@ static void bind_named_type_init(oci8_bind_t *obind, VALUE svc, VALUE val, VALUE
669
751
 
670
752
  static void bind_named_type_init_elem(oci8_bind_t *obind, VALUE svc)
671
753
  {
672
- oci8_hp_obj_t *oho = (oci8_hp_obj_t *)obind->valuep;
754
+ bind_named_type_t *bnt = (bind_named_type_t *)obind;
755
+ void **hp = (void **)obind->valuep;
673
756
  oci8_base_t *tdo = DATA_PTR(obind->tdo);
674
757
  OCITypeCode tc = OCITypeTypeCode(oci8_envhp, oci8_errhp, tdo->hp.tdo);
675
758
  VALUE klass = Qnil;
@@ -687,14 +770,14 @@ static void bind_named_type_init_elem(oci8_bind_t *obind, VALUE svc)
687
770
  }
688
771
  svcctx = oci8_get_svcctx(svc);
689
772
  do {
690
- oho[idx].obj = rb_class_new_instance(0, NULL, klass);
691
- RB_OBJ_WRITTEN(obind->base.self, Qundef, oho[idx].obj);
692
- obj = DATA_PTR(oho[idx].obj);
693
- RB_OBJ_WRITE(oho[idx].obj, &obj->tdo, obind->tdo);
694
- obj->instancep = (char**)&oho[idx].hp;
773
+ bnt->obj[idx] = rb_class_new_instance(0, NULL, klass);
774
+ RB_OBJ_WRITTEN(obind->base.self, Qundef, bnt->obj[idx]);
775
+ obj = DATA_PTR(bnt->obj[idx]);
776
+ RB_OBJ_WRITE(bnt->obj[idx], &obj->tdo, obind->tdo);
777
+ obj->instancep = (char**)&hp[idx];
695
778
  obj->null_structp = (char**)&obind->u.null_structs[idx];
696
779
  oci8_link_to_parent(&obj->base, &obind->base);
697
- RB_OBJ_WRITTEN(oho[idx].obj, Qundef, obind->base.self);
780
+ RB_OBJ_WRITTEN(bnt->obj[idx], Qundef, obind->base.self);
698
781
 
699
782
  chker2(OCIObjectNew(oci8_envhp, oci8_errhp, svcctx->base.hp.svc, tc, tdo->hp.tdo, NULL, OCI_DURATION_SESSION, TRUE, (dvoid**)obj->instancep),
700
783
  &svcctx->base);
@@ -736,7 +819,7 @@ static const oci8_bind_data_type_t bind_named_type_data_type = {
736
819
  #endif
737
820
  },
738
821
  bind_named_type_free,
739
- sizeof(oci8_bind_t)
822
+ sizeof(bind_named_type_t)
740
823
  },
741
824
  bind_named_type_get,
742
825
  bind_named_type_set,
@@ -754,8 +837,11 @@ static VALUE bind_named_type_alloc(VALUE klass)
754
837
 
755
838
  void Init_oci_object(VALUE cOCI8)
756
839
  {
840
+ cOCI8MetadataType = rb_eval_string("OCI8::Metadata::Type");
757
841
  id_to_value = rb_intern("to_value");
758
842
  id_set_attributes = rb_intern("attributes=");
843
+ id_get_tdo_by_metadata = rb_intern("get_tdo_by_metadata");
844
+ id_at_is_final_type = rb_intern("@is_final_type");
759
845
 
760
846
  /* OCI8::TDO */
761
847
  cOCI8TDO = oci8_define_class_under(cOCI8, "TDO", &oci8_tdo_data_type, oci8_tdo_alloc);
@@ -773,6 +859,10 @@ void Init_oci_object(VALUE cOCI8)
773
859
  /* @private */
774
860
  rb_define_const(cOCI8TDO, "ATTR_OCIDATE", INT2FIX(ATTR_OCIDATE));
775
861
  /* @private */
862
+ rb_define_const(cOCI8TDO, "ATTR_TIMESTAMP", INT2FIX(ATTR_TIMESTAMP));
863
+ /* @private */
864
+ rb_define_const(cOCI8TDO, "ATTR_TIMESTAMP_TZ", INT2FIX(ATTR_TIMESTAMP_TZ));
865
+ /* @private */
776
866
  rb_define_const(cOCI8TDO, "ATTR_BINARY_DOUBLE", INT2FIX(ATTR_BINARY_DOUBLE));
777
867
  /* @private */
778
868
  rb_define_const(cOCI8TDO, "ATTR_BINARY_FLOAT", INT2FIX(ATTR_BINARY_FLOAT));