ruby-oci8-master 2.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +2321 -0
- data/Makefile +88 -0
- data/NEWS +303 -0
- data/README +76 -0
- data/VERSION +1 -0
- data/dist-files +83 -0
- data/doc/api.en.html +527 -0
- data/doc/api.en.rd +554 -0
- data/doc/api.ja.html +525 -0
- data/doc/api.ja.rd +557 -0
- data/doc/manual.css +35 -0
- data/ext/oci8/.document +18 -0
- data/ext/oci8/MANIFEST +18 -0
- data/ext/oci8/apiwrap.c.tmpl +182 -0
- data/ext/oci8/apiwrap.h.tmpl +61 -0
- data/ext/oci8/apiwrap.rb +91 -0
- data/ext/oci8/apiwrap.yml +1455 -0
- data/ext/oci8/attr.c +105 -0
- data/ext/oci8/bind.c +366 -0
- data/ext/oci8/connection_pool.c +199 -0
- data/ext/oci8/encoding.c +289 -0
- data/ext/oci8/env.c +178 -0
- data/ext/oci8/error.c +378 -0
- data/ext/oci8/extconf.rb +179 -0
- data/ext/oci8/lob.c +805 -0
- data/ext/oci8/metadata.c +232 -0
- data/ext/oci8/object.c +727 -0
- data/ext/oci8/oci8.c +1156 -0
- data/ext/oci8/oci8.h +574 -0
- data/ext/oci8/oci8lib.c +527 -0
- data/ext/oci8/ocidatetime.c +484 -0
- data/ext/oci8/ocihandle.c +751 -0
- data/ext/oci8/ocinumber.c +1612 -0
- data/ext/oci8/oraconf.rb +1119 -0
- data/ext/oci8/oradate.c +611 -0
- data/ext/oci8/oranumber_util.c +352 -0
- data/ext/oci8/oranumber_util.h +24 -0
- data/ext/oci8/post-config.rb +5 -0
- data/ext/oci8/stmt.c +673 -0
- data/ext/oci8/thread_util.c +85 -0
- data/ext/oci8/thread_util.h +30 -0
- data/ext/oci8/win32.c +137 -0
- data/lib/.document +1 -0
- data/lib/dbd/OCI8.rb +591 -0
- data/lib/oci8.rb.in +94 -0
- data/lib/oci8/.document +8 -0
- data/lib/oci8/bindtype.rb +349 -0
- data/lib/oci8/compat.rb +113 -0
- data/lib/oci8/connection_pool.rb +99 -0
- data/lib/oci8/datetime.rb +611 -0
- data/lib/oci8/encoding-init.rb +74 -0
- data/lib/oci8/encoding.yml +537 -0
- data/lib/oci8/metadata.rb +2132 -0
- data/lib/oci8/object.rb +581 -0
- data/lib/oci8/oci8.rb +721 -0
- data/lib/oci8/ocihandle.rb +425 -0
- data/lib/oci8/oracle_version.rb +144 -0
- data/lib/oci8/properties.rb +73 -0
- data/metaconfig +142 -0
- data/pre-distclean.rb +7 -0
- data/ruby-oci8.gemspec +63 -0
- data/setup.rb +1331 -0
- data/test/README +4 -0
- data/test/config.rb +122 -0
- data/test/test_all.rb +51 -0
- data/test/test_appinfo.rb +63 -0
- data/test/test_array_dml.rb +333 -0
- data/test/test_bind_raw.rb +46 -0
- data/test/test_bind_time.rb +178 -0
- data/test/test_break.rb +96 -0
- data/test/test_clob.rb +82 -0
- data/test/test_connstr.rb +81 -0
- data/test/test_datetime.rb +582 -0
- data/test/test_dbi.rb +366 -0
- data/test/test_dbi_clob.rb +53 -0
- data/test/test_encoding.rb +100 -0
- data/test/test_error.rb +88 -0
- data/test/test_metadata.rb +1399 -0
- data/test/test_oci8.rb +434 -0
- data/test/test_oracle_version.rb +70 -0
- data/test/test_oradate.rb +256 -0
- data/test/test_oranumber.rb +746 -0
- data/test/test_rowid.rb +33 -0
- 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
|
data/ext/oci8/stmt.c
ADDED
@@ -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
|
+
}
|