ruby-oci8 1.0.7 → 2.0.0

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.
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
  }