ruby-oci8-master 2.0.7

Sign up to get free protection for your applications and to get access to all the features.
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
+ }