ruby-oci8 1.0.7 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. data/ChangeLog +1254 -390
  2. data/Makefile +10 -13
  3. data/README +56 -385
  4. data/VERSION +1 -1
  5. data/dist-files +26 -27
  6. data/ext/oci8/.document +1 -0
  7. data/ext/oci8/MANIFEST +0 -4
  8. data/ext/oci8/apiwrap.c.tmpl +172 -0
  9. data/ext/oci8/apiwrap.h.tmpl +61 -0
  10. data/ext/oci8/apiwrap.rb +91 -0
  11. data/ext/oci8/apiwrap.yml +1243 -0
  12. data/ext/oci8/attr.c +124 -384
  13. data/ext/oci8/bind.c +472 -164
  14. data/ext/oci8/encoding.c +196 -0
  15. data/ext/oci8/env.c +84 -253
  16. data/ext/oci8/error.c +196 -127
  17. data/ext/oci8/extconf.rb +82 -59
  18. data/ext/oci8/lob.c +710 -370
  19. data/ext/oci8/metadata.c +359 -0
  20. data/ext/oci8/object.c +622 -0
  21. data/ext/oci8/oci8.c +577 -161
  22. data/ext/oci8/oci8.h +354 -258
  23. data/ext/oci8/oci8lib.c +493 -0
  24. data/ext/oci8/ocidatetime.c +473 -0
  25. data/ext/oci8/ocinumber.c +1123 -24
  26. data/ext/oci8/oraconf.rb +72 -106
  27. data/ext/oci8/oradate.c +511 -321
  28. data/ext/oci8/stmt.c +752 -572
  29. data/ext/oci8/win32.c +131 -0
  30. data/ext/oci8/xmldb.c +383 -0
  31. data/lib/.document +2 -0
  32. data/lib/dbd/OCI8.rb +2 -17
  33. data/lib/oci8.rb.in +41 -1622
  34. data/lib/oci8/.document +5 -0
  35. data/lib/oci8/compat.rb +108 -0
  36. data/lib/oci8/datetime.rb +489 -0
  37. data/lib/oci8/encoding-init.rb +40 -0
  38. data/lib/oci8/encoding.yml +537 -0
  39. data/lib/oci8/metadata.rb +2077 -0
  40. data/lib/oci8/object.rb +548 -0
  41. data/lib/oci8/oci8.rb +773 -0
  42. data/lib/oci8/oracle_version.rb +144 -0
  43. data/metaconfig +3 -3
  44. data/ruby-oci8.gemspec +5 -5
  45. data/setup.rb +4 -4
  46. data/test/config.rb +64 -84
  47. data/test/test_all.rb +14 -21
  48. data/test/test_array_dml.rb +317 -0
  49. data/test/test_bind_raw.rb +18 -25
  50. data/test/test_bind_time.rb +78 -91
  51. data/test/test_break.rb +37 -35
  52. data/test/test_clob.rb +33 -89
  53. data/test/test_connstr.rb +5 -4
  54. data/test/test_datetime.rb +469 -0
  55. data/test/test_dbi.rb +99 -60
  56. data/test/test_dbi_clob.rb +3 -8
  57. data/test/test_metadata.rb +65 -51
  58. data/test/test_oci8.rb +151 -55
  59. data/test/test_oracle_version.rb +70 -0
  60. data/test/test_oradate.rb +76 -83
  61. data/test/test_oranumber.rb +405 -71
  62. data/test/test_rowid.rb +6 -11
  63. metadata +31 -32
  64. data/NEWS +0 -420
  65. data/ext/oci8/const.c +0 -165
  66. data/ext/oci8/define.c +0 -53
  67. data/ext/oci8/describe.c +0 -81
  68. data/ext/oci8/descriptor.c +0 -39
  69. data/ext/oci8/handle.c +0 -273
  70. data/ext/oci8/oranumber.c +0 -445
  71. data/ext/oci8/param.c +0 -37
  72. data/ext/oci8/server.c +0 -182
  73. data/ext/oci8/session.c +0 -99
  74. data/ext/oci8/svcctx.c +0 -238
  75. data/ruby-oci8.spec +0 -62
  76. data/support/README +0 -4
  77. data/support/runit/assert.rb +0 -281
  78. data/support/runit/cui/testrunner.rb +0 -101
  79. data/support/runit/error.rb +0 -4
  80. data/support/runit/method_mappable.rb +0 -20
  81. data/support/runit/robserver.rb +0 -25
  82. data/support/runit/setuppable.rb +0 -15
  83. data/support/runit/teardownable.rb +0 -16
  84. data/support/runit/testcase.rb +0 -113
  85. data/support/runit/testfailure.rb +0 -25
  86. data/support/runit/testresult.rb +0 -121
  87. data/support/runit/testsuite.rb +0 -43
  88. data/support/runit/version.rb +0 -3
  89. data/test/test_describe.rb +0 -137
