ruby-oci8-master 2.0.7

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 (84) hide show
  1. data/ChangeLog +2321 -0
  2. data/Makefile +88 -0
  3. data/NEWS +303 -0
  4. data/README +76 -0
  5. data/VERSION +1 -0
  6. data/dist-files +83 -0
  7. data/doc/api.en.html +527 -0
  8. data/doc/api.en.rd +554 -0
  9. data/doc/api.ja.html +525 -0
  10. data/doc/api.ja.rd +557 -0
  11. data/doc/manual.css +35 -0
  12. data/ext/oci8/.document +18 -0
  13. data/ext/oci8/MANIFEST +18 -0
  14. data/ext/oci8/apiwrap.c.tmpl +182 -0
  15. data/ext/oci8/apiwrap.h.tmpl +61 -0
  16. data/ext/oci8/apiwrap.rb +91 -0
  17. data/ext/oci8/apiwrap.yml +1455 -0
  18. data/ext/oci8/attr.c +105 -0
  19. data/ext/oci8/bind.c +366 -0
  20. data/ext/oci8/connection_pool.c +199 -0
  21. data/ext/oci8/encoding.c +289 -0
  22. data/ext/oci8/env.c +178 -0
  23. data/ext/oci8/error.c +378 -0
  24. data/ext/oci8/extconf.rb +179 -0
  25. data/ext/oci8/lob.c +805 -0
  26. data/ext/oci8/metadata.c +232 -0
  27. data/ext/oci8/object.c +727 -0
  28. data/ext/oci8/oci8.c +1156 -0
  29. data/ext/oci8/oci8.h +574 -0
  30. data/ext/oci8/oci8lib.c +527 -0
  31. data/ext/oci8/ocidatetime.c +484 -0
  32. data/ext/oci8/ocihandle.c +751 -0
  33. data/ext/oci8/ocinumber.c +1612 -0
  34. data/ext/oci8/oraconf.rb +1119 -0
  35. data/ext/oci8/oradate.c +611 -0
  36. data/ext/oci8/oranumber_util.c +352 -0
  37. data/ext/oci8/oranumber_util.h +24 -0
  38. data/ext/oci8/post-config.rb +5 -0
  39. data/ext/oci8/stmt.c +673 -0
  40. data/ext/oci8/thread_util.c +85 -0
  41. data/ext/oci8/thread_util.h +30 -0
  42. data/ext/oci8/win32.c +137 -0
  43. data/lib/.document +1 -0
  44. data/lib/dbd/OCI8.rb +591 -0
  45. data/lib/oci8.rb.in +94 -0
  46. data/lib/oci8/.document +8 -0
  47. data/lib/oci8/bindtype.rb +349 -0
  48. data/lib/oci8/compat.rb +113 -0
  49. data/lib/oci8/connection_pool.rb +99 -0
  50. data/lib/oci8/datetime.rb +611 -0
  51. data/lib/oci8/encoding-init.rb +74 -0
  52. data/lib/oci8/encoding.yml +537 -0
  53. data/lib/oci8/metadata.rb +2132 -0
  54. data/lib/oci8/object.rb +581 -0
  55. data/lib/oci8/oci8.rb +721 -0
  56. data/lib/oci8/ocihandle.rb +425 -0
  57. data/lib/oci8/oracle_version.rb +144 -0
  58. data/lib/oci8/properties.rb +73 -0
  59. data/metaconfig +142 -0
  60. data/pre-distclean.rb +7 -0
  61. data/ruby-oci8.gemspec +63 -0
  62. data/setup.rb +1331 -0
  63. data/test/README +4 -0
  64. data/test/config.rb +122 -0
  65. data/test/test_all.rb +51 -0
  66. data/test/test_appinfo.rb +63 -0
  67. data/test/test_array_dml.rb +333 -0
  68. data/test/test_bind_raw.rb +46 -0
  69. data/test/test_bind_time.rb +178 -0
  70. data/test/test_break.rb +96 -0
  71. data/test/test_clob.rb +82 -0
  72. data/test/test_connstr.rb +81 -0
  73. data/test/test_datetime.rb +582 -0
  74. data/test/test_dbi.rb +366 -0
  75. data/test/test_dbi_clob.rb +53 -0
  76. data/test/test_encoding.rb +100 -0
  77. data/test/test_error.rb +88 -0
  78. data/test/test_metadata.rb +1399 -0
  79. data/test/test_oci8.rb +434 -0
  80. data/test/test_oracle_version.rb +70 -0
  81. data/test/test_oradate.rb +256 -0
  82. data/test/test_oranumber.rb +746 -0
  83. data/test/test_rowid.rb +33 -0
  84. metadata +137 -0
