ruby-oci8 2.0.6 → 2.1.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 (59) hide show
  1. data/ChangeLog +366 -19
  2. data/Makefile +2 -8
  3. data/NEWS +111 -0
  4. data/README +4 -85
  5. data/VERSION +1 -1
  6. data/dist-files +9 -2
  7. data/ext/oci8/.document +1 -0
  8. data/ext/oci8/apiwrap.c.tmpl +12 -2
  9. data/ext/oci8/apiwrap.yml +37 -21
  10. data/ext/oci8/attr.c +23 -74
  11. data/ext/oci8/bind.c +93 -225
  12. data/ext/oci8/connection_pool.c +201 -0
  13. data/ext/oci8/encoding.c +117 -24
  14. data/ext/oci8/env.c +5 -10
  15. data/ext/oci8/error.c +171 -189
  16. data/ext/oci8/extconf.rb +6 -2
  17. data/ext/oci8/lob.c +81 -79
  18. data/ext/oci8/metadata.c +42 -177
  19. data/ext/oci8/object.c +55 -28
  20. data/ext/oci8/oci8.c +426 -294
  21. data/ext/oci8/oci8.h +84 -51
  22. data/ext/oci8/oci8lib.c +75 -53
  23. data/ext/oci8/ocidatetime.c +67 -88
  24. data/ext/oci8/ocihandle.c +78 -37
  25. data/ext/oci8/ocinumber.c +166 -109
  26. data/ext/oci8/oraconf.rb +68 -157
  27. data/ext/oci8/oradate.c +2 -7
  28. data/ext/oci8/stmt.c +40 -183
  29. data/ext/oci8/thread_util.c +85 -0
  30. data/ext/oci8/thread_util.h +30 -0
  31. data/lib/oci8.rb.in +19 -13
  32. data/lib/oci8/.document +2 -0
  33. data/lib/oci8/bindtype.rb +62 -45
  34. data/lib/oci8/connection_pool.rb +118 -0
  35. data/lib/oci8/datetime.rb +304 -320
  36. data/lib/oci8/encoding-init.rb +62 -30
  37. data/lib/oci8/encoding.yml +3 -3
  38. data/lib/oci8/metadata.rb +552 -497
  39. data/lib/oci8/object.rb +9 -9
  40. data/lib/oci8/oci8.rb +161 -2
  41. data/lib/oci8/ocihandle.rb +427 -0
  42. data/lib/oci8/properties.rb +31 -1
  43. data/ruby-oci8.gemspec +10 -3
  44. data/test/README +41 -3
  45. data/test/config.rb +16 -0
  46. data/test/test_all.rb +3 -0
  47. data/test/test_bind_string.rb +106 -0
  48. data/test/test_break.rb +33 -7
  49. data/test/test_clob.rb +13 -10
  50. data/test/test_connection_pool.rb +125 -0
  51. data/test/test_connstr.rb +2 -2
  52. data/test/test_datetime.rb +26 -66
  53. data/test/test_encoding.rb +7 -3
  54. data/test/test_error.rb +88 -0
  55. data/test/test_metadata.rb +1356 -204
  56. data/test/test_oci8.rb +27 -8
  57. data/test/test_oranumber.rb +41 -0
  58. metadata +34 -9
  59. data/ext/oci8/xmldb.c +0 -383
@@ -2,19 +2,31 @@
2
2
  /*
3
3
  * bind.c
4
4
  *
5
- * $Author: kubo $
6
- * $Date: 2010-12-14 20:30:44 +0900 (Tue, 14 Dec 2010) $
7
- *
8
- * Copyright (C) 2002-2008 KUBO Takehiro <kubo@jiubao.org>
5
+ * Copyright (C) 2002-2011 KUBO Takehiro <kubo@jiubao.org>
9
6
  */
10
7
  #include "oci8.h"
11
8
 
9
+ #ifndef OCI_ATTR_MAXCHAR_SIZE
10
+ #define OCI_ATTR_MAXCHAR_SIZE 164
11
+ #endif
12
+
12
13
  static ID id_bind_type;
14
+ static VALUE sym_length;
15
+ static VALUE sym_length_semantics;
16
+ static VALUE sym_char;
17
+ static VALUE sym_nchar;
13
18
 