@@ -1,194 +1,502 @@
1
+ /* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
1
2
  /*
2
- define.c - part of ruby-oci8
3
+ * bind.c
4
+ *
5
+ * $Author: kubo $
6
+ * $Date: 2009-01-12 00:11:09 +0900 (Mon, 12 Jan 2009) $
7
+ *
8
+ * Copyright (C) 2002-2008 KUBO Takehiro <kubo@jiubao.org>
9
+ */
10
+ #include "oci8.h"
11
+
12
+ static ID id_bind_type;
13
+ static ID id_set;
3
14
 
4
- Copyright (C) 2002,2006 KUBO Takehiro <kubo@jiubao.org>
15
+ static VALUE cOCI8BindTypeBase;
5
16
 
6
- =begin
7
- == OCIBind
8
- The bind handle, which is created by ((<OCIStmt#bindByPos>)) or ((<OCIStmt#bindByName>)).
17
+ /*
18
+ * bind_string
19
+ */
20
+ static VALUE bind_string_get(oci8_bind_t *obind, void *data, void *null_struct)
21
+ {
22
+ oci8_vstr_t *vstr = (oci8_vstr_t *)data;
23
+ return rb_external_str_new_with_enc(vstr->buf, vstr->size, oci8_encoding);
24
+ }
9
25
 
10
- super class: ((<OCIHandle>))
26
+ static void bind_string_set(oci8_bind_t *obind, void *data, void **null_structp, VALUE val)
27
+ {
28
+ oci8_vstr_t *vstr = (oci8_vstr_t *)data;
11
29
 
12
- correspond native OCI datatype: ((|OCIBind|))
13
- =end
14
- */
15
- #include "oci8.h"
30
+ OCI8StringValue(val);
31
+ if (RSTRING_LEN(val) > obind->value_sz - sizeof(vstr->size)) {
32
+ rb_raise(rb_eArgError, "too long String to set. (%ld for %d)", RSTRING_LEN(val), obind->value_sz - (sb4)sizeof(vstr->size));
33
+ }
34
+ memcpy(vstr->buf, RSTRING_PTR(val), RSTRING_LEN(val));
35
+ vstr->size = RSTRING_LEN(val);
36
+ }
37
+
38
+ static void bind_string_init(oci8_bind_t *obind, VALUE svc, VALUE val, VALUE length)
39
+ {
40
+ sb4 sz;
41
+ if (NIL_P(length)) {
42
+ if (NIL_P(val)) {
43
+ rb_raise(rb_eArgError, "value and length are both null.");
44
+ }
45
+ StringValue(val);
46
+ sz = RSTRING_LEN(val);
47
+ } else {
48
+ sz = NUM2INT(length);
49
+ }
50
+ if (sz <= 0) {
51
+ rb_raise(rb_eArgError, "invalid bind length %d", sz);
52
+ }
53
+ sz += sizeof(sb4);
54
+ obind->value_sz = sz;
55
+ obind->alloc_sz = (sz + (sizeof(sb4) - 1)) & ~(sizeof(sb4) - 1);
56
+ }
57
+
58
+ static const oci8_bind_class_t bind_string_class = {
59
+ {
60
+ NULL,
61
+ oci8_bind_free,
62
+ sizeof(oci8_bind_t)
63
+ },
64
+ bind_string_get,
65
+ bind_string_set,
66
+ bind_string_init,
67
+ NULL,
68
+ NULL,
69
+ NULL,
70
+ NULL,
71
+ SQLT_LVC
72
+ };
16
73
 
17
74
  /*
18
- =begin
19
- --- OCIBind#get()
20
- get the bind value, which set by OCI call.
75
+ * bind_raw
76
+ */
77
+ static VALUE bind_raw_get(oci8_bind_t *obind, void *data, void *null_struct)
78
+ {
79
+ oci8_vstr_t *vstr = (oci8_vstr_t *)data;
80
+ return rb_str_new(vstr->buf, vstr->size);
81
+ }
21
82
 
22
- :return value
23
- the bind value. Its datatype is correspond to the 2nd argument of ((<OCIStmt#bindByPos>)) or ((<OCIStmt#bindByName>)).
83
+ static const oci8_bind_class_t bind_raw_class = {
84
+ {
85
+ NULL,
86
+ oci8_bind_free,
87
+ sizeof(oci8_bind_t)
88
+ },
89
+ bind_raw_get,
90
+ bind_string_set,
91
+ bind_string_init,
92
+ NULL,
93
+ NULL,
94
+ NULL,
95
+ NULL,
96
+ SQLT_LVB
97
+ };
24
98
 
25
- correspond native OCI function: nothing
26
- =end
27
- */
28
- static VALUE oci8_get_data(VALUE self)
99
+ #ifdef USE_DYNAMIC_FETCH /* don't use DYNAMIC_FETCH. It doesn't work well... */
100
+ /*
101
+ * bind_long
102
+ */
103
+ typedef struct {
104
+ VALUE obj;
105
+ ub4 alen;
106
+ char buf[1];
107
+ } bind_long_t;
108
+ #define bind_long_offset ((size_t)((bind_long_t*)0)->buf)
109
+
110
+ static void bind_long_mark(oci8_base_t *base)
29
111
  {
30
- oci8_bind_handle_t *defnhp;
31
- VALUE obj;
112
+ oci8_bind_t *obind = (oci8_bind_t*)base;
113
+ ub4 idx = 0;
32
114
 
33
- Data_Get_Struct(self, oci8_bind_handle_t, defnhp);
34
- obj = oci8_get_value(defnhp);
35
- return obj;
115
+ if (obind->valuep == NULL)
116
+ return;
117
+ do {
118
+ bind_long_t *bl = (bind_long_t *)((char*)obind->valuep + obind->alloc_sz * idx);
119
+ rb_gc_mark(bl->obj);
120
+ } while (++idx < obind->maxar_sz);
36
121
  }
37
122
 
38
- /*
39
- =begin
40
- --- OCIBind#set(value)
41
- get the bind value to pass Oracle via OCI call.
123
+ static VALUE bind_long_get(oci8_bind_t *obind, void *data, void *null_struct)
124
+ {
125
+ bind_long_t *bl = (bind_long_t *)data;
126
+ return RTEST(bl->obj) ? rb_str_dup(bl->obj) : Qnil;
127
+ }
42
128
 
43
- :value
44
- the value to set the bind handle. Its datatype must be correspond to the 2nd argument of ((<OCIStmt#bindByPos>)) or ((<OCIStmt#bindByName>)).
129
+ static void bind_long_set(oci8_bind_t *obind, void *data, void **null_structp, VALUE val)
130
+ {
131
+ bind_long_t *bl = (bind_long_t *)data;
132
+ bl->obj = rb_str_dup(val);
133
+ }
45
134
 
46
- correspond native OCI function: nothing
47
- =end
48
- */
49
- static VALUE oci8_set_data(VALUE self, VALUE val)
135
+ static void bind_long_init(oci8_bind_t *obind, VALUE svc, VALUE val, VALUE length)
50
136
  {
51
- oci8_bind_handle_t *hp;
137
+ sb4 sz = 0;
52
138
 
53
- Data_Get_Struct(self, oci8_bind_handle_t, hp);
54
- oci8_set_value(hp, val);
55
- return self;
139
+ if (!NIL_P(length)) {
140
+ sz = NUM2INT(length);
141
+ }
142
+ if (sz < 4000) {
143
+ sz = 4000;
144
+ }
145
+ sz += bind_long_offset;
146
+ obind->value_sz = INT_MAX;
147
+ obind->alloc_sz = (sz + (sizeof(VALUE) - 1)) & ~(sizeof(VALUE) - 1);
56
148
  }
57
149
 
58
- void Init_oci8_bind(void)
150
+ static void bind_long_init_elem(oci8_bind_t *obind, VALUE svc)
59
151
  {
60
- rb_define_method(cOCIBind, "get", oci8_get_data, 0);
61
- rb_define_method(cOCIBind, "set", oci8_set_data, 1);
152
+ ub4 idx = 0;
153
+
154
+ do {
155
+ bind_long_t *bl = (bind_long_t *)((char*)obind->valuep + obind->alloc_sz * idx);
156
+ bl->obj = Qnil;
157
+ } while (++idx < obind->maxar_sz);
62
158
  }
63
159
 
64
- VALUE oci8_get_value(oci8_bind_handle_t *hp)
160
+ static ub1 bind_long_in(oci8_bind_t *obind, ub4 idx, ub1 piece, void **valuepp, ub4 **alenpp, void **indpp)
65
161
  {
66
- ora_date_t *od;
67
- ora_vnumber_t *ovn;
68
- VALUE obj;
69
- unsigned char buf[ORA_NUMBER_BUF_SIZE];
70
- int year, month, day, hour, minute, second;
71
- static ID id_local = (ID)-1;
162
+ bind_long_t *bl = (bind_long_t *)((char*)obind->valuep + obind->alloc_sz * idx);
72
163
 
73
- if (hp->ind != 0)
74
- return Qnil;
75
- switch (hp->bind_type) {
76
- case BIND_STRING:
77
- return rb_str_new(hp->value.str.buf, hp->value.str.len);
78
- case BIND_FIXNUM:
79
- return LONG2NUM(hp->value.lng);
80
- case BIND_INTEGER_VIA_ORA_NUMBER:
81
- ora_number_to_str(buf, NULL, &(hp->value.on), hp->rlen);
82
- return rb_cstr2inum(TO_CHARPTR(buf), 10);
83
- case BIND_TIME_VIA_ORA_DATE:
84
- oci8_get_ora_date(&(hp->value.od), &year, &month, &day, &hour, &minute, &second);
85
- if (id_local == (ID)-1)
86
- id_local = rb_intern("local");
87
- return rb_funcall(rb_cTime, id_local, 6, INT2FIX(year), INT2FIX(month), INT2FIX(day), INT2FIX(hour), INT2FIX(minute), INT2FIX(second));
88
- case BIND_FLOAT:
89
- case BIND_BINARY_DOUBLE:
90
- return rb_float_new(hp->value.dbl);
91
- case BIND_ORA_DATE:
92
- obj = Data_Make_Struct(cOraDate, ora_date_t, NULL, xfree, od);
93
- memcpy(od, &(hp->value.od), sizeof(ora_date_t));
94
- return obj;
95
- case BIND_ORA_NUMBER:
96
- obj = Data_Make_Struct(cOraNumber, ora_vnumber_t, NULL, xfree, ovn);
97
- ovn->size = hp->rlen;
98
- memcpy(&(ovn->num), &(hp->value.on), sizeof(ora_number_t));
99
- return obj;
100
- case BIND_HANDLE:
101
- return hp->value.handle.v;
102
- }
103
- rb_bug("unsupported data type: %d", hp->bind_type);
104
- }
105
-
106
- void oci8_set_value(oci8_bind_handle_t *hp, VALUE val)
107
- {
108
- ora_date_t *od;
109
- ora_vnumber_t *ovn;
110
- int year, mon, day, hour, min, sec;
111
- static ID id_year = (ID)-1;
112
- static ID id_mon = (ID)-1;
113
- static ID id_day = (ID)-1;
114
- static ID id_hour = (ID)-1;
115
- static ID id_min = (ID)-1;
116
- static ID id_sec = (ID)-1;
117
-
118
- if (NIL_P(val)) {
119
- hp->ind = -1;
120
- return;
121
- }
122
- switch (hp->bind_type) {
123
- case BIND_FIXNUM:
164
+ *alenpp = &bl->alen;
165
+ *indpp = &obind->u.inds[idx];
166
+ if (NIL_P(bl->obj)) {
167
+ *valuepp = NULL;
168
+ bl->alen = 0;
169
+ obind->u.inds[idx] = -1;
170
+ } else {
171
+ StringValue(bl->obj);
172
+ *valuepp = RSTRING_PTR(bl->obj);
173
+ bl->alen = RSTRING_LEN(bl->obj);
174
+ obind->u.inds[idx] = 0;
175
+ }
176
+ return OCI_ONE_PIECE;
177
+ }
178
+
179
+ static void bind_long_out(oci8_bind_t *obind, ub4 idx, ub1 piece, void **valuepp, ub4 **alenpp, void **indpp)
180
+ {
181
+ bind_long_t *bl = (bind_long_t *)((char*)obind->valuep + obind->alloc_sz * idx);
182
+
183
+ switch (piece) {
184
+ case OCI_NEXT_PIECE:
185
+ case OCI_LAST_PIECE:
186
+ if (bl->alen > 0) {
187
+ if (!RTEST(bl->obj)) {
188
+ bl->obj = rb_str_buf_new(bl->alen);
189
+ }
190
+ rb_str_buf_cat(bl->obj, bl->buf, bl->alen);
191
+ }
192
+ break;
193
+ default:
194
+ /* OCI_FIRST_PIECE is passed at the first call according to manuals.
195
+ * But OCI_ONE_PIECE is passed on Oracle 8 and 8i on Windows...
196
+ */
197
+ bl->obj = Qnil;
198
+ }
199
+ *valuepp = bl->buf;
200
+ *alenpp = &bl->alen;
201
+ *indpp = &obind->u.inds[idx];
202
+ bl->alen = obind->alloc_sz - bind_long_offset;
203
+ obind->u.inds[idx] = 0;
204
+ }
205
+
206
+ static const oci8_bind_class_t bind_long_class = {
207
+ {
208
+ bind_long_mark,
209
+ oci8_bind_free,
210
+ sizeof(oci8_bind_t)
211
+ },
212
+ bind_long_get,
213
+ bind_long_set,
214
+ bind_long_init,
215
+ bind_long_init_elem,
216
+ bind_long_in,
217
+ bind_long_out,
218
+ NULL,
219
+ SQLT_CHR
220
+ };
221
+
222
+ /*
223
+ * bind_long_raw
224
+ */
225
+ static const oci8_bind_class_t bind_long_raw_class = {
226
+ {
227
+ bind_long_mark,
228
+ oci8_bind_free,
229
+ sizeof(oci8_bind_t)
230
+ },
231
+ bind_long_get,
232
+ bind_long_set,
233
+ bind_long_init,
234
+ bind_long_init_elem,
235
+ bind_long_in,
236
+ bind_long_out,
237
+ NULL,
238
+ SQLT_BIN
239
+ };
240
+ #endif /* USE_DYNAMIC_FETCH */
241
+
242
+ /*
243
+ * bind_fixnum
244
+ */
245
+ static VALUE bind_fixnum_get(oci8_bind_t *obind, void *data, void *null_struct)
246
+ {
247
+ return LONG2NUM(*(long*)data);
248
+ }
249
+
250
+ static void bind_fixnum_set(oci8_bind_t *obind, void *data, void **null_structp, VALUE val)
251
+ {
124
252
  Check_Type(val, T_FIXNUM);
125
- hp->value.lng = FIX2LONG(val);
126
- break;
127
- case BIND_STRING:
128
- Check_Type(val, T_STRING);
129
- if (hp->value_sz - 4 < RSTRING_LEN(val)) {
130
- rb_raise(rb_eArgError, "Assigned string is too long. %ld (max %d)", RSTRING_LEN(val), hp->value_sz - 4);
131
- }
132
- memcpy(hp->value.str.buf, RSTRING_PTR(val), RSTRING_LEN(val));
133
- hp->value.str.len = RSTRING_LEN(val);
134
- break;
135
- case BIND_TIME_VIA_ORA_DATE:
136
- if (!rb_obj_is_instance_of(val, rb_cTime)) {
137
- rb_raise(rb_eTypeError, "invalid argument (expect Time)");
138
- }
139
- #define GET_TIME_OF_XXX(name) \
140
- if (id_##name == (ID)-1) \
141
- id_##name = rb_intern(#name); \
142
- name = FIX2INT(rb_funcall(val, id_##name, 0))
143
- GET_TIME_OF_XXX(year);
144
- GET_TIME_OF_XXX(mon);
145
- GET_TIME_OF_XXX(day);
146
- GET_TIME_OF_XXX(hour);
147
- GET_TIME_OF_XXX(min);
148
- GET_TIME_OF_XXX(sec);
149
- oci8_set_ora_date(&(hp->value.od), year, mon, day, hour, min, sec);
150
- break;
151
- case BIND_FLOAT:
152
- case BIND_BINARY_DOUBLE:
253
+ *(long*)data = FIX2LONG(val);
254
+ }
255
+
256
+ static void bind_fixnum_init(oci8_bind_t *obind, VALUE svc, VALUE val, VALUE length)
257
+ {
258
+ obind->value_sz = sizeof(long);
259
+ obind->alloc_sz = sizeof(long);
260
+ }
261
+
262
+ static const oci8_bind_class_t bind_fixnum_class = {
263
+ {
264
+ NULL,
265
+ oci8_bind_free,
266
+ sizeof(oci8_bind_t)
267
+ },
268
+ bind_fixnum_get,
269
+ bind_fixnum_set,
270
+ bind_fixnum_init,
271
+ NULL,
272
+ NULL,
273
+ NULL,
274
+ NULL,
275
+ SQLT_INT
276
+ };
277
+
278
+ /*
279
+ * bind_float
280
+ */
281
+ static VALUE bind_float_get(oci8_bind_t *obind, void *data, void *null_struct)
282
+ {
283
+ return rb_float_new(*(double*)data);
284
+ }
285
+
286
+ static void bind_float_set(oci8_bind_t *obind, void *data, void **null_structp, VALUE val)
287
+ {
153
288
  Check_Type(val, T_FLOAT);
154
- hp->value.dbl = RFLOAT(val)->value;
155
- break;
156
- case BIND_ORA_DATE:
157
- if (!rb_obj_is_instance_of(val, cOraDate)) {
158
- rb_raise(rb_eTypeError, "invalid argument (expect OraDate)");
159
- }
160
- Data_Get_Struct(val, ora_date_t, od);
161
- memcpy(&(hp->value.od), od, sizeof(ora_date_t));
162
- break;
163
- case BIND_INTEGER_VIA_ORA_NUMBER:
164
- case BIND_ORA_NUMBER:
165
- if (rb_obj_is_instance_of(val, cOraNumber)) {
166
- Data_Get_Struct(val, ora_vnumber_t, ovn);
167
- hp->rlen = ovn->size;
168
- memcpy(&(hp->value.on), &(ovn->num), sizeof(ora_number_t));
169
- } else if (rb_obj_is_kind_of(val, rb_cNumeric)) {
170
- ora_vnumber_t ovn;
171
- if (set_oci_vnumber(&ovn, val, hp->errhp) == 0) {
172
- rb_raise(rb_eTypeError, "could not bind value.");
173
- }
174
- hp->rlen = ovn.size;
175
- memcpy(&(hp->value.on), &(ovn.num), sizeof(ora_number_t));
289
+ *(double*)data = RFLOAT_VALUE(val);
290
+ }
291
+
292
+ static void bind_float_init(oci8_bind_t *obind, VALUE svc, VALUE val, VALUE length)
293
+ {
294
+ obind->value_sz = sizeof(double);
295
+ obind->alloc_sz = sizeof(double);
296
+ }
297
+
298
+ static const oci8_bind_class_t bind_float_class = {
299
+ {
300
+ NULL,
301
+ oci8_bind_free,
302
+ sizeof(oci8_bind_t)
303
+ },
304
+ bind_float_get,
305
+ bind_float_set,
306
+ bind_float_init,
307
+ NULL,
308
+ NULL,
309
+ NULL,
310
+ NULL,
311
+ SQLT_FLT
312
+ };
313
+
314
+ #ifndef SQLT_BDOUBLE
315
+ #define SQLT_BDOUBLE 22
316
+ #endif
317
+ static const oci8_bind_class_t bind_binary_double_class = {
318
+ {
319
+ NULL,
320
+ oci8_bind_free,
321
+ sizeof(oci8_bind_t)
322
+ },
323
+ bind_float_get,
324
+ bind_float_set,
325
+ bind_float_init,
326
+ NULL,
327
+ NULL,
328
+ NULL,
329
+ NULL,
330
+ SQLT_BDOUBLE
331
+ };
332
+
333
+ static inline VALUE oci8_get_data_at(const oci8_bind_class_t *obc, oci8_bind_t *obind, ub4 idx)
334
+ {
335
+ void **null_structp = NULL;
336
+
337
+ if (NIL_P(obind->tdo)) {
338
+ if (obind->u.inds[idx] != 0)
339
+ return Qnil;
340
+ } else {
341
+ null_structp = &obind->u.null_structs[idx];
342
+ if (*(OCIInd*)*null_structp != 0)
343
+ return Qnil;
344
+ }
345
+ return obc->get(obind, (void*)((size_t)obind->valuep + obind->alloc_sz * idx), null_structp);
346
+ }
347
+
348
+ static VALUE oci8_get_data(VALUE self)
349
+ {
350
+ oci8_bind_t *obind = DATA_PTR(self);
351
+ const oci8_bind_class_t *obc = (const oci8_bind_class_t *)obind->base.klass;
352
+
353
+ if (obind->maxar_sz == 0) {
354
+ return oci8_get_data_at(obc, obind, 0);
355
+ } else {
356
+ volatile VALUE ary = rb_ary_new2(obind->curar_sz);
357
+ ub4 idx;
358
+
359
+ for (idx = 0; idx < obind->curar_sz; idx++) {
360
+ rb_ary_store(ary, idx, oci8_get_data_at(obc, obind, idx));
361
+ }
362
+ return ary;
363
+ }
364
+ }
365
+
366
+ static inline void oci8_set_data_at(const oci8_bind_class_t *obc, oci8_bind_t *obind, ub4 idx, VALUE val)
367
+ {
368
+
369
+ if (NIL_P(val)) {
370
+ if (NIL_P(obind->tdo)) {
371
+ obind->u.inds[idx] = -1;
372
+ } else {
373
+ *(OCIInd*)obind->u.null_structs[idx] = -1;
374
+ }
375
+ } else {
376
+ void **null_structp = NULL;
377
+
378
+ if (NIL_P(obind->tdo)) {
379
+ null_structp = NULL;
380
+ obind->u.inds[idx] = 0;
381
+ } else {
382
+ null_structp = &obind->u.null_structs[idx];
383
+ }
384
+ obc->set(obind, (void*)((size_t)obind->valuep + obind->alloc_sz * idx), null_structp, val);
385
+ }
386
+ }
387
+
388
+ static VALUE oci8_set_data(VALUE self, VALUE val)
389
+ {
390
+ oci8_bind_t *obind = DATA_PTR(self);
391
+ const oci8_bind_class_t *obc = (const oci8_bind_class_t *)obind->base.klass;
392
+
393
+ if (obind->maxar_sz == 0) {
394
+ oci8_set_data_at(obc, obind, 0, val);
395
+ } else {
396
+ ub4 size;
397
+ ub4 idx;
398
+ Check_Type(val, T_ARRAY);
399
+
400
+ size = RARRAY_LEN(val);
401
+ if (size > obind->maxar_sz) {
402
+ rb_raise(rb_eRuntimeError, "over the max array size");
403
+ }
404
+ for (idx = 0; idx < size; idx++) {
405
+ oci8_set_data_at(obc, obind, idx, RARRAY_PTR(val)[idx]);
406
+ }
407
+ obind->curar_sz = size;
408
+ }
409
+ return self;
410
+ }
411
+
412
+ static VALUE oci8_bind_initialize(VALUE self, VALUE svc, VALUE val, VALUE length, VALUE max_array_size)
413
+ {
414
+ oci8_bind_t *obind = DATA_PTR(self);
415
+ const oci8_bind_class_t *bind_class = (const oci8_bind_class_t *)obind->base.klass;
416
+ ub4 cnt = 1;
417
+
418
+ obind->tdo = Qnil;
419
+ obind->maxar_sz = NIL_P(max_array_size) ? 0 : NUM2UINT(max_array_size);
420
+ obind->curar_sz = 0;
421
+ if (obind->maxar_sz > 0)
422
+ cnt = obind->maxar_sz;
423
+ bind_class->init(obind, svc, val, length);
424
+ if (obind->alloc_sz > 0) {
425
+ obind->valuep = xmalloc(obind->alloc_sz * cnt);
426
+ memset(obind->valuep, 0, obind->alloc_sz * cnt);
176
427
  } else {
177
- rb_raise(rb_eTypeError, "invalid argument (expect OraNumber)");
178
- }
179
- break;
180
- case BIND_HANDLE:
181
- if (rb_obj_is_kind_of(val, hp->value.handle.klass)) {
182
- oci8_handle_t *h;
183
- Get_Handle(val, h);
184
- hp->value.handle.v = val;
185
- hp->value.handle.hp = h->hp;
428
+ obind->valuep = NULL;
429
+ }
430
+ if (NIL_P(obind->tdo)) {
431
+ obind->u.inds = xmalloc(sizeof(sb2) * cnt);
432
+ memset(obind->u.inds, -1, sizeof(sb2) * cnt);
186
433
  } else {
187
- rb_raise(rb_eTypeError, "invalid argument: %s (expect %s)", rb_obj_classname(val), rb_class2name(hp->value.handle.klass));
434
+ obind->u.null_structs = xmalloc(sizeof(void *) * cnt);
435
+ memset(obind->u.null_structs, 0, sizeof(void *) * cnt);
436
+ }
437
+ if (bind_class->init_elem != NULL) {
438
+ bind_class->init_elem(obind, svc);
439
+ }
440
+ if (!NIL_P(val)) {
441
+ rb_funcall(self, id_set, 1, val);
442
+ }
443
+ return Qnil;
444
+ }
445
+
446
+ void oci8_bind_free(oci8_base_t *base)
447
+ {
448
+ oci8_bind_t *obind = (oci8_bind_t *)base;
449
+ if (obind->valuep != NULL) {
450
+ xfree(obind->valuep);
451
+ obind->valuep = NULL;
452
+ }
453
+ if (obind->u.inds != NULL) {
454
+ xfree(obind->u.inds);
455
+ obind->u.inds = NULL;
188
456
  }
189
- break;
190
- default:
191
- rb_bug("unsupported data type: %d", hp->bind_type);
192
- }
193
- hp->ind = 0;
457
+ }
458
+
459
+ void oci8_bind_hp_obj_mark(oci8_base_t *base)
460
+ {
461
+ oci8_bind_t *obind = (oci8_bind_t *)base;
462
+ oci8_hp_obj_t *oho = (oci8_hp_obj_t *)obind->valuep;
463
+
464
+ if (oho != NULL) {
465
+ ub4 idx = 0;
466
+
467
+ do {
468
+ rb_gc_mark(oho[idx].obj);
469
+ } while (++idx < obind->maxar_sz);
470
+ }
471
+ }
472
+
473
+ void Init_oci8_bind(VALUE klass)
474
+ {
475
+ cOCI8BindTypeBase = klass;
476
+ id_bind_type = rb_intern("bind_type");
477
+ id_set = rb_intern("set");
478
+
479
+ rb_define_method(cOCI8BindTypeBase, "initialize", oci8_bind_initialize, 4);
480
+ rb_define_method(cOCI8BindTypeBase, "get", oci8_get_data, 0);
481
+ rb_define_method(cOCI8BindTypeBase, "set", oci8_set_data, 1);
482
+
483
+ /* register primitive data types. */
484
+ oci8_define_bind_class("String", &bind_string_class);
485
+ oci8_define_bind_class("RAW", &bind_raw_class);
486
+ #ifdef USE_DYNAMIC_FETCH
487
+ oci8_define_bind_class("Long", &bind_long_class);
488
+ oci8_define_bind_class("LongRaw", &bind_long_raw_class);
489
+ #endif /* USE_DYNAMIC_FETCH */
490
+ oci8_define_bind_class("Fixnum", &bind_fixnum_class);
491
+ oci8_define_bind_class("Float", &bind_float_class);
492
+ if (oracle_client_version >= ORAVER_10_1) {
493
+ oci8_define_bind_class("BinaryDouble", &bind_binary_double_class);
494
+ }
495
+ }
496
+
497
+ oci8_bind_t *oci8_get_bind(VALUE obj)
498
+ {
499
+ oci8_base_t *base;
500
+ Check_Handle(obj, cOCI8BindTypeBase, base);
501
+ return (oci8_bind_t *)base;
194
502
  }