@@ -0,0 +1,352 @@
1
+ /* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
2
+ #include <stdio.h>
3
+ #include <string.h>
4
+ #include "oranumber_util.h"
5
+
6
+ int oranumber_to_str(const OCINumber *on, char *buf, int buflen)
7
+ {
8
+ signed char exponent;
9
+ signed char mantissa[21]; /* terminated by a negative number */
10
+ int datalen = on->OCINumberPart[0];
11
+ int len = 0;
12
+ int idx;
13
+ int n;
14
+ #define PUTC(chr) do { \
15
+ if (len < buflen) { \
16
+ buf[len++] = (chr); \
17
+ } else { \
18
+ return ORANUMBER_TOO_SHORT_BUFFER; \
19
+ } \
20
+ } while(0)
21
+ #define PUTEND() do { \
22
+ if (len < buflen) { \
23
+ buf[len] = '\0'; \
24
+ } else { \
25
+ return ORANUMBER_TOO_SHORT_BUFFER; \
26
+ } \
27
+ } while(0)
28
+
29
+ if (datalen == 0) {
30
+ /* too short */
31
+ return -1;
32
+ }
33
+ if (datalen == 1) {
34
+ if (on->OCINumberPart[1] == 0x80) {
35
+ /* zero */
36
+ PUTC('0');
37
+ PUTEND();
38
+ return 1;
39
+ }
40
+ if (on->OCINumberPart[1] == 0) {
41
+ /* negative infinity */
42
+ PUTC('-');
43
+ PUTC('~');
44
+ PUTEND();
45
+ return 2;
46
+ }
47
+ /* unexpected format */
48
+ return -1;
49
+ }
50
+ if (datalen == 2) {
51
+ if (on->OCINumberPart[1] == 255 && on->OCINumberPart[2] == 101) {
52
+ /* positive infinity */
53
+ PUTC('~');
54
+ PUTEND();
55
+ return 1;
56
+ }
57
+ }
58
+ if (datalen > 21) {
59
+ /* too long */
60
+ return -1;
61
+ }
62
+ /* normalize exponent and mantissa */
63
+ if (on->OCINumberPart[1] >= 128) {
64
+ /* positive number */
65
+ exponent = on->OCINumberPart[1] - 193;
66
+ for (idx = 0; idx < on->OCINumberPart[0] - 1; idx++) {
67
+ mantissa[idx] = on->OCINumberPart[idx + 2] - 1;
68
+ }
69
+ mantissa[idx] = -1;
70
+ } else {
71
+ /* negative number */
72
+ exponent = 62 - on->OCINumberPart[1];
73
+ for (idx = 0; idx < on->OCINumberPart[0] - 1; idx++) {
74
+ mantissa[idx] = 101 - on->OCINumberPart[idx + 2];
75
+ }
76
+ mantissa[idx] = -1;
77
+ PUTC('-');
78
+ }
79
+ /* convert exponent and mantissa to human readable number */
80
+ idx = 0;
81
+ if (exponent-- >= 0) {
82
+ /* integer part */
83
+ n = mantissa[idx++];
84
+ if (n / 10 != 0) {
85
+ PUTC(n / 10 + '0');
86
+ }
87
+ PUTC(n % 10 + '0');
88
+ while (exponent-- >= 0) {
89
+ n = mantissa[idx++];
90
+ if (n < 0) {
91
+ do {
92
+ PUTC('0');
93
+ PUTC('0');
94
+ } while (exponent-- >= 0);
95
+ PUTEND();
96
+ return len;
97
+ }
98
+ PUTC(n / 10 + '0');
99
+ PUTC(n % 10 + '0');
100
+ }
101
+ if (mantissa[idx] < 0) {
102
+ PUTEND();
103
+ return len;
104
+ }
105
+ } else {
106
+ PUTC('0');
107
+ }
108
+ PUTC('.');
109
+ /* fractional number part */
110
+ while (++exponent < -1) {
111
+ PUTC('0');
112
+ PUTC('0');
113
+ }
114
+ while ((n = mantissa[idx++]) >= 0) {
115
+ PUTC(n / 10 + '0');
116
+ PUTC(n % 10 + '0');
117
+ }
118
+ if (buf[len - 1] == '0') {
119
+ len--;
120
+ }
121
+ PUTEND();
122
+ return len;
123
+ }
124
+
125
+ int oranumber_from_str(OCINumber *on, const char *buf, int buflen)
126
+ {
127
+ const char *end;
128
+ int is_positive = 1;
129
+ char mantissa[41];
130
+ int dec_point;
131
+ long exponent = 0;
132
+ int idx = 0;
133
+ int i;
134
+
135
+ if (buflen < 0) {
136
+ end = buf + strlen(buf);
137
+ } else {
138
+ end = buf + buflen;
139
+ }
140
+
141
+ /* skip leading spaces */
142
+ while (buf < end && *buf == ' ') {
143
+ buf++;
144
+ }
145
+ if (buf == end) {
146
+ return ORANUMBER_INVALID_NUMBER;
147
+ }
148
+ /* read a sign mark */
149
+ if (*buf == '+') {
150
+ buf++;
151
+ } else if (*buf == '-') {
152
+ buf++;
153
+ is_positive = 0;
154
+ }
155
+ if (*buf == '~') {
156
+ buf ++;
157
+ /* skip trailing spaces */
158
+ while (buf < end && *buf == ' ') {
159
+ buf++;
160
+ }
161
+ if (buf != end) {
162
+ return ORANUMBER_INVALID_NUMBER;
163
+ }
164
+ if (is_positive) {
165
+ /* positive infinity */
166
+ on->OCINumberPart[0] = 2;
167
+ on->OCINumberPart[1] = 255;
168
+ on->OCINumberPart[2] = 101;
169
+ } else {
170
+ /* negative infinity */
171
+ on->OCINumberPart[0] = 1;
172
+ on->OCINumberPart[1] = 0;
173
+ }
174
+ return ORANUMBER_SUCCESS;
175
+ }
176
+
177
+ /* next should be number or a dot */
178
+ if ((*buf < '0' || '9' < *buf) && *buf != '.') {
179
+ return ORANUMBER_INVALID_NUMBER;
180
+ }
181
+ /* skip leading zeros */
182
+ while (buf < end) {
183
+ if (*buf == '0') {
184
+ buf++;
185
+ } else {
186
+ break;
187
+ }
188
+ }
189
+ /* read integer part */
190
+ while (buf < end) {
191
+ if ('0' <= *buf && *buf <= '9') {
192
+ if (idx < 41) {
193
+ mantissa[idx] = *buf - '0';
194
+ }
195
+ idx++;
196
+ } else if (*buf == '.' || *buf == 'E' || *buf == 'e' || *buf == ' ') {
197
+ break;
198
+ } else {
199
+ return ORANUMBER_INVALID_NUMBER;
200
+ }
201
+ buf++;
202
+ }
203
+ dec_point = idx;
204
+ /* read fractional part */
205
+ if (buf < end && *buf == '.') {
206
+ buf++;
207
+ if (idx == 0) {
208
+ /* skip leading zeros */
209
+ while (buf < end) {
210
+ if (*buf == '0') {
211
+ dec_point--;
212
+ buf++;
213
+ } else {
214
+ break;
215
+ }
216
+ }
217
+ }
218
+ while (buf < end) {
219
+ if ('0' <= *buf && *buf <= '9') {
220
+ if (idx < 41) {
221
+ mantissa[idx++] = *buf - '0';
222
+ }
223
+ } else if (*buf == 'E' || *buf == 'e' || *buf == ' ') {
224
+ break;
225
+ } else {
226
+ return ORANUMBER_INVALID_NUMBER;
227
+ }
228
+ buf++;
229
+ }
230
+ }
231
+ /* read exponent part */
232
+ if (buf < end && (*buf == 'E' || *buf == 'e')) {
233
+ int negate = 0;
234
+ buf++;
235
+ if (buf < end) {
236
+ if (*buf == '+') {
237
+ buf++;
238
+ } else if (*buf == '-') {
239
+ buf++;
240
+ negate = 1;
241
+ }
242
+ }
243
+ while (buf < end) {
244
+ if ('0' <= *buf && *buf <= '9') {
245
+ exponent *= 10;
246
+ exponent += *buf - '0';
247
+ } else if (*buf == ' ') {
248
+ break;
249
+ } else {
250
+ return ORANUMBER_INVALID_NUMBER;
251
+ }
252
+ buf++;
253
+ }
254
+ if (negate) {
255
+ exponent = -exponent;
256
+ }
257
+ }
258
+ /* skip trailing spaces */
259
+ while (buf < end && *buf == ' ') {
260
+ buf++;
261
+ }
262
+ /* final format check */
263
+ if (buf != end) {
264
+ return ORANUMBER_INVALID_NUMBER;
265
+ }
266
+ /* determine exponent */
267
+ exponent += dec_point - 1;
268
+ if (exponent % 2 == 0) {
269
+ memmove(mantissa + 1, mantissa, 40);
270
+ mantissa[0] = 0;
271
+ idx++;
272
+ }
273
+ /* round if needed */
274
+ if (idx > 40) {
275
+ idx = 40;
276
+ if (mantissa[40] >= 5) {
277
+ /* round up */
278
+ for (i = 39; i >= 0; i--) {
279
+ mantissa[i]++;
280
+ if (mantissa[i] == 10) {
281
+ mantissa[i] = 0;
282
+ } else {
283
+ break;
284
+ }
285
+ }
286
+ if (i == -1) {
287
+ /* all figures are rounded up. */
288
+ mantissa[0] = 0;
289
+ mantissa[1] = 1;
290
+ idx = 2;
291
+ exponent++;
292
+ }
293
+ }
294
+ }
295
+ /* shrink mantissa scale */
296
+ while (idx > 0 && mantissa[idx - 1] == 0) {
297
+ idx--;
298
+ }
299
+ /* check zero or underflow */
300
+ if (idx == 0 || exponent < -130) {
301
+ on->OCINumberPart[0] = 1;
302
+ on->OCINumberPart[1] = 0x80;
303
+ return ORANUMBER_SUCCESS;
304
+ }
305
+ /* check overflow */
306
+ if (exponent > 125) {
307
+ return ORANUMBER_NUMERIC_OVERFLOW;
308
+ }
309
+ /* change the base number from 10 to 100 */
310
+ if (idx % 2 == 1) {
311
+ mantissa[idx++] = 0;
312
+ }
313
+ idx /= 2;
314
+ for (i = 0; i < idx; i++) {
315
+ mantissa[i] = mantissa[i * 2] * 10 + mantissa[i * 2 + 1];
316
+ }
317
+ /* add negative value's terminator */
318
+ if (!is_positive && idx < 20) {
319
+ mantissa[idx++] = -1;
320
+ }
321
+ /* construct OCINumber */
322
+ on->OCINumberPart[0] = 1 + idx;
323
+ if (is_positive) {
324
+ on->OCINumberPart[1] = (exponent >> 1) + 193;
325
+ for (i = 0; i < idx; i++) {
326
+ on->OCINumberPart[i + 2] = mantissa[i] + 1;
327
+ }
328
+ } else {
329
+ on->OCINumberPart[1] = 62 - (exponent >> 1);
330
+ for (i = 0; i < idx; i++) {
331
+ on->OCINumberPart[i + 2] = 101 - mantissa[i];
332
+ }
333
+ }
334
+ return ORANUMBER_SUCCESS;
335
+ }
336
+
337
+ int oranumber_dump(const OCINumber *on, char *buf)
338
+ {
339
+ int idx;
340
+ int len = on->OCINumberPart[0];
341
+ int offset;
342
+
343
+ offset = sprintf(buf, "Typ=2 Len=%u: ", len);
344
+ if (len > 21) {
345
+ len = 21;
346
+ }
347
+ for (idx = 1; idx <= len; idx++) {
348
+ offset += sprintf(buf + offset, "%u,", (ub4)on->OCINumberPart[idx]);
349
+ }
350
+ buf[--offset] = '\0';
351
+ return offset;
352
+ }
@@ -0,0 +1,24 @@
1
+ /* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * oranumber_util.h - part of ruby-oci8
4
+ *
5
+ * Copyright (C) 2010 KUBO Takehiro <kubo@jiubao.org>
6
+ */
7
+ #ifndef ORANUMBER_UTIL_H
8
+ #define ORANUMBER_UTIL_H 1
9
+ #include <orl.h>
10
+
11
+ #define ORANUMBER_INVALID_INTERNAL_FORMAT -1
12
+ #define ORANUMBER_TOO_SHORT_BUFFER -2
13
+
14
+ #define ORANUMBER_SUCCESS 0
15
+ #define ORANUMBER_INVALID_NUMBER 1722
16
+ #define ORANUMBER_NUMERIC_OVERFLOW 1426
17
+
18
+ int oranumber_to_str(const OCINumber *on, char *buf, int buflen);
19
+ int oranumber_from_str(OCINumber *on, const char *buf, int buflen);
20
+
21
+ #define ORANUMBER_DUMP_BUF_SIZ 99
22
+ int oranumber_dump(const OCINumber *on, char *buf);
23
+
24
+ #endif
@@ -0,0 +1,5 @@
1
+ File.foreach("#{curr_objdir}/extconf.h") do |line|
2
+ if /^#define OCI8_CLIENT_VERSION "(...)"/ =~ line
3
+ set_config('oracle_version', $1)
4
+ end
5
+ end
@@ -0,0 +1,673 @@
1
+ /* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * stmt.c - part of ruby-oci8
4
+ * implement the methods of OCIStmt.
5
+ *
6
+ * Copyright (C) 2002-2010 KUBO Takehiro <kubo@jiubao.org>
7
+ *
8
+ */
9
+ #include "oci8.h"
10
+
11
+ static VALUE oci8_sym_select_stmt;
12
+ static VALUE oci8_sym_update_stmt;
13
+ static VALUE oci8_sym_delete_stmt;
14
+ static VALUE oci8_sym_insert_stmt;
15
+ static VALUE oci8_sym_create_stmt;
16
+ static VALUE oci8_sym_drop_stmt;
17
+ static VALUE oci8_sym_alter_stmt;
18
+ static VALUE oci8_sym_begin_stmt;
19
+ static VALUE oci8_sym_declare_stmt;
20
+ static ID id_at_column_metadata;
21
+ static ID id_at_actual_array_size;
22
+ static ID id_at_max_array_size;
23
+ static ID id_each_value;
24
+ static ID id_at_names;
25
+ static ID id_empty_p;
26
+ static ID id_at_con;
27
+ static ID id_clear;
28
+
29
+ VALUE cOCIStmt;
30
+
31
+ #define TO_STMT(obj) ((oci8_stmt_t *)oci8_get_handle((obj), cOCIStmt))
32
+
33
+ typedef struct {
34
+ oci8_base_t base;
35
+ VALUE svc;
36
+ VALUE binds;
37
+ VALUE defns;
38
+ } oci8_stmt_t;
39
+
40
+ static void oci8_stmt_mark(oci8_base_t *base)
41
+ {
42
+ oci8_stmt_t *stmt = (oci8_stmt_t *)base;
43
+ rb_gc_mark(stmt->svc);
44
+ rb_gc_mark(stmt->binds);
45
+ rb_gc_mark(stmt->defns);
46
+ }
47
+
48
+ static void oci8_stmt_free(oci8_base_t *base)
49
+ {
50
+ oci8_stmt_t *stmt = (oci8_stmt_t *)base;
51
+ stmt->svc = Qnil;
52
+ stmt->binds = Qnil;
53
+ stmt->defns = Qnil;
54
+ }
55
+
56
+ static oci8_base_vtable_t oci8_stmt_vtable = {
57
+ oci8_stmt_mark,
58
+ oci8_stmt_free,
59
+ sizeof(oci8_stmt_t),
60
+ };
61
+
62
+ static VALUE oci8_stmt_initialize(int argc, VALUE *argv, VALUE self)
63
+ {
64
+ oci8_stmt_t *stmt = DATA_PTR(self);
65
+ VALUE svc;
66
+ VALUE sql;
67
+ sword rv;
68
+
69
+ rb_scan_args(argc, argv, "11", &svc, &sql);
70
+
71
+ oci8_check_pid_consistency(oci8_get_svcctx(svc));
72
+ if (argc > 1)
73
+ OCI8SafeStringValue(sql);
74
+
75
+ rv = OCIHandleAlloc(oci8_envhp, &stmt->base.hp.ptr, OCI_HTYPE_STMT, 0, NULL);
76
+ if (rv != OCI_SUCCESS)
77
+ oci8_env_raise(oci8_envhp, rv);
78
+ stmt->base.type = OCI_HTYPE_STMT;
79
+ stmt->svc = svc;
80
+ stmt->binds = rb_hash_new();
81
+ stmt->defns = rb_ary_new();
82
+ rb_ivar_set(stmt->base.self, id_at_column_metadata, rb_ary_new());
83
+ rb_ivar_set(stmt->base.self, id_at_names, Qnil);
84
+ rb_ivar_set(stmt->base.self, id_at_con, svc);
85
+ rb_ivar_set(stmt->base.self, id_at_max_array_size, Qnil);
86
+
87
+ if (argc > 1) {
88
+ rv = OCIStmtPrepare(stmt->base.hp.stmt, oci8_errhp, RSTRING_ORATEXT(sql), RSTRING_LEN(sql), OCI_NTV_SYNTAX, OCI_DEFAULT);
89
+ if (IS_OCI_ERROR(rv)) {
90
+ chker3(rv, &stmt->base, stmt->base.hp.stmt);
91
+ }
92
+ }
93
+ oci8_link_to_parent((oci8_base_t*)stmt, (oci8_base_t*)DATA_PTR(svc));
94
+ return Qnil;
95
+ }
96
+
97
+ static VALUE oci8_define_by_pos(VALUE self, VALUE vposition, VALUE vbindobj)
98
+ {
99
+ oci8_stmt_t *stmt = TO_STMT(self);
100
+ ub4 position;
101
+ oci8_bind_t *obind;
102
+ const oci8_bind_vtable_t *vptr;
103
+ sword status;
104
+
105
+ position = NUM2INT(vposition); /* 1 */
106
+ obind = oci8_get_bind(vbindobj); /* 2 */
107
+ if (obind->base.hp.dfn != NULL) {
108
+ oci8_base_free(&obind->base); /* TODO: OK? */
109
+ }
110
+ vptr = (const oci8_bind_vtable_t *)obind->base.vptr;
111
+ status = OCIDefineByPos(stmt->base.hp.stmt, &obind->base.hp.dfn, oci8_errhp, position, obind->valuep, obind->value_sz, vptr->dty, NIL_P(obind->tdo) ? obind->u.inds : NULL, NULL, 0, OCI_DEFAULT);
112
+ if (status != OCI_SUCCESS) {
113
+ chker3(status, &stmt->base, stmt->base.hp.ptr);
114
+ }
115
+ obind->base.type = OCI_HTYPE_DEFINE;
116
+ /* link to the parent as soon as possible to preserve deallocation order. */
117
+ oci8_unlink_from_parent((oci8_base_t*)obind);
118
+ oci8_link_to_parent((oci8_base_t*)obind, (oci8_base_t*)stmt);
119
+
120
+ if (NIL_P(obind->tdo) && obind->maxar_sz > 0) {
121
+ chker2(OCIDefineArrayOfStruct(obind->base.hp.dfn, oci8_errhp, obind->alloc_sz, sizeof(sb2), 0, 0), &stmt->base);
122
+ }
123
+ if (vptr->post_bind_hook != NULL) {
124
+ vptr->post_bind_hook(obind);
125
+ }
126
+ if (position - 1 < RARRAY_LEN(stmt->defns)) {
127
+ VALUE old_value = RARRAY_PTR(stmt->defns)[position - 1];
128
+ if (!NIL_P(old_value)) {
129
+ oci8_base_free((oci8_base_t*)oci8_get_bind(old_value));
130
+ }
131
+ }
132
+ rb_ary_store(stmt->defns, position - 1, obind->base.self);
133
+ return obind->base.self;
134
+ }
135
+
136
+ static VALUE oci8_bind(VALUE self, VALUE vplaceholder, VALUE vbindobj)
137
+ {
138
+ oci8_stmt_t *stmt = TO_STMT(self);
139
+ char *placeholder_ptr = (char*)-1; /* initialize as an invalid value */
140
+ ub4 placeholder_len = 0;
141
+ ub4 position = 0;
142
+ oci8_bind_t *obind;
143
+ const oci8_bind_vtable_t *vptr;
144
+ sword status;
145
+ VALUE old_value;
146
+ void *indp;
147
+ ub4 *curelep;
148
+
149
+ if (NIL_P(vplaceholder)) { /* 1 */
150
+ placeholder_ptr = NULL;
151
+ placeholder_len = 0;
152
+ } else if (SYMBOL_P(vplaceholder)) {
153
+ const char *symname = rb_id2name(SYM2ID(vplaceholder));
154
+ size_t len = strlen(symname);
155
+ placeholder_ptr = ALLOCA_N(char, len + 1);
156
+ placeholder_len = len + 1;
157
+ placeholder_ptr[0] = ':';
158
+ memcpy(placeholder_ptr + 1, symname, len);
159
+ } else if (FIXNUM_P(vplaceholder)) {
160
+ position = NUM2INT(vplaceholder);
161
+ } else {
162
+ OCI8StringValue(vplaceholder);
163
+ placeholder_ptr = RSTRING_PTR(vplaceholder);
164
+ placeholder_len = RSTRING_LEN(vplaceholder);
165
+ }
166
+ obind = oci8_get_bind(vbindobj); /* 2 */
167
+ if (obind->base.hp.bnd != NULL) {
168
+ oci8_base_free(&obind->base); /* TODO: OK? */
169
+ }
170
+ vptr = (const oci8_bind_vtable_t *)obind->base.vptr;
171
+
172
+ indp = NIL_P(obind->tdo) ? obind->u.inds : NULL;
173
+ if (obind->maxar_sz == 0) {
174
+ curelep = NULL;
175
+ } else {
176
+ curelep = &obind->curar_sz;
177
+ }
178
+ if (placeholder_ptr == (char*)-1) {
179
+ status = OCIBindByPos(stmt->base.hp.stmt, &obind->base.hp.bnd, oci8_errhp, position, obind->valuep, obind->value_sz, vptr->dty, indp, NULL, 0, 0, 0, OCI_DEFAULT);
180
+ } else {
181
+ status = OCIBindByName(stmt->base.hp.stmt, &obind->base.hp.bnd, oci8_errhp, TO_ORATEXT(placeholder_ptr), placeholder_len, obind->valuep, obind->value_sz, vptr->dty, indp, NULL, 0, 0, 0, OCI_DEFAULT);
182
+ }
183
+ if (status != OCI_SUCCESS) {
184
+ chker3(status, &stmt->base, stmt->base.hp.stmt);
185
+ }
186
+ obind->base.type = OCI_HTYPE_BIND;
187
+ /* link to the parent as soon as possible to preserve deallocation order. */
188
+ oci8_unlink_from_parent((oci8_base_t*)obind);
189
+ oci8_link_to_parent((oci8_base_t*)obind, (oci8_base_t*)stmt);
190
+
191
+ if (NIL_P(obind->tdo) && obind->maxar_sz > 0) {
192
+ chker2(OCIBindArrayOfStruct(obind->base.hp.bnd, oci8_errhp, obind->alloc_sz, sizeof(sb2), 0, 0),
193
+ &stmt->base);
194
+ }
195
+ if (vptr->post_bind_hook != NULL) {
196
+ vptr->post_bind_hook(obind);
197
+ }
198
+ old_value = rb_hash_aref(stmt->binds, vplaceholder);
199
+ if (!NIL_P(old_value)) {
200
+ oci8_base_free((oci8_base_t*)oci8_get_bind(old_value));
201
+ }
202
+ rb_hash_aset(stmt->binds, vplaceholder, obind->base.self);
203
+ return obind->base.self;
204
+ }
205
+
206
+ static sword oci8_call_stmt_execute(oci8_svcctx_t *svcctx, oci8_stmt_t *stmt, ub4 iters, ub4 mode)
207
+ {
208
+ sword rv;
209
+
210
+ rv = OCIStmtExecute_nb(svcctx, svcctx->base.hp.svc, stmt->base.hp.stmt, oci8_errhp, iters, 0, NULL, NULL, mode);
211
+ if (rv == OCI_ERROR) {
212
+ if (oci8_get_error_code(oci8_errhp) == 1000) {
213
+ /* run GC to close unreferred cursors
214
+ * when ORA-01000 (maximum open cursors exceeded).
215
+ */
216
+ rb_gc();
217
+ rv = OCIStmtExecute_nb(svcctx, svcctx->base.hp.svc, stmt->base.hp.stmt, oci8_errhp, iters, 0, NULL, NULL, mode);
218
+ }
219
+ }
220
+ return rv;
221
+ }
222
+
223
+ static VALUE oci8_stmt_execute(VALUE self, VALUE iteration_count)
224
+ {
225
+ oci8_stmt_t *stmt = TO_STMT(self);
226
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(stmt->svc);
227
+ ub4 iters;
228
+ ub4 mode;
229
+
230
+ if (oci8_get_ub2_attr(&stmt->base, OCI_ATTR_STMT_TYPE, stmt->base.hp.stmt) == INT2FIX(OCI_STMT_SELECT)) {
231
+ iters = 0;
232
+ mode = OCI_DEFAULT;
233
+ } else {
234
+ if(!NIL_P(iteration_count))
235
+ iters = NUM2INT(iteration_count);
236
+ else
237
+ iters = 1;
238
+ mode = svcctx->is_autocommit ? OCI_COMMIT_ON_SUCCESS : OCI_DEFAULT;
239
+ }
240
+ chker3(oci8_call_stmt_execute(svcctx, stmt, iters, mode),
241
+ &stmt->base, stmt->base.hp.stmt);
242
+ return self;
243
+ }
244
+
245
+ static VALUE each_value(VALUE obj)
246
+ {
247
+ return rb_funcall(obj, id_each_value, 0);
248
+ }
249
+
250
+ static VALUE clear_binds_iterator_proc(VALUE val, VALUE arg)
251
+ {
252
+ if(!NIL_P(val)) {
253
+ oci8_base_free((oci8_base_t*)oci8_get_bind(val));
254
+ }
255
+ return Qnil;
256
+ }
257
+
258
+ static VALUE oci8_stmt_clear_binds(VALUE self)
259
+ {
260
+ oci8_stmt_t *stmt = TO_STMT(self);
261
+
262
+ if(!RTEST(rb_funcall(stmt->binds, id_empty_p, 0)))
263
+ {
264
+ rb_iterate(each_value, stmt->binds, clear_binds_iterator_proc, Qnil);
265
+ rb_funcall(stmt->binds,id_clear,0);
266
+ }
267
+
268
+ return self;
269
+ }
270
+
271
+ static VALUE oci8_stmt_do_fetch(oci8_stmt_t *stmt, oci8_svcctx_t *svcctx)
272
+ {
273
+ VALUE ary;
274
+ sword rv;
275
+ long idx;
276
+ oci8_bind_t *obind;
277
+ const oci8_bind_vtable_t *vptr;
278
+
279
+ if (stmt->base.children != NULL) {
280
+ obind = (oci8_bind_t *)stmt->base.children;
281
+ do {
282
+ if (obind->base.type == OCI_HTYPE_DEFINE) {
283
+ vptr = (const oci8_bind_vtable_t *)obind->base.vptr;
284
+ if (vptr->pre_fetch_hook != NULL) {
285
+ vptr->pre_fetch_hook(obind, stmt->svc);
286
+ }
287
+ }
288
+ obind = (oci8_bind_t *)obind->base.next;
289
+ } while (obind != (oci8_bind_t*)stmt->base.children);
290
+ }
291
+ rv = OCIStmtFetch_nb(svcctx, stmt->base.hp.stmt, oci8_errhp, 1, OCI_FETCH_NEXT, OCI_DEFAULT);
292
+ if (rv == OCI_NO_DATA) {
293
+ return Qnil;
294
+ }
295
+ chker3(rv, &svcctx->base, stmt->base.hp.stmt);
296
+ ary = rb_ary_new2(RARRAY_LEN(stmt->defns));
297
+ for (idx = 0; idx < RARRAY_LEN(stmt->defns); idx++) {
298
+ rb_ary_store(ary, idx, oci8_bind_get_data(RARRAY_PTR(stmt->defns)[idx]));
299
+ }
300
+ return ary;
301
+ }
302
+
303
+ /*
304
+ * Gets fetched data as array. This is available for select
305
+ * statement only.
306
+ *
307
+ * example:
308
+ * conn = OCI8.new('scott', 'tiger')
309
+ * cursor = conn.exec('SELECT * FROM emp')
310
+ * while r = cursor.fetch()
311
+ * puts r.join(',')
312
+ * end
313
+ * cursor.close
314
+ * conn.logoff
315
+ */
316
+ static VALUE oci8_stmt_fetch(VALUE self)
317
+ {
318
+ oci8_stmt_t *stmt = TO_STMT(self);
319
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(stmt->svc);
320
+
321
+ if (rb_block_given_p()) {
322
+ for (;;) {
323
+ VALUE rs = oci8_stmt_do_fetch(stmt, svcctx);
324
+ if (NIL_P(rs))
325
+ return self; /* NEED TO CHECK 0.1 behavior. */
326
+ rb_yield(rs);
327
+ }
328
+ } else {
329
+ return oci8_stmt_do_fetch(stmt, svcctx);
330
+ }
331
+ }
332
+
333
+ static VALUE oci8_stmt_get_param(VALUE self, VALUE pos)
334
+ {
335
+ oci8_stmt_t *stmt = TO_STMT(self);
336
+ OCIParam *parmhp = NULL;
337
+ sword rv;
338
+
339
+ Check_Type(pos, T_FIXNUM); /* 1 */
340
+ rv = OCIParamGet(stmt->base.hp.stmt, OCI_HTYPE_STMT, oci8_errhp, (dvoid *)&parmhp, FIX2INT(pos));
341
+ if (rv != OCI_SUCCESS) {
342
+ chker3(rv, &stmt->base, stmt->base.hp.stmt);
343
+ }
344
+ return oci8_metadata_create(parmhp, stmt->svc, self);
345
+ }
346
+
347
+ /*
348
+ * gets the type of SQL statement as follows.
349
+ * * OCI8::STMT_SELECT
350
+ * * OCI8::STMT_UPDATE
351
+ * * OCI8::STMT_DELETE
352
+ * * OCI8::STMT_INSERT
353
+ * * OCI8::STMT_CREATE
354
+ * * OCI8::STMT_DROP
355
+ * * OCI8::STMT_ALTER
356
+ * * OCI8::STMT_BEGIN (PL/SQL block which starts with a BEGIN keyword)
357
+ * * OCI8::STMT_DECLARE (PL/SQL block which starts with a DECLARE keyword)
358
+ * * Other Fixnum value undocumented in Oracle manuals.
359
+ *
360
+ * <em>Changes between ruby-oci8 1.0 and 2.0.</em>
361
+ *
362
+ * [ruby-oci8 2.0] OCI8::STMT_* are Symbols. (:select_stmt, :update_stmt, etc.)
363
+ * [ruby-oci8 1.0] OCI8::STMT_* are Fixnums. (1, 2, 3, etc.)
364
+ */
365
+ static VALUE oci8_stmt_get_stmt_type(VALUE self)
366
+ {
367
+ oci8_base_t *base = oci8_get_handle(self, cOCIStmt);
368
+ VALUE stmt_type = oci8_get_ub2_attr(base, OCI_ATTR_STMT_TYPE, base->hp.stmt);
369
+ switch (FIX2INT(stmt_type)) {
370
+ case OCI_STMT_SELECT:
371
+ return oci8_sym_select_stmt;
372
+ case OCI_STMT_UPDATE:
373
+ return oci8_sym_update_stmt;
374
+ case OCI_STMT_DELETE:
375
+ return oci8_sym_delete_stmt;
376
+ case OCI_STMT_INSERT:
377
+ return oci8_sym_insert_stmt;
378
+ case OCI_STMT_CREATE:
379
+ return oci8_sym_create_stmt;
380
+ case OCI_STMT_DROP:
381
+ return oci8_sym_drop_stmt;
382
+ case OCI_STMT_ALTER:
383
+ return oci8_sym_alter_stmt;
384
+ case OCI_STMT_BEGIN:
385
+ return oci8_sym_begin_stmt;
386
+ case OCI_STMT_DECLARE:
387
+ return oci8_sym_declare_stmt;
388
+ default:
389
+ return stmt_type;
390
+ }
391
+ }
392
+
393
+ /*
394
+ * Returns the number of processed rows.
395
+ */
396
+ static VALUE oci8_stmt_get_row_count(VALUE self)
397
+ {
398
+ oci8_base_t *base = oci8_get_handle(self, cOCIStmt);
399
+ return oci8_get_ub4_attr(base, OCI_ATTR_ROW_COUNT, base->hp.stmt);
400
+ }
401
+
402
+ /*
403
+ * Get the rowid of the last inserted/updated/deleted row.
404
+ * This cannot be used for select statements.
405
+ *
406
+ * example:
407
+ * cursor = conn.parse('INSERT INTO foo_table values(:1, :2)', 1, 2)
408
+ * cursor.exec
409
+ * cursor.rowid # => the inserted row's rowid
410
+ *
411
+ * <em>Changes between ruby-oci8 1.0.3 and 1.0.4.</em>
412
+ *
413
+ * [ruby-oci8 1.0.4 or upper] The return value is a String.
414
+ * [ruby-oci8 1.0.3 or lower] It returns an OCIRowid object.
415
+ */
416
+ static VALUE oci8_stmt_get_rowid(VALUE self)
417
+ {
418
+ oci8_base_t *base = oci8_get_handle(self, cOCIStmt);
419
+ return oci8_get_rowid_attr(base, OCI_ATTR_ROWID, base->hp.stmt);
420
+ }
421
+
422
+ static VALUE oci8_stmt_get_param_count(VALUE self)
423
+ {
424
+ oci8_base_t *base = oci8_get_handle(self, cOCIStmt);
425
+ return oci8_get_ub4_attr(base, OCI_ATTR_PARAM_COUNT, base->hp.stmt);
426
+ }
427
+
428
+ /*
429
+ * call-seq:
430
+ * [key]
431
+ *
432
+ * Gets the value of the bind variable.
433
+ *
434
+ * In case of binding explicitly, use same key with that of
435
+ * OCI8::Cursor#bind_param. A placeholder can be bound by
436
+ * name or position. If you bind by name, use that name. If you bind
437
+ * by position, use the position.
438
+ *
439
+ * example:
440
+ * cursor = conn.parse("BEGIN :out := 'BAR'; END;")
441
+ * cursor.bind_param(':out', 'FOO') # bind by name
442
+ * p cursor[':out'] # => 'FOO'
443
+ * p cursor[1] # => nil
444
+ * cursor.exec()
445
+ * p cursor[':out'] # => 'BAR'
446
+ * p cursor[1] # => nil
447
+ *
448
+ * example:
449
+ * cursor = conn.parse("BEGIN :out := 'BAR'; END;")
450
+ * cursor.bind_param(1, 'FOO') # bind by position
451
+ * p cursor[':out'] # => nil
452
+ * p cursor[1] # => 'FOO'
453
+ * cursor.exec()
454
+ * p cursor[':out'] # => nil
455
+ * p cursor[1] # => 'BAR'
456
+ *
457
+ * In case of binding by OCI8#exec or OCI8::Cursor#exec,
458
+ * get the value by position, which starts from 1.
459
+ *
460
+ * example:
461
+ * cursor = conn.exec("BEGIN :out := 'BAR'; END;", 'FOO')
462
+ * # 1st bind variable is bound as String with width 3. Its initial value is 'FOO'
463
+ * # After execute, the value become 'BAR'.
464
+ * p cursor[1] # => 'BAR'
465
+ */
466
+ static VALUE oci8_stmt_aref(VALUE self, VALUE key)
467
+ {
468
+ oci8_stmt_t *stmt = TO_STMT(self);
469
+ VALUE obj = rb_hash_aref(stmt->binds, key);
470
+ if (NIL_P(obj)) {
471
+ return Qnil;
472
+ }
473
+ return oci8_bind_get_data(obj);
474
+ }
475
+
476
+ /*
477
+ * call-seq:
478
+ * [key] = val
479
+ *
480
+ * Sets the value to the bind variable. The way to specify the
481
+ * +key+ is same with OCI8::Cursor#[]. This is available
482
+ * to replace the value and execute many times.
483
+ *
484
+ * example1:
485
+ * cursor = conn.parse("INSERT INTO test(col1) VALUES(:1)")
486
+ * cursor.bind_params(1, nil, String, 3)
487
+ * ['FOO', 'BAR', 'BAZ'].each do |key|
488
+ * cursor[1] = key
489
+ * cursor.exec
490
+ * end
491
+ * cursor.close()
492
+ *
493
+ * example2:
494
+ * ['FOO', 'BAR', 'BAZ'].each do |key|
495
+ * conn.exec("INSERT INTO test(col1) VALUES(:1)", key)
496
+ * end
497
+ *
498
+ * Both example's results are same. But the former will use less resources.
499
+ */
500
+ static VALUE oci8_stmt_aset(VALUE self, VALUE key, VALUE val)
501
+ {
502
+ long max_array_size;
503
+ long actual_array_size;
504
+ long bind_array_size;
505
+
506
+ oci8_stmt_t *stmt = TO_STMT(self);
507
+ VALUE obj = rb_hash_aref(stmt->binds, key);
508
+ if (NIL_P(obj)) {
509
+ return Qnil; /* ?? MUST BE ERROR? */
510
+ }
511
+
512
+ if(TYPE(val) == T_ARRAY) {
513
+ max_array_size = NUM2INT(rb_ivar_get(self, id_at_max_array_size));
514
+ actual_array_size = NUM2INT(rb_ivar_get(self, id_at_actual_array_size));
515
+ bind_array_size = RARRAY_LEN(val);
516
+
517
+ if(actual_array_size > 0 && bind_array_size != actual_array_size) {
518
+ rb_raise(rb_eRuntimeError, "all binding arrays hould be the same size");
519
+ }
520
+ if(bind_array_size <= max_array_size && actual_array_size == 0) {
521
+ rb_ivar_set(self, id_at_actual_array_size, INT2NUM(bind_array_size));
522
+ }
523
+ }
524
+ oci8_bind_set_data(obj, val);
525
+ return val;
526
+ }
527
+
528
+ /*
529
+ * call-seq:
530
+ * keys -> an Array
531
+ *
532
+ * Returns the keys of bind variables as array.
533
+ */
534
+ static VALUE oci8_stmt_keys(VALUE self)
535
+ {
536
+ oci8_stmt_t *stmt = TO_STMT(self);
537
+ return rb_funcall(stmt->binds, oci8_id_keys, 0);
538
+ }
539
+
540
+ static VALUE oci8_stmt_defined_p(VALUE self, VALUE pos)
541
+ {
542
+ oci8_stmt_t *stmt = TO_STMT(self);
543
+ long position = NUM2INT(pos);
544
+
545
+ if (position - 1 < RARRAY_LEN(stmt->defns)) {
546
+ VALUE value = RARRAY_PTR(stmt->defns)[position - 1];
547
+ if (!NIL_P(value)) {
548
+ return Qtrue;
549
+ }
550
+ }
551
+ return Qfalse;
552
+ }
553
+
554
+ /*
555
+ * call-seq:
556
+ * prefetch_rows = aFixnum
557
+ *
558
+ * Set number of rows to be prefetched.
559
+ * This can reduce the number of network round trips when fetching
560
+ * many rows. The default value is one.
561
+ *
562
+ * FYI: Rails oracle adaptor uses 100 by default.
563
+ */
564
+ static VALUE oci8_stmt_set_prefetch_rows(VALUE self, VALUE rows)
565
+ {
566
+ oci8_stmt_t *stmt = TO_STMT(self);
567
+ ub4 num = NUM2UINT(rows);
568
+
569
+ chker2(OCIAttrSet(stmt->base.hp.ptr, OCI_HTYPE_STMT, &num, 0, OCI_ATTR_PREFETCH_ROWS, oci8_errhp),
570
+ &stmt->base);
571
+ return Qfalse;
572
+ }
573
+
574
+ /*
575
+ * bind_stmt
576
+ */
577
+ VALUE oci8_stmt_get(oci8_bind_t *obind, void *data, void *null_struct)
578
+ {
579
+ oci8_hp_obj_t *oho = (oci8_hp_obj_t *)data;
580
+ rb_funcall(oho->obj, rb_intern("define_columns"), 0);
581
+ return oho->obj;
582
+ }
583
+
584
+ static void bind_stmt_set(oci8_bind_t *obind, void *data, void **null_structp, VALUE val)
585
+ {
586
+ oci8_hp_obj_t *oho = (oci8_hp_obj_t *)data;
587
+ oci8_base_t *h;
588
+ if (!rb_obj_is_instance_of(val, cOCIStmt))
589
+ rb_raise(rb_eArgError, "Invalid argument: %s (expect OCIStmt)", rb_class2name(CLASS_OF(val)));
590
+ h = DATA_PTR(val);
591
+ oho->hp = h->hp.ptr;
592
+ oho->obj = val;
593
+ }
594
+
595
+ static void bind_stmt_init(oci8_bind_t *obind, VALUE svc, VALUE val, VALUE length)
596
+ {
597
+ obind->value_sz = sizeof(void *);
598
+ obind->alloc_sz = sizeof(oci8_hp_obj_t);
599
+ }
600
+
601
+ static void bind_stmt_init_elem(oci8_bind_t *obind, VALUE svc)
602
+ {
603
+ oci8_hp_obj_t *oho = (oci8_hp_obj_t *)obind->valuep;
604
+ oci8_base_t *h;
605
+ ub4 idx = 0;
606
+
607
+ do {
608
+ oho[idx].obj = rb_funcall(cOCIStmt, oci8_id_new, 1, svc);
609
+ h = DATA_PTR(oho[idx].obj);
610
+ oho[idx].hp = h->hp.ptr;
611
+ } while (++idx < obind->maxar_sz);
612
+ }
613
+
614
+ static const oci8_bind_vtable_t bind_stmt_vtable = {
615
+ {
616
+ oci8_bind_hp_obj_mark,
617
+ oci8_bind_free,
618
+ sizeof(oci8_bind_t)
619
+ },
620
+ oci8_stmt_get,
621
+ bind_stmt_set,
622
+ bind_stmt_init,
623
+ bind_stmt_init_elem,
624
+ bind_stmt_init_elem,
625
+ SQLT_RSET
626
+ };
627
+
628
+ void Init_oci8_stmt(VALUE cOCI8)
629
+ {
630
+ #if 0
631
+ cOCIHandle = rb_define_class("OCIHandle", rb_cObject);
632
+ cOCI8 = rb_define_class("OCI8", cOCIHandle);
633
+ cOCIStmt = rb_define_class_under(cOCI8, "Cursor", cOCIHandle);
634
+ #endif
635
+ cOCIStmt = oci8_define_class_under(cOCI8, "Cursor", &oci8_stmt_vtable);
636
+
637
+ oci8_sym_select_stmt = ID2SYM(rb_intern("select_stmt"));
638
+ oci8_sym_update_stmt = ID2SYM(rb_intern("update_stmt"));
639
+ oci8_sym_delete_stmt = ID2SYM(rb_intern("delete_stmt"));
640
+ oci8_sym_insert_stmt = ID2SYM(rb_intern("insert_stmt"));
641
+ oci8_sym_create_stmt = ID2SYM(rb_intern("create_stmt"));
642
+ oci8_sym_drop_stmt = ID2SYM(rb_intern("drop_stmt"));
643
+ oci8_sym_alter_stmt = ID2SYM(rb_intern("alter_stmt"));
644
+ oci8_sym_begin_stmt = ID2SYM(rb_intern("begin_stmt"));
645
+ oci8_sym_declare_stmt = ID2SYM(rb_intern("declare_stmt"));
646
+ id_at_column_metadata = rb_intern("@column_metadata");
647
+ id_at_actual_array_size = rb_intern("@actual_array_size");
648
+ id_at_max_array_size = rb_intern("@max_array_size");
649
+ id_each_value = rb_intern("each_value");
650
+ id_at_names = rb_intern("@names");
651
+ id_at_con = rb_intern("@con");
652
+ id_empty_p = rb_intern("empty?");
653
+ id_clear = rb_intern("clear");
654
+
655
+ rb_define_private_method(cOCIStmt, "initialize", oci8_stmt_initialize, -1);
656
+ rb_define_private_method(cOCIStmt, "__define", oci8_define_by_pos, 2);
657
+ rb_define_private_method(cOCIStmt, "__bind", oci8_bind, 2);
658
+ rb_define_private_method(cOCIStmt, "__execute", oci8_stmt_execute, 1);
659
+ rb_define_private_method(cOCIStmt, "__clearBinds", oci8_stmt_clear_binds, 0);
660
+ rb_define_method(cOCIStmt, "fetch", oci8_stmt_fetch, 0);
661
+ rb_define_private_method(cOCIStmt, "__paramGet", oci8_stmt_get_param, 1);
662
+ rb_define_method(cOCIStmt, "type", oci8_stmt_get_stmt_type, 0);
663
+ rb_define_method(cOCIStmt, "row_count", oci8_stmt_get_row_count, 0);
664
+ rb_define_method(cOCIStmt, "rowid", oci8_stmt_get_rowid, 0);
665
+ rb_define_private_method(cOCIStmt, "__param_count", oci8_stmt_get_param_count, 0);
666
+ rb_define_method(cOCIStmt, "[]", oci8_stmt_aref, 1);
667
+ rb_define_method(cOCIStmt, "[]=", oci8_stmt_aset, 2);
668
+ rb_define_method(cOCIStmt, "keys", oci8_stmt_keys, 0);
669
+ rb_define_private_method(cOCIStmt, "__defined?", oci8_stmt_defined_p, 1);
670
+ rb_define_method(cOCIStmt, "prefetch_rows=", oci8_stmt_set_prefetch_rows, 1);
671
+
672
+ oci8_define_bind_class("Cursor", &bind_stmt_vtable);
673
+ }