14
19
  static VALUE cOCI8BindTypeBase;
15
20
 
21
+ typedef struct {
22
+ oci8_bind_t obind;
23
+ sb4 bytelen;
24
+ sb4 charlen;
25
+ ub1 csfrm;
26
+ } oci8_bind_string_t;
27
+
16
28
  /*
17
- * bind_char and bind_nchar
29
+ * bind_string
18
30
  */
19
31
  static VALUE bind_string_get(oci8_bind_t *obind, void *data, void *null_struct)
20
32
  {
@@ -24,67 +36,87 @@ static VALUE bind_string_get(oci8_bind_t *obind, void *data, void *null_struct)
24
36
 
25
37
  static void bind_string_set(oci8_bind_t *obind, void *data, void **null_structp, VALUE val)
26
38
  {
39
+ oci8_bind_string_t *obs = (oci8_bind_string_t *)obind;
27
40
  oci8_vstr_t *vstr = (oci8_vstr_t *)data;
28
41
 
29
42
  OCI8StringValue(val);
30
- if (RSTRING_LEN(val) > obind->value_sz - sizeof(vstr->size)) {
31
- rb_raise(rb_eArgError, "too long String to set. (%ld for %d)", RSTRING_LEN(val), obind->value_sz - (sb4)sizeof(vstr->size));
43
+ if (RSTRING_LEN(val) > obs->bytelen) {
44
+ rb_raise(rb_eArgError, "too long String to set. (%ld for %d)", RSTRING_LEN(val), obs->bytelen);
32
45
  }
33
46
  memcpy(vstr->buf, RSTRING_PTR(val), RSTRING_LEN(val));
34
47
  vstr->size = RSTRING_LEN(val);
35
48
  }
36
49
 
37
- static void bind_string_init(oci8_bind_t *obind, VALUE svc, VALUE val, VALUE length)
50
+ static void bind_string_init(oci8_bind_t *obind, VALUE svc, VALUE val, VALUE param)
38
51
  {
52
+ oci8_bind_string_t *obs = (oci8_bind_string_t *)obind;
53
+ VALUE length;
54
+ VALUE length_semantics;
55
+ VALUE nchar;
39
56
  sb4 sz;
40
- if (NIL_P(length)) {
41
- if (NIL_P(val)) {
42
- rb_raise(rb_eArgError, "value and length are both null.");
57
+
58
+ Check_Type(param, T_HASH);
59
+ length = rb_hash_aref(param, sym_length);
60
+ length_semantics = rb_hash_aref(param, sym_length_semantics);
61
+ nchar = rb_hash_aref(param, sym_nchar);
62
+
63
+ sz = NUM2INT(length);
64
+ if (sz < 0) {
65
+ rb_raise(rb_eArgError, "invalid bind length %d", sz);
66
+ }
67
+ if (length_semantics == sym_char) {
68
+ /* character semantics */
69
+ obs->charlen = sz;
70
+ obs->bytelen = sz = sz * oci8_nls_ratio;
71
+ if (oci8_nls_ratio == 1) {
72
+ /* sz must be bigger than charlen to suppress ORA-06502.
73
+ * I don't know the reason...
74
+ */
75
+ sz *= 2;
43
76
  }
44
- StringValue(val);
45
- sz = RSTRING_LEN(val);
46
77
  } else {
47
- sz = NUM2INT(length);
78
+ /* byte semantics */
79
+ obs->bytelen = sz;
80
+ obs->charlen = 0;
48
81
  }
49
- if (sz < 0) {
50
- rb_raise(rb_eArgError, "invalid bind length %d", sz);
82
+ if (RTEST(nchar)) {
83
+ obs->csfrm = SQLCS_NCHAR; /* bind as NCHAR/NVARCHAR2 */
84
+ } else {
85
+ obs->csfrm = SQLCS_IMPLICIT; /* bind as CHAR/VARCHAR2 */
86
+ }
87
+ if (sz == 0) {
88
+ sz = 1; /* to avoid ORA-01459. */
51
89
  }
52
90
  sz += sizeof(sb4);
53
91
  obind->value_sz = sz;
54
92
  obind->alloc_sz = (sz + (sizeof(sb4) - 1)) & ~(sizeof(sb4) - 1);
55
93
  }
56
94
 
57
- static const oci8_bind_class_t bind_char_class = {
58
- {
59
- NULL,
60
- oci8_bind_free,
61
- sizeof(oci8_bind_t)
62
- },
63
- bind_string_get,
64
- bind_string_set,
65
- bind_string_init,
66
- NULL,
67
- NULL,
68
- NULL,
69
- NULL,
70
- SQLT_LVC
71
- };
95
+ static void bind_string_post_bind_hook(oci8_bind_t *obind)
96
+ {
97
+ oci8_bind_string_t *obs = (oci8_bind_string_t *)obind;
72
98
 
73
- static const oci8_bind_class_t bind_nchar_class = {
99
+ if (obs->charlen != 0) {
100
+ chker2(OCIAttrSet(obind->base.hp.ptr, obind->base.type, (void*)&obs->charlen, 0, OCI_ATTR_MAXCHAR_SIZE, oci8_errhp),
101
+ &obind->base);
102
+ }
103
+ chker2(OCIAttrSet(obind->base.hp.ptr, obind->base.type, (void*)&obs->csfrm, 0, OCI_ATTR_CHARSET_FORM, oci8_errhp),
104
+ &obind->base);
105
+ }
106
+
107
+ static const oci8_bind_vtable_t bind_string_vtable = {
74
108
  {
75
109
  NULL,
76
110
  oci8_bind_free,
77
- sizeof(oci8_bind_t)
111
+ sizeof(oci8_bind_string_t)
78
112
  },
79
113
  bind_string_get,
80
114
  bind_string_set,
81
115
  bind_string_init,
82
116
  NULL,
83
117
  NULL,
84
- NULL,
85
- NULL,
86
118
  SQLT_LVC,
87
- SQLCS_NCHAR,
119
+ bind_string_post_bind_hook,
88
120
  };
89
121
 
90
122
  /*
@@ -98,225 +130,63 @@ static VALUE bind_raw_get(oci8_bind_t *obind, void *data, void *null_struct)
98
130
 
99
131
  static void bind_raw_set(oci8_bind_t *obind, void *data, void **null_structp, VALUE val)
100
132
  {
133
+ oci8_bind_string_t *obs = (oci8_bind_string_t *)obind;
101
134
  oci8_vstr_t *vstr = (oci8_vstr_t *)data;
102
135
 
103
136
  StringValue(val);
104
- if (RSTRING_LEN(val) > obind->value_sz - sizeof(vstr->size)) {
105
- rb_raise(rb_eArgError, "too long String to set. (%ld for %d)", RSTRING_LEN(val), obind->value_sz - (sb4)sizeof(vstr->size));
137
+ if (RSTRING_LEN(val) > obs->bytelen) {
138
+ rb_raise(rb_eArgError, "too long String to set. (%ld for %d)", RSTRING_LEN(val), obs->bytelen);
106
139
  }
107
140
  memcpy(vstr->buf, RSTRING_PTR(val), RSTRING_LEN(val));
108
141
  vstr->size = RSTRING_LEN(val);
109
142
  }
110
143
 
111
- static const oci8_bind_class_t bind_raw_class = {
144
+ static const oci8_bind_vtable_t bind_raw_vtable = {
112
145
  {
113
146
  NULL,
114
147
  oci8_bind_free,
115
- sizeof(oci8_bind_t)
148
+ sizeof(oci8_bind_string_t)
116
149
  },
117
150
  bind_raw_get,
118
151
  bind_raw_set,
119
152
  bind_string_init,
120
153
  NULL,
121
154
  NULL,
122
- NULL,
123
- NULL,
124
155
  SQLT_LVB
125
156
  };
126
157
 
127
- #ifdef USE_DYNAMIC_FETCH /* don't use DYNAMIC_FETCH. It doesn't work well... */
128
158
  /*
129
- * bind_long
159
+ * bind_binary_double
130
160
  */
131
- typedef struct {
132
- VALUE obj;
133
- ub4 alen;
134
- char buf[1];
135
- } bind_long_t;
136
- #define bind_long_offset ((size_t)((bind_long_t*)0)->buf)
137
-
138
- static void bind_long_mark(oci8_base_t *base)
139
- {
140
- oci8_bind_t *obind = (oci8_bind_t*)base;
141
- ub4 idx = 0;
142
-
143
- if (obind->valuep == NULL)
144
- return;
145
- do {
146
- bind_long_t *bl = (bind_long_t *)((char*)obind->valuep + obind->alloc_sz * idx);
147
- rb_gc_mark(bl->obj);
148
- } while (++idx < obind->maxar_sz);
149
- }
150
-
151
- static VALUE bind_long_get(oci8_bind_t *obind, void *data, void *null_struct)
152
- {
153
- bind_long_t *bl = (bind_long_t *)data;
154
- return RTEST(bl->obj) ? rb_str_dup(bl->obj) : Qnil;
155
- }
156
-
157
- static void bind_long_set(oci8_bind_t *obind, void *data, void **null_structp, VALUE val)
158
- {
159
- bind_long_t *bl = (bind_long_t *)data;
160
- bl->obj = rb_str_dup(val);
161
- }
162
-
163
- static void bind_long_init(oci8_bind_t *obind, VALUE svc, VALUE val, VALUE length)
164
- {
165
- sb4 sz = 0;
166
-
167
- if (!NIL_P(length)) {
168
- sz = NUM2INT(length);
169
- }
170
- if (sz < 4000) {
171
- sz = 4000;
172
- }
173
- sz += bind_long_offset;
174
- obind->value_sz = INT_MAX;
175
- obind->alloc_sz = (sz + (sizeof(VALUE) - 1)) & ~(sizeof(VALUE) - 1);
176
- }
177
-
178
- static void bind_long_init_elem(oci8_bind_t *obind, VALUE svc)
179
- {
180
- ub4 idx = 0;
181
-
182
- do {
183
- bind_long_t *bl = (bind_long_t *)((char*)obind->valuep + obind->alloc_sz * idx);
184
- bl->obj = Qnil;
185
- } while (++idx < obind->maxar_sz);
186
- }
187
-
188
- static ub1 bind_long_in(oci8_bind_t *obind, ub4 idx, ub1 piece, void **valuepp, ub4 **alenpp, void **indpp)
189
- {
190
- bind_long_t *bl = (bind_long_t *)((char*)obind->valuep + obind->alloc_sz * idx);
191
-
192
- *alenpp = &bl->alen;
193
- *indpp = &obind->u.inds[idx];
194
- if (NIL_P(bl->obj)) {
195
- *valuepp = NULL;
196
- bl->alen = 0;
197
- obind->u.inds[idx] = -1;
198
- } else {
199
- StringValue(bl->obj);
200
- *valuepp = RSTRING_PTR(bl->obj);
201
- bl->alen = RSTRING_LEN(bl->obj);
202
- obind->u.inds[idx] = 0;
203
- }
204
- return OCI_ONE_PIECE;
205
- }
206
-
207
- static void bind_long_out(oci8_bind_t *obind, ub4 idx, ub1 piece, void **valuepp, ub4 **alenpp, void **indpp)
208
- {
209
- bind_long_t *bl = (bind_long_t *)((char*)obind->valuep + obind->alloc_sz * idx);
210
-
211
- switch (piece) {
212
- case OCI_NEXT_PIECE:
213
- case OCI_LAST_PIECE:
214
- if (bl->alen > 0) {
215
- if (!RTEST(bl->obj)) {
216
- bl->obj = rb_str_buf_new(bl->alen);
217
- }
218
- rb_str_buf_cat(bl->obj, bl->buf, bl->alen);
219
- }
220
- break;
221
- default:
222
- /* OCI_FIRST_PIECE is passed at the first call according to manuals.
223
- * But OCI_ONE_PIECE is passed on Oracle 8 and 8i on Windows...
224
- */
225
- bl->obj = Qnil;
226
- }
227
- *valuepp = bl->buf;
228
- *alenpp = &bl->alen;
229
- *indpp = &obind->u.inds[idx];
230
- bl->alen = obind->alloc_sz - bind_long_offset;
231
- obind->u.inds[idx] = 0;
232
- }
233
-
234
- static const oci8_bind_class_t bind_long_class = {
235
- {
236
- bind_long_mark,
237
- oci8_bind_free,
238
- sizeof(oci8_bind_t)
239
- },
240
- bind_long_get,
241
- bind_long_set,
242
- bind_long_init,
243
- bind_long_init_elem,
244
- bind_long_in,
245
- bind_long_out,
246
- NULL,
247
- SQLT_CHR
248
- };
249
-
250
- /*
251
- * bind_long_raw
252
- */
253
- static const oci8_bind_class_t bind_long_raw_class = {
254
- {
255
- bind_long_mark,
256
- oci8_bind_free,
257
- sizeof(oci8_bind_t)
258
- },
259
- bind_long_get,
260
- bind_long_set,
261
- bind_long_init,
262
- bind_long_init_elem,
263
- bind_long_in,
264
- bind_long_out,
265
- NULL,
266
- SQLT_BIN
267
- };
268
- #endif /* USE_DYNAMIC_FETCH */
269
-
270
- /*
271
- * bind_float
272
- */
273
- static VALUE bind_float_get(oci8_bind_t *obind, void *data, void *null_struct)
161
+ static VALUE bind_binary_double_get(oci8_bind_t *obind, void *data, void *null_struct)
274
162
  {
275
163
  return rb_float_new(*(double*)data);
276
164
  }
277
165
 
278
- static void bind_float_set(oci8_bind_t *obind, void *data, void **null_structp, VALUE val)
166
+ static void bind_binary_double_set(oci8_bind_t *obind, void *data, void **null_structp, VALUE val)
279
167
  {
280
168
  /* val is converted to Float if it isn't Float. */
281
169
  *(double*)data = RFLOAT_VALUE(rb_Float(val));
282
170
  }
283
171
 
284
- static void bind_float_init(oci8_bind_t *obind, VALUE svc, VALUE val, VALUE length)
172
+ static void bind_binary_double_init(oci8_bind_t *obind, VALUE svc, VALUE val, VALUE length)
285
173
  {
286
174
  obind->value_sz = sizeof(double);
287
175
  obind->alloc_sz = sizeof(double);
288
176
  }
289
177
 
290
- static const oci8_bind_class_t bind_float_class = {
291
- {
292
- NULL,
293
- oci8_bind_free,
294
- sizeof(oci8_bind_t)
295
- },
296
- bind_float_get,
297
- bind_float_set,
298
- bind_float_init,
299
- NULL,
300
- NULL,
301
- NULL,
302
- NULL,
303
- SQLT_FLT
304
- };
305
-
306
178
  #ifndef SQLT_BDOUBLE
307
179
  #define SQLT_BDOUBLE 22
308
180
  #endif
309
- static const oci8_bind_class_t bind_binary_double_class = {
181
+ static const oci8_bind_vtable_t bind_binary_double_vtable = {
310
182
  {
311
183
  NULL,
312
184
  oci8_bind_free,
313
185
  sizeof(oci8_bind_t)
314
186
  },
315
- bind_float_get,
316
- bind_float_set,
317
- bind_float_init,
318
- NULL,
319
- NULL,
187
+ bind_binary_double_get,
188
+ bind_binary_double_set,
189
+ bind_binary_double_init,
320
190
  NULL,
321
191
  NULL,
322
192
  SQLT_BDOUBLE
@@ -325,7 +195,7 @@ static const oci8_bind_class_t bind_binary_double_class = {
325
195
  static VALUE oci8_bind_get(VALUE self)
326
196
  {
327
197
  oci8_bind_t *obind = DATA_PTR(self);
328
- const oci8_bind_class_t *obc = (const oci8_bind_class_t *)obind->base.klass;
198
+ const oci8_bind_vtable_t *vptr = (const oci8_bind_vtable_t *)obind->base.vptr;
329
199
  ub4 idx = obind->curar_idx;
330
200
  void **null_structp = NULL;
331
201
 
@@ -333,7 +203,7 @@ static VALUE oci8_bind_get(VALUE self)
333
203
  if (obind->u.inds[idx] != 0)
334
204
  return Qnil;
335
205
  }
336
- return obc->get(obind, (void*)((size_t)obind->valuep + obind->alloc_sz * idx), null_structp);
206
+ return vptr->get(obind, (void*)((size_t)obind->valuep + obind->alloc_sz * idx), null_structp);
337
207
  }
338
208
 
339
209
  VALUE oci8_bind_get_data(VALUE self)
@@ -358,7 +228,7 @@ VALUE oci8_bind_get_data(VALUE self)
358
228
  static VALUE oci8_bind_set(VALUE self, VALUE val)
359
229
  {
360
230
  oci8_bind_t *obind = DATA_PTR(self);
361
- const oci8_bind_class_t *obc = (const oci8_bind_class_t *)obind->base.klass;
231
+ const oci8_bind_vtable_t *vptr = (const oci8_bind_vtable_t *)obind->base.vptr;
362
232
  ub4 idx = obind->curar_idx;
363
233
 
364
234
  if (NIL_P(val)) {
@@ -377,7 +247,7 @@ static VALUE oci8_bind_set(VALUE self, VALUE val)
377
247
  null_structp = &obind->u.null_structs[idx];
378
248
  *(OCIInd*)obind->u.null_structs[idx] = 0;
379
249
  }
380
- obc->set(obind, (void*)((size_t)obind->valuep + obind->alloc_sz * idx), null_structp, val);
250
+ vptr->set(obind, (void*)((size_t)obind->valuep + obind->alloc_sz * idx), null_structp, val);
381
251
  }
382
252
  return self;
383
253
  }
@@ -409,7 +279,7 @@ void oci8_bind_set_data(VALUE self, VALUE val)
409
279
  static VALUE oci8_bind_initialize(VALUE self, VALUE svc, VALUE val, VALUE length, VALUE max_array_size)
410
280
  {
411
281
  oci8_bind_t *obind = DATA_PTR(self);
412
- const oci8_bind_class_t *bind_class = (const oci8_bind_class_t *)obind->base.klass;
282
+ const oci8_bind_vtable_t *bind_class = (const oci8_bind_vtable_t *)obind->base.vptr;
413
283
  ub4 cnt = 1;
414
284
 
415
285
  obind->tdo = Qnil;
@@ -471,22 +341,20 @@ void Init_oci8_bind(VALUE klass)
471
341
  {
472
342
  cOCI8BindTypeBase = klass;
473
343
  id_bind_type = rb_intern("bind_type");
344
+ sym_length = ID2SYM(rb_intern("length"));
345
+ sym_length_semantics = ID2SYM(rb_intern("length_semantics"));
346
+ sym_char = ID2SYM(rb_intern("char"));
347
+ sym_nchar = ID2SYM(rb_intern("nchar"));
474
348
 
475
349
  rb_define_method(cOCI8BindTypeBase, "initialize", oci8_bind_initialize, 4);
476
350
  rb_define_method(cOCI8BindTypeBase, "get", oci8_bind_get, 0);
477
351
  rb_define_method(cOCI8BindTypeBase, "set", oci8_bind_set, 1);
478
352
 
479
353
  /* register primitive data types. */
480
- oci8_define_bind_class("CHAR", &bind_char_class);
481
- oci8_define_bind_class("NCHAR", &bind_nchar_class);
482
- oci8_define_bind_class("RAW", &bind_raw_class);
483
- #ifdef USE_DYNAMIC_FETCH
484
- oci8_define_bind_class("Long", &bind_long_class);
485
- oci8_define_bind_class("LongRaw", &bind_long_raw_class);
486
- #endif /* USE_DYNAMIC_FETCH */
487
- oci8_define_bind_class("Float", &bind_float_class);
354
+ oci8_define_bind_class("String", &bind_string_vtable);
355
+ oci8_define_bind_class("RAW", &bind_raw_vtable);
488
356
  if (oracle_client_version >= ORAVER_10_1) {
489
- oci8_define_bind_class("BinaryDouble", &bind_binary_double_class);
357
+ oci8_define_bind_class("BinaryDouble", &bind_binary_double_vtable);
490
358
  }
491
359
  }
492
360