ruby-oci8 2.1.2 → 2.1.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.yardopts +3 -0
- data/COPYING +30 -0
- data/COPYING_old +64 -0
- data/ChangeLog +115 -0
- data/Makefile +8 -4
- data/NEWS +60 -1
- data/README.md +9 -4
- data/VERSION +1 -1
- data/dist-files +5 -0
- data/ext/oci8/apiwrap.c.tmpl +5 -5
- data/ext/oci8/attr.c +1 -42
- data/ext/oci8/bind.c +5 -2
- data/ext/oci8/connection_pool.c +2 -2
- data/ext/oci8/encoding.c +18 -12
- data/ext/oci8/env.c +1 -1
- data/ext/oci8/extconf.rb +15 -12
- data/ext/oci8/lob.c +19 -2
- data/ext/oci8/oci8.c +69 -52
- data/ext/oci8/oci8.h +31 -18
- data/ext/oci8/oci8lib.c +73 -40
- data/ext/oci8/ocihandle.c +7 -2
- data/ext/oci8/ocinumber.c +5 -5
- data/ext/oci8/stmt.c +66 -368
- data/ext/oci8/thread_util.c +3 -3
- data/ext/oci8/thread_util.h +1 -1
- data/lib/oci8.rb.in +30 -17
- data/lib/oci8/connection_pool.rb +16 -27
- data/lib/oci8/cursor.rb +564 -0
- data/lib/oci8/datetime.rb +11 -17
- data/lib/oci8/encoding-init.rb +1 -0
- data/lib/oci8/metadata.rb +76 -151
- data/lib/oci8/object.rb +3 -3
- data/lib/oci8/oci8.rb +29 -335
- data/ruby-oci8.gemspec +1 -0
- data/setup.rb +4 -2
- data/test/config.rb +64 -0
- data/test/setup_test_object.sql +171 -0
- data/test/test_all.rb +1 -0
- data/test/test_break.rb +18 -2
- data/test/test_clob.rb +4 -4
- data/test/test_datetime.rb +8 -47
- data/test/test_metadata.rb +78 -0
- data/test/test_object.rb +463 -0
- data/test/test_oci8.rb +22 -0
- metadata +10 -3
data/ext/oci8/oci8.h
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
/*
|
3
3
|
* oci8.h - part of ruby-oci8
|
4
4
|
*
|
5
|
-
* Copyright (C) 2002-
|
5
|
+
* Copyright (C) 2002-2012 KUBO Takehiro <kubo@jiubao.org>
|
6
6
|
*/
|
7
7
|
#ifndef _RUBY_OCI_H_
|
8
8
|
#define _RUBY_OCI_H_ 1
|
@@ -126,7 +126,20 @@ typedef struct OCICPool OCICPool;
|
|
126
126
|
#define STRINGIZE(name) #name
|
127
127
|
#endif
|
128
128
|
#ifndef RB_GC_GUARD
|
129
|
-
#
|
129
|
+
#ifdef __GNUC__
|
130
|
+
#define RB_GC_GUARD_PTR(ptr) \
|
131
|
+
__extension__ ({volatile VALUE *rb_gc_guarded_ptr = (ptr); rb_gc_guarded_ptr;})
|
132
|
+
#else
|
133
|
+
#ifdef _MSC_VER
|
134
|
+
#pragma optimize("", off)
|
135
|
+
#endif
|
136
|
+
static inline volatile VALUE *rb_gc_guarded_ptr(volatile VALUE *ptr) {return ptr;}
|
137
|
+
#ifdef _MSC_VER
|
138
|
+
#pragma optimize("", on)
|
139
|
+
#endif
|
140
|
+
#define RB_GC_GUARD_PTR(ptr) rb_gc_guarded_ptr(ptr)
|
141
|
+
#endif
|
142
|
+
#define RB_GC_GUARD(v) (*RB_GC_GUARD_PTR(&(v)))
|
130
143
|
#endif
|
131
144
|
|
132
145
|
/* new functions in ruby 1.9.
|
@@ -135,9 +148,6 @@ typedef struct OCICPool OCICPool;
|
|
135
148
|
#if !defined(HAVE_RB_ERRINFO) && defined(HAVE_RUBY_ERRINFO)
|
136
149
|
#define rb_errinfo() ruby_errinfo
|
137
150
|
#endif
|
138
|
-
#if !defined HAVE_TYPE_RB_BLOCKING_FUNCTION_T_ && !defined HAVE_TYPE_RB_BLOCKING_FUNCTION_TP
|
139
|
-
typedef VALUE rb_blocking_function_t(void *);
|
140
|
-
#endif
|
141
151
|
|
142
152
|
#ifndef HAVE_TYPE_RB_ENCODING
|
143
153
|
#define rb_enc_associate(str, enc) do {} while(0)
|
@@ -160,7 +170,11 @@ typedef VALUE rb_blocking_function_t(void *);
|
|
160
170
|
#endif
|
161
171
|
#endif
|
162
172
|
|
163
|
-
#if defined(
|
173
|
+
#if defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL) || defined(HAVE_RB_THREAD_BLOCKING_REGION)
|
174
|
+
#define NATIVE_THREAD_WITH_GVL 1
|
175
|
+
#endif
|
176
|
+
|
177
|
+
#if defined(HAVE_NATIVETHREAD) || NATIVE_THREAD_WITH_GVL
|
164
178
|
/*
|
165
179
|
* oci8_errhp is a thread local object in ruby 1.9, rubinius
|
166
180
|
* and ruby 1.8 configured with --enable-pthread.
|
@@ -213,7 +227,7 @@ typedef VALUE rb_blocking_function_t(void *);
|
|
213
227
|
#define oci8_tls_get(key) pthread_getspecific(key)
|
214
228
|
#define oci8_tls_set(key, val) pthread_setspecific((key), (val))
|
215
229
|
#endif
|
216
|
-
#endif /*
|
230
|
+
#endif /* USE_THREAD_LOCAL_ERRHP */
|
217
231
|
|
218
232
|
/* utility macros
|
219
233
|
*/
|
@@ -333,6 +347,11 @@ struct oci8_bind {
|
|
333
347
|
|
334
348
|
typedef struct oci8_logoff_strategy oci8_logoff_strategy_t;
|
335
349
|
|
350
|
+
typedef struct oci8_temp_lob {
|
351
|
+
struct oci8_temp_lob *next;
|
352
|
+
OCILobLocator *lob;
|
353
|
+
} oci8_temp_lob_t;
|
354
|
+
|
336
355
|
typedef struct oci8_svcctx {
|
337
356
|
oci8_base_t base;
|
338
357
|
volatile VALUE executing_thread;
|
@@ -342,15 +361,16 @@ typedef struct oci8_svcctx {
|
|
342
361
|
rb_pid_t pid;
|
343
362
|
unsigned char state;
|
344
363
|
char is_autocommit;
|
345
|
-
#ifdef
|
364
|
+
#ifdef NATIVE_THREAD_WITH_GVL
|
346
365
|
char non_blocking;
|
347
366
|
#endif
|
348
367
|
VALUE long_read_len;
|
368
|
+
oci8_temp_lob_t *temp_lobs;
|
349
369
|
} oci8_svcctx_t;
|
350
370
|
|
351
371
|
struct oci8_logoff_strategy {
|
352
372
|
void *(*prepare)(oci8_svcctx_t *svcctx);
|
353
|
-
|
373
|
+
void *(*execute)(void *);
|
354
374
|
};
|
355
375
|
|
356
376
|
typedef struct {
|
@@ -428,7 +448,6 @@ extern ID oci8_id_at_last_error;
|
|
428
448
|
extern ID oci8_id_new;
|
429
449
|
extern ID oci8_id_get;
|
430
450
|
extern ID oci8_id_set;
|
431
|
-
extern ID oci8_id_keys;
|
432
451
|
extern ID oci8_id_oci8_vtable;
|
433
452
|
#ifdef CHAR_IS_NOT_A_SHORTCUT_TO_ID
|
434
453
|
extern ID oci8_id_add_op; /* ID of the addition operator '+' */
|
@@ -449,7 +468,7 @@ VALUE oci8_define_class_under(VALUE outer, const char *name, oci8_base_vtable_t
|
|
449
468
|
VALUE oci8_define_bind_class(const char *name, const oci8_bind_vtable_t *vptr);
|
450
469
|
void oci8_link_to_parent(oci8_base_t *base, oci8_base_t *parent);
|
451
470
|
void oci8_unlink_from_parent(oci8_base_t *base);
|
452
|
-
sword
|
471
|
+
sword oci8_call_without_gvl(oci8_svcctx_t *svcctx, void *(*func)(void *), void *data);
|
453
472
|
sword oci8_exec_sql(oci8_svcctx_t *svcctx, const char *sql_text, ub4 num_define_vars, oci8_exec_sql_var_t *define_vars, ub4 num_bind_vars, oci8_exec_sql_var_t *bind_vars, int raise_on_error);
|
454
473
|
#if defined RUNTIME_API_CHECK
|
455
474
|
void *oci8_find_symbol(const char *symbol_name);
|
@@ -471,7 +490,7 @@ void oci8_check_error_(sword status, oci8_base_t *base, OCIStmt *stmthp, const c
|
|
471
490
|
void Init_oci8_handle(void);
|
472
491
|
|
473
492
|
/* oci8.c */
|
474
|
-
|
493
|
+
void Init_oci8(VALUE *out);
|
475
494
|
void oci8_do_parse_connect_string(VALUE conn_str, VALUE *user, VALUE *pass, VALUE *dbname, VALUE *mode);
|
476
495
|
oci8_svcctx_t *oci8_get_svcctx(VALUE obj);
|
477
496
|
OCISvcCtx *oci8_get_oci_svcctx(VALUE obj);
|
@@ -496,8 +515,6 @@ void oci8_bind_free(oci8_base_t *base);
|
|
496
515
|
void oci8_bind_hp_obj_mark(oci8_base_t *base);
|
497
516
|
void Init_oci8_bind(VALUE cOCI8BindTypeBase);
|
498
517
|
oci8_bind_t *oci8_get_bind(VALUE obj);
|
499
|
-
void oci8_bind_set_data(VALUE self, VALUE val);
|
500
|
-
VALUE oci8_bind_get_data(VALUE self);
|
501
518
|
|
502
519
|
/* metadata.c */
|
503
520
|
extern VALUE cOCI8MetadataBase;
|
@@ -551,11 +568,7 @@ VALUE oci8_make_interval_ds(OCIInterval *s);
|
|
551
568
|
void Init_oci_object(VALUE mOCI);
|
552
569
|
|
553
570
|
/* attr.c */
|
554
|
-
VALUE oci8_get_sb1_attr(oci8_base_t *base, ub4 attrtype, OCIStmt *stmtp);
|
555
571
|
VALUE oci8_get_ub2_attr(oci8_base_t *base, ub4 attrtype, OCIStmt *stmtp);
|
556
|
-
VALUE oci8_get_sb2_attr(oci8_base_t *base, ub4 attrtype, OCIStmt *stmtp);
|
557
|
-
VALUE oci8_get_ub4_attr(oci8_base_t *base, ub4 attrtype, OCIStmt *stmtp);
|
558
|
-
VALUE oci8_get_string_attr(oci8_base_t *base, ub4 attrtype, OCIStmt *stmtp);
|
559
572
|
VALUE oci8_get_rowid_attr(oci8_base_t *base, ub4 attrtype, OCIStmt *stmtp);
|
560
573
|
|
561
574
|
/* encoding.c */
|
data/ext/oci8/oci8lib.c
CHANGED
@@ -4,12 +4,14 @@
|
|
4
4
|
*/
|
5
5
|
|
6
6
|
#include "oci8.h"
|
7
|
+
#ifdef HAVE_RUBY_THREAD_H
|
8
|
+
#include <ruby/thread.h>
|
9
|
+
#endif
|
7
10
|
|
8
11
|
ID oci8_id_at_last_error;
|
9
12
|
ID oci8_id_new;
|
10
13
|
ID oci8_id_get;
|
11
14
|
ID oci8_id_set;
|
12
|
-
ID oci8_id_keys;
|
13
15
|
ID oci8_id_oci8_vtable;
|
14
16
|
#ifdef CHAR_IS_NOT_A_SHORTCUT_TO_ID
|
15
17
|
ID oci8_id_add_op;
|
@@ -80,7 +82,6 @@ Init_oci8lib()
|
|
80
82
|
oci8_id_new = rb_intern("new");
|
81
83
|
oci8_id_get = rb_intern("get");
|
82
84
|
oci8_id_set = rb_intern("set");
|
83
|
-
oci8_id_keys = rb_intern("keys");
|
84
85
|
oci8_id_oci8_vtable = rb_intern("__oci8_vtable__");
|
85
86
|
#ifdef CHAR_IS_NOT_A_SHORTCUT_TO_ID
|
86
87
|
oci8_id_add_op = rb_intern("+");
|
@@ -100,7 +101,7 @@ Init_oci8lib()
|
|
100
101
|
Init_oci8_handle();
|
101
102
|
|
102
103
|
/* OCI8 class */
|
103
|
-
|
104
|
+
Init_oci8(&cOCI8);
|
104
105
|
|
105
106
|
/* OCI8::ConnectionPool class */
|
106
107
|
Init_oci8_connection_pool(cOCI8);
|
@@ -201,74 +202,106 @@ void oci8_unlink_from_parent(oci8_base_t *base)
|
|
201
202
|
base->parent = NULL;
|
202
203
|
}
|
203
204
|
|
204
|
-
#ifdef
|
205
|
+
#ifdef NATIVE_THREAD_WITH_GVL
|
205
206
|
|
206
|
-
|
207
|
-
|
208
|
-
|
207
|
+
static void oci8_unblock_func(void *user_data)
|
208
|
+
{
|
209
|
+
oci8_svcctx_t *svcctx = (oci8_svcctx_t *)user_data;
|
210
|
+
OCIBreak(svcctx->base.hp.ptr, oci8_errhp);
|
211
|
+
}
|
212
|
+
|
213
|
+
typedef struct free_temp_lob_arg_t {
|
214
|
+
oci8_svcctx_t *svcctx;
|
215
|
+
OCISvcCtx *svchp;
|
209
216
|
OCIError *errhp;
|
210
|
-
|
217
|
+
OCILobLocator *lob;
|
218
|
+
} free_temp_lob_arg_t;
|
211
219
|
|
212
|
-
static
|
220
|
+
static void *free_temp_lob(void *user_data)
|
213
221
|
{
|
214
|
-
|
215
|
-
|
216
|
-
|
222
|
+
free_temp_lob_arg_t *data = (free_temp_lob_arg_t *)user_data;
|
223
|
+
sword rv = OCILobFreeTemporary(data->svchp, data->errhp, data->lob);
|
224
|
+
|
225
|
+
data->svcctx->executing_thread = Qnil;
|
226
|
+
return (void*)(VALUE)rv;
|
217
227
|
}
|
218
228
|
|
219
|
-
|
229
|
+
/* ruby 1.9 */
|
230
|
+
sword oci8_call_without_gvl(oci8_svcctx_t *svcctx, void *(*func)(void *), void *data)
|
220
231
|
{
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
rb_thread_blocking_region(call_OCIBreak, &arg, NULL, NULL);
|
232
|
+
oci8_temp_lob_t *lob;
|
233
|
+
OCIError *errhp = oci8_errhp;
|
234
|
+
|
235
|
+
if (!NIL_P(svcctx->executing_thread)) {
|
236
|
+
rb_raise(rb_eRuntimeError /* FIXME */, "executing in another thread");
|
227
237
|
}
|
228
|
-
|
238
|
+
|
239
|
+
lob = svcctx->temp_lobs;
|
240
|
+
while (lob != NULL) {
|
241
|
+
oci8_temp_lob_t *lob_next = lob->next;
|
242
|
+
|
243
|
+
if (svcctx->non_blocking) {
|
244
|
+
free_temp_lob_arg_t arg;
|
245
|
+
sword rv;
|
246
|
+
|
247
|
+
arg.svcctx = svcctx;
|
248
|
+
arg.svchp = svcctx->base.hp.svc;
|
249
|
+
arg.errhp = errhp;
|
250
|
+
arg.lob = lob->lob;
|
251
|
+
|
252
|
+
svcctx->executing_thread = rb_thread_current();
|
253
|
+
#ifdef HAVE_RB_THREAD_CALL_WITHOUT_GVL
|
254
|
+
rv = (sword)(VALUE)rb_thread_call_without_gvl(free_temp_lob, &arg, oci8_unblock_func, svcctx);
|
229
255
|
#else
|
230
|
-
|
231
|
-
{
|
232
|
-
oci8_svcctx_t *svcctx = (oci8_svcctx_t *)user_data;
|
233
|
-
OCIBreak(svcctx->base.hp.ptr, oci8_errhp);
|
234
|
-
}
|
256
|
+
rv = (sword)rb_thread_blocking_region((VALUE(*)(void*))free_temp_lob, &arg, oci8_unblock_func, svcctx);
|
235
257
|
#endif
|
258
|
+
if (rv == OCI_ERROR) {
|
259
|
+
if (oci8_get_error_code(errhp) == 1013) {
|
260
|
+
rb_raise(eOCIBreak, "Canceled by user request.");
|
261
|
+
}
|
262
|
+
}
|
263
|
+
} else {
|
264
|
+
OCILobFreeTemporary(svcctx->base.hp.svc, errhp, lob->lob);
|
265
|
+
}
|
266
|
+
OCIDescriptorFree(lob->lob, OCI_DTYPE_LOB);
|
267
|
+
|
268
|
+
xfree(lob);
|
269
|
+
svcctx->temp_lobs = lob = lob_next;
|
270
|
+
}
|
236
271
|
|
237
|
-
/* ruby 1.9 */
|
238
|
-
sword oci8_blocking_region(oci8_svcctx_t *svcctx, rb_blocking_function_t func, void *data)
|
239
|
-
{
|
240
272
|
if (svcctx->non_blocking) {
|
241
273
|
sword rv;
|
242
274
|
|
243
|
-
if (!NIL_P(svcctx->executing_thread)) {
|
244
|
-
rb_raise(rb_eRuntimeError /* FIXME */, "executing in another thread");
|
245
|
-
}
|
246
275
|
svcctx->executing_thread = rb_thread_current();
|
247
276
|
/* Note: executing_thread is cleard at the end of the blocking function. */
|
248
|
-
|
277
|
+
#ifdef HAVE_RB_THREAD_CALL_WITHOUT_GVL
|
278
|
+
rv = (sword)(VALUE)rb_thread_call_without_gvl(func, data, oci8_unblock_func, svcctx);
|
279
|
+
#else
|
280
|
+
rv = (sword)rb_thread_blocking_region((VALUE(*)(void*))func, data, oci8_unblock_func, svcctx);
|
281
|
+
#endif
|
249
282
|
if (rv == OCI_ERROR) {
|
250
|
-
if (oci8_get_error_code(
|
283
|
+
if (oci8_get_error_code(errhp) == 1013) {
|
251
284
|
rb_raise(eOCIBreak, "Canceled by user request.");
|
252
285
|
}
|
253
286
|
}
|
254
287
|
return rv;
|
255
288
|
} else {
|
256
|
-
return (sword)func(data);
|
289
|
+
return (sword)(VALUE)func(data);
|
257
290
|
}
|
258
291
|
}
|
259
|
-
#else /*
|
292
|
+
#else /* NATIVE_THREAD_WITH_GVL */
|
260
293
|
|
261
294
|
/* ruby 1.8 */
|
262
295
|
typedef struct {
|
263
296
|
oci8_svcctx_t *svcctx;
|
264
|
-
|
297
|
+
void *(*func)(void *);
|
265
298
|
void *data;
|
266
299
|
} blocking_region_arg_t;
|
267
300
|
|
268
301
|
static VALUE blocking_function_execute(blocking_region_arg_t *arg)
|
269
302
|
{
|
270
303
|
oci8_svcctx_t *svcctx = arg->svcctx;
|
271
|
-
|
304
|
+
void *(*func)(void *) = arg->func;
|
272
305
|
void *data = arg->data;
|
273
306
|
struct timeval tv;
|
274
307
|
sword rv;
|
@@ -276,7 +309,7 @@ static VALUE blocking_function_execute(blocking_region_arg_t *arg)
|
|
276
309
|
tv.tv_sec = 0;
|
277
310
|
tv.tv_usec = 10000;
|
278
311
|
svcctx->executing_thread = rb_thread_current();
|
279
|
-
while ((rv = func(data)) == OCI_STILL_EXECUTING) {
|
312
|
+
while ((rv = (sword)(VALUE)func(data)) == OCI_STILL_EXECUTING) {
|
280
313
|
rb_thread_wait_for(tv);
|
281
314
|
if (tv.tv_usec < 500000)
|
282
315
|
tv.tv_usec <<= 1;
|
@@ -303,7 +336,7 @@ static VALUE blocking_function_ensure(oci8_svcctx_t *svcctx)
|
|
303
336
|
return Qnil;
|
304
337
|
}
|
305
338
|
|
306
|
-
sword
|
339
|
+
sword oci8_call_without_gvl(oci8_svcctx_t *svcctx, void *(*func)(void *), void *data)
|
307
340
|
{
|
308
341
|
blocking_region_arg_t arg;
|
309
342
|
|
@@ -315,7 +348,7 @@ sword oci8_blocking_region(oci8_svcctx_t *svcctx, rb_blocking_function_t func, v
|
|
315
348
|
}
|
316
349
|
return (sword)rb_ensure(blocking_function_execute, (VALUE)&arg, blocking_function_ensure, (VALUE)svcctx);
|
317
350
|
}
|
318
|
-
#endif /*
|
351
|
+
#endif /* NATIVE_THREAD_WITH_GVL */
|
319
352
|
|
320
353
|
typedef struct {
|
321
354
|
oci8_svcctx_t *svcctx;
|
data/ext/oci8/ocihandle.c
CHANGED
@@ -419,8 +419,9 @@ static VALUE attr_get_binary(VALUE self, VALUE attr_type)
|
|
419
419
|
static VALUE attr_get_integer(VALUE self, VALUE attr_type)
|
420
420
|
{
|
421
421
|
oci8_base_t *base = DATA_PTR(self);
|
422
|
+
OCINumber onum;
|
422
423
|
union {
|
423
|
-
|
424
|
+
void *value;
|
424
425
|
ub8 dummy; /* padding for incorrect attrtype to protect the stack */
|
425
426
|
} v;
|
426
427
|
ub4 size = 0;
|
@@ -428,7 +429,11 @@ static VALUE attr_get_integer(VALUE self, VALUE attr_type)
|
|
428
429
|
v.dummy = 0;
|
429
430
|
Check_Type(attr_type, T_FIXNUM);
|
430
431
|
chker2(OCIAttrGet(base->hp.ptr, base->type, &v.value, &size, FIX2INT(attr_type), oci8_errhp), base);
|
431
|
-
|
432
|
+
|
433
|
+
memset(&onum, 0, sizeof(onum));
|
434
|
+
onum.OCINumberPart[0] = size;
|
435
|
+
memcpy(&onum.OCINumberPart[1], v.value, size);
|
436
|
+
return oci8_make_integer(&onum, oci8_errhp);
|
432
437
|
}
|
433
438
|
|
434
439
|
/*
|
data/ext/oci8/ocinumber.c
CHANGED
@@ -32,7 +32,7 @@ static ID id_denominator;
|
|
32
32
|
static ID id_Rational;
|
33
33
|
static ID id_BigDecimal;
|
34
34
|
|
35
|
-
#ifndef
|
35
|
+
#ifndef rb_Rational2
|
36
36
|
static VALUE cRational;
|
37
37
|
#endif
|
38
38
|
static VALUE cBigDecimal;
|
@@ -51,7 +51,7 @@ static OCINumber const_mPI2; /* -PI/2 */
|
|
51
51
|
#endif
|
52
52
|
#define RBOCI8_T_ORANUMBER (T_MASK + 1)
|
53
53
|
#define RBOCI8_T_BIGDECIMAL (T_MASK + 2)
|
54
|
-
#ifdef
|
54
|
+
#ifdef rb_Rational2
|
55
55
|
#define RBOCI8_T_RATIONAL T_RATIONAL
|
56
56
|
#else
|
57
57
|
#define RBOCI8_T_RATIONAL (T_MASK + 3)
|
@@ -63,7 +63,7 @@ static int rboci8_type(VALUE obj)
|
|
63
63
|
VALUE klass;
|
64
64
|
|
65
65
|
switch (type) {
|
66
|
-
#ifndef
|
66
|
+
#ifndef rb_Rational2
|
67
67
|
case T_OBJECT:
|
68
68
|
klass = CLASS_OF(obj);
|
69
69
|
if (cRational != 0) {
|
@@ -1262,7 +1262,7 @@ static VALUE onum_round(int argc, VALUE *argv, VALUE self)
|
|
1262
1262
|
*
|
1263
1263
|
* @param [Integer]
|
1264
1264
|
* @return [OraNumber]
|
1265
|
-
* @todo returns
|
1265
|
+
* @todo returns <i>Integer</i> when <i>decplace</i> is not specified.
|
1266
1266
|
*/
|
1267
1267
|
static VALUE onum_trunc(int argc, VALUE *argv, VALUE self)
|
1268
1268
|
{
|
@@ -1435,7 +1435,7 @@ static VALUE onum_to_r(VALUE self)
|
|
1435
1435
|
} else {
|
1436
1436
|
y = rb_funcall(INT2FIX(10), rb_intern("**"), 1, INT2FIX(nshift));
|
1437
1437
|
}
|
1438
|
-
#ifdef
|
1438
|
+
#ifdef rb_Rational2
|
1439
1439
|
return rb_Rational(x, y);
|
1440
1440
|
#else
|
1441
1441
|
if (!cRational) {
|
data/ext/oci8/stmt.c
CHANGED
@@ -3,29 +3,11 @@
|
|
3
3
|
* stmt.c - part of ruby-oci8
|
4
4
|
* implement the methods of OCIStmt.
|
5
5
|
*
|
6
|
-
* Copyright (C) 2002-
|
6
|
+
* Copyright (C) 2002-2012 KUBO Takehiro <kubo@jiubao.org>
|
7
7
|
*
|
8
8
|
*/
|
9
9
|
#include "oci8.h"
|
10
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
11
|
VALUE cOCIStmt;
|
30
12
|
|
31
13
|
#define TO_STMT(obj) ((oci8_stmt_t *)oci8_get_handle((obj), cOCIStmt))
|
@@ -33,8 +15,6 @@ VALUE cOCIStmt;
|
|
33
15
|
typedef struct {
|
34
16
|
oci8_base_t base;
|
35
17
|
VALUE svc;
|
36
|
-
VALUE binds;
|
37
|
-
VALUE defns;
|
38
18
|
int use_stmt_release;
|
39
19
|
} oci8_stmt_t;
|
40
20
|
|
@@ -42,16 +22,12 @@ static void oci8_stmt_mark(oci8_base_t *base)
|
|
42
22
|
{
|
43
23
|
oci8_stmt_t *stmt = (oci8_stmt_t *)base;
|
44
24
|
rb_gc_mark(stmt->svc);
|
45
|
-
rb_gc_mark(stmt->binds);
|
46
|
-
rb_gc_mark(stmt->defns);
|
47
25
|
}
|
48
26
|
|
49
27
|
static void oci8_stmt_free(oci8_base_t *base)
|
50
28
|
{
|
51
29
|
oci8_stmt_t *stmt = (oci8_stmt_t *)base;
|
52
30
|
stmt->svc = Qnil;
|
53
|
-
stmt->binds = Qnil;
|
54
|
-
stmt->defns = Qnil;
|
55
31
|
if (stmt->use_stmt_release) {
|
56
32
|
OCIStmtRelease(base->hp.stmt, oci8_errhp, NULL, 0, OCI_DEFAULT);
|
57
33
|
base->type = 0;
|
@@ -65,19 +41,24 @@ static oci8_base_vtable_t oci8_stmt_vtable = {
|
|
65
41
|
sizeof(oci8_stmt_t),
|
66
42
|
};
|
67
43
|
|
68
|
-
|
44
|
+
/*
|
45
|
+
* call-seq:
|
46
|
+
* __initialize(connection, sql_statement)
|
47
|
+
*
|
48
|
+
* @param [OCI8] connection
|
49
|
+
* @param [String] sql_statement
|
50
|
+
*
|
51
|
+
* @private
|
52
|
+
*/
|
53
|
+
static VALUE oci8_stmt_initialize(VALUE self, VALUE svc, VALUE sql)
|
69
54
|
{
|
70
55
|
oci8_stmt_t *stmt = DATA_PTR(self);
|
71
56
|
oci8_svcctx_t *svcctx;
|
72
|
-
VALUE svc;
|
73
|
-
VALUE sql;
|
74
57
|
sword rv;
|
75
58
|
|
76
|
-
rb_scan_args(argc, argv, "11", &svc, &sql);
|
77
|
-
|
78
59
|
svcctx = oci8_get_svcctx(svc);
|
79
60
|
oci8_check_pid_consistency(svcctx);
|
80
|
-
if (
|
61
|
+
if (!NIL_P(sql) && oracle_client_version >= ORAVER_9_2) {
|
81
62
|
OCI8SafeStringValue(sql);
|
82
63
|
|
83
64
|
rv = OCIStmtPrepare2(svcctx->base.hp.svc, &stmt->base.hp.stmt, oci8_errhp, RSTRING_ORATEXT(sql), RSTRING_LEN(sql), NULL, 0, OCI_NTV_SYNTAX, OCI_DEFAULT);
|
@@ -92,7 +73,7 @@ static VALUE oci8_stmt_initialize(int argc, VALUE *argv, VALUE self)
|
|
92
73
|
oci8_env_raise(oci8_envhp, rv);
|
93
74
|
}
|
94
75
|
stmt->base.type = OCI_HTYPE_STMT;
|
95
|
-
if (
|
76
|
+
if (!NIL_P(sql)) {
|
96
77
|
OCI8SafeStringValue(sql);
|
97
78
|
rv = OCIStmtPrepare(stmt->base.hp.stmt, oci8_errhp, RSTRING_ORATEXT(sql), RSTRING_LEN(sql), OCI_NTV_SYNTAX, OCI_DEFAULT);
|
98
79
|
if (IS_OCI_ERROR(rv)) {
|
@@ -101,17 +82,20 @@ static VALUE oci8_stmt_initialize(int argc, VALUE *argv, VALUE self)
|
|
101
82
|
}
|
102
83
|
}
|
103
84
|
stmt->svc = svc;
|
104
|
-
stmt->binds = rb_hash_new();
|
105
|
-
stmt->defns = rb_ary_new();
|
106
|
-
rb_ivar_set(stmt->base.self, id_at_column_metadata, rb_ary_new());
|
107
|
-
rb_ivar_set(stmt->base.self, id_at_names, Qnil);
|
108
|
-
rb_ivar_set(stmt->base.self, id_at_con, svc);
|
109
|
-
rb_ivar_set(stmt->base.self, id_at_max_array_size, Qnil);
|
110
85
|
|
111
86
|
oci8_link_to_parent((oci8_base_t*)stmt, (oci8_base_t*)DATA_PTR(svc));
|
112
87
|
return Qnil;
|
113
88
|
}
|
114
89
|
|
90
|
+
/*
|
91
|
+
* call-seq:
|
92
|
+
* __define(position, bindobj)
|
93
|
+
*
|
94
|
+
* @param [Integer] position
|
95
|
+
* @param [OCI8::BindType::Base] bindobj
|
96
|
+
*
|
97
|
+
* @private
|
98
|
+
*/
|
115
99
|
static VALUE oci8_define_by_pos(VALUE self, VALUE vposition, VALUE vbindobj)
|
116
100
|
{
|
117
101
|
oci8_stmt_t *stmt = TO_STMT(self);
|
@@ -141,16 +125,18 @@ static VALUE oci8_define_by_pos(VALUE self, VALUE vposition, VALUE vbindobj)
|
|
141
125
|
if (vptr->post_bind_hook != NULL) {
|
142
126
|
vptr->post_bind_hook(obind);
|
143
127
|
}
|
144
|
-
if (position - 1 < RARRAY_LEN(stmt->defns)) {
|
145
|
-
VALUE old_value = RARRAY_PTR(stmt->defns)[position - 1];
|
146
|
-
if (!NIL_P(old_value)) {
|
147
|
-
oci8_base_free((oci8_base_t*)oci8_get_bind(old_value));
|
148
|
-
}
|
149
|
-
}
|
150
|
-
rb_ary_store(stmt->defns, position - 1, obind->base.self);
|
151
128
|
return obind->base.self;
|
152
129
|
}
|
153
130
|
|
131
|
+
/*
|
132
|
+
* call-seq:
|
133
|
+
* __bind(placeholder, bindobj)
|
134
|
+
*
|
135
|
+
* @param [Integer, String or Symbol] placeholder
|
136
|
+
* @param [OCI8::BindType::Base] bindobj
|
137
|
+
*
|
138
|
+
* @private
|
139
|
+
*/
|
154
140
|
static VALUE oci8_bind(VALUE self, VALUE vplaceholder, VALUE vbindobj)
|
155
141
|
{
|
156
142
|
oci8_stmt_t *stmt = TO_STMT(self);
|
@@ -160,7 +146,6 @@ static VALUE oci8_bind(VALUE self, VALUE vplaceholder, VALUE vbindobj)
|
|
160
146
|
oci8_bind_t *obind;
|
161
147
|
const oci8_bind_vtable_t *vptr;
|
162
148
|
sword status;
|
163
|
-
VALUE old_value;
|
164
149
|
void *indp;
|
165
150
|
|
166
151
|
if (NIL_P(vplaceholder)) { /* 1 */
|
@@ -207,11 +192,6 @@ static VALUE oci8_bind(VALUE self, VALUE vplaceholder, VALUE vbindobj)
|
|
207
192
|
if (vptr->post_bind_hook != NULL) {
|
208
193
|
vptr->post_bind_hook(obind);
|
209
194
|
}
|
210
|
-
old_value = rb_hash_aref(stmt->binds, vplaceholder);
|
211
|
-
if (!NIL_P(old_value)) {
|
212
|
-
oci8_base_free((oci8_base_t*)oci8_get_bind(old_value));
|
213
|
-
}
|
214
|
-
rb_hash_aset(stmt->binds, vplaceholder, obind->base.self);
|
215
195
|
return obind->base.self;
|
216
196
|
}
|
217
197
|
|
@@ -232,59 +212,39 @@ static sword oci8_call_stmt_execute(oci8_svcctx_t *svcctx, oci8_stmt_t *stmt, ub
|
|
232
212
|
return rv;
|
233
213
|
}
|
234
214
|
|
215
|
+
/*
|
216
|
+
* call-seq:
|
217
|
+
* __execute(iteration_count)
|
218
|
+
*
|
219
|
+
* @param [Integer] iteration_count
|
220
|
+
*
|
221
|
+
* @private
|
222
|
+
*/
|
235
223
|
static VALUE oci8_stmt_execute(VALUE self, VALUE iteration_count)
|
236
224
|
{
|
237
225
|
oci8_stmt_t *stmt = TO_STMT(self);
|
238
226
|
oci8_svcctx_t *svcctx = oci8_get_svcctx(stmt->svc);
|
239
|
-
ub4 iters;
|
240
|
-
ub4 mode;
|
241
227
|
|
242
|
-
|
243
|
-
|
244
|
-
mode = OCI_DEFAULT;
|
245
|
-
} else {
|
246
|
-
if(!NIL_P(iteration_count))
|
247
|
-
iters = NUM2INT(iteration_count);
|
248
|
-
else
|
249
|
-
iters = 1;
|
250
|
-
mode = svcctx->is_autocommit ? OCI_COMMIT_ON_SUCCESS : OCI_DEFAULT;
|
251
|
-
}
|
252
|
-
chker3(oci8_call_stmt_execute(svcctx, stmt, iters, mode),
|
228
|
+
chker3(oci8_call_stmt_execute(svcctx, stmt, NUM2UINT(iteration_count),
|
229
|
+
svcctx->is_autocommit ? OCI_COMMIT_ON_SUCCESS : OCI_DEFAULT),
|
253
230
|
&stmt->base, stmt->base.hp.stmt);
|
254
231
|
return self;
|
255
232
|
}
|
256
233
|
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
return Qnil;
|
268
|
-
}
|
269
|
-
|
270
|
-
static VALUE oci8_stmt_clear_binds(VALUE self)
|
234
|
+
/*
|
235
|
+
* call-seq:
|
236
|
+
* __fetch(connection)
|
237
|
+
*
|
238
|
+
* @param [OCI8] connection
|
239
|
+
* @return [true or false] true on success and false when all rows are fetched.
|
240
|
+
*
|
241
|
+
* @private
|
242
|
+
*/
|
243
|
+
static VALUE oci8_stmt_fetch(VALUE self, VALUE svc)
|
271
244
|
{
|
272
245
|
oci8_stmt_t *stmt = TO_STMT(self);
|
273
|
-
|
274
|
-
if(!RTEST(rb_funcall(stmt->binds, id_empty_p, 0)))
|
275
|
-
{
|
276
|
-
rb_iterate(each_value, stmt->binds, clear_binds_iterator_proc, Qnil);
|
277
|
-
rb_funcall(stmt->binds,id_clear,0);
|
278
|
-
}
|
279
|
-
|
280
|
-
return self;
|
281
|
-
}
|
282
|
-
|
283
|
-
static VALUE oci8_stmt_do_fetch(oci8_stmt_t *stmt, oci8_svcctx_t *svcctx)
|
284
|
-
{
|
285
|
-
VALUE ary;
|
246
|
+
oci8_svcctx_t *svcctx = oci8_get_svcctx(svc);
|
286
247
|
sword rv;
|
287
|
-
long idx;
|
288
248
|
oci8_bind_t *obind;
|
289
249
|
const oci8_bind_vtable_t *vptr;
|
290
250
|
|
@@ -302,46 +262,21 @@ static VALUE oci8_stmt_do_fetch(oci8_stmt_t *stmt, oci8_svcctx_t *svcctx)
|
|
302
262
|
}
|
303
263
|
rv = OCIStmtFetch_nb(svcctx, stmt->base.hp.stmt, oci8_errhp, 1, OCI_FETCH_NEXT, OCI_DEFAULT);
|
304
264
|
if (rv == OCI_NO_DATA) {
|
305
|
-
return
|
265
|
+
return Qfalse;
|
306
266
|
}
|
307
267
|
chker3(rv, &svcctx->base, stmt->base.hp.stmt);
|
308
|
-
|
309
|
-
for (idx = 0; idx < RARRAY_LEN(stmt->defns); idx++) {
|
310
|
-
rb_ary_store(ary, idx, oci8_bind_get_data(RARRAY_PTR(stmt->defns)[idx]));
|
311
|
-
}
|
312
|
-
return ary;
|
268
|
+
return Qtrue;
|
313
269
|
}
|
314
270
|
|
315
271
|
/*
|
316
|
-
*
|
317
|
-
*
|
272
|
+
* call-seq:
|
273
|
+
* __paramGet(pos)
|
274
|
+
*
|
275
|
+
* @param [Fixnum] pos Column position which starts from one
|
276
|
+
* @return [OCI8::Metadata::Base]
|
318
277
|
*
|
319
|
-
*
|
320
|
-
* conn = OCI8.new('scott', 'tiger')
|
321
|
-
* cursor = conn.exec('SELECT * FROM emp')
|
322
|
-
* while r = cursor.fetch()
|
323
|
-
* puts r.join(',')
|
324
|
-
* end
|
325
|
-
* cursor.close
|
326
|
-
* conn.logoff
|
278
|
+
* @private
|
327
279
|
*/
|
328
|
-
static VALUE oci8_stmt_fetch(VALUE self)
|
329
|
-
{
|
330
|
-
oci8_stmt_t *stmt = TO_STMT(self);
|
331
|
-
oci8_svcctx_t *svcctx = oci8_get_svcctx(stmt->svc);
|
332
|
-
|
333
|
-
if (rb_block_given_p()) {
|
334
|
-
for (;;) {
|
335
|
-
VALUE rs = oci8_stmt_do_fetch(stmt, svcctx);
|
336
|
-
if (NIL_P(rs))
|
337
|
-
return self; /* NEED TO CHECK 0.1 behavior. */
|
338
|
-
rb_yield(rs);
|
339
|
-
}
|
340
|
-
} else {
|
341
|
-
return oci8_stmt_do_fetch(stmt, svcctx);
|
342
|
-
}
|
343
|
-
}
|
344
|
-
|
345
280
|
static VALUE oci8_stmt_get_param(VALUE self, VALUE pos)
|
346
281
|
{
|
347
282
|
oci8_stmt_t *stmt = TO_STMT(self);
|
@@ -357,73 +292,15 @@ static VALUE oci8_stmt_get_param(VALUE self, VALUE pos)
|
|
357
292
|
}
|
358
293
|
|
359
294
|
/*
|
360
|
-
*
|
361
|
-
* * OCI8::STMT_SELECT
|
362
|
-
* * OCI8::STMT_UPDATE
|
363
|
-
* * OCI8::STMT_DELETE
|
364
|
-
* * OCI8::STMT_INSERT
|
365
|
-
* * OCI8::STMT_CREATE
|
366
|
-
* * OCI8::STMT_DROP
|
367
|
-
* * OCI8::STMT_ALTER
|
368
|
-
* * OCI8::STMT_BEGIN (PL/SQL block which starts with a BEGIN keyword)
|
369
|
-
* * OCI8::STMT_DECLARE (PL/SQL block which starts with a DECLARE keyword)
|
370
|
-
* * Other Fixnum value undocumented in Oracle manuals.
|
371
|
-
*
|
372
|
-
* <em>Changes between ruby-oci8 1.0 and 2.0.</em>
|
373
|
-
*
|
374
|
-
* [ruby-oci8 2.0] OCI8::STMT_* are Symbols. (:select_stmt, :update_stmt, etc.)
|
375
|
-
* [ruby-oci8 1.0] OCI8::STMT_* are Fixnums. (1, 2, 3, etc.)
|
376
|
-
*/
|
377
|
-
static VALUE oci8_stmt_get_stmt_type(VALUE self)
|
378
|
-
{
|
379
|
-
oci8_base_t *base = oci8_get_handle(self, cOCIStmt);
|
380
|
-
VALUE stmt_type = oci8_get_ub2_attr(base, OCI_ATTR_STMT_TYPE, base->hp.stmt);
|
381
|
-
switch (FIX2INT(stmt_type)) {
|
382
|
-
case OCI_STMT_SELECT:
|
383
|
-
return oci8_sym_select_stmt;
|
384
|
-
case OCI_STMT_UPDATE:
|
385
|
-
return oci8_sym_update_stmt;
|
386
|
-
case OCI_STMT_DELETE:
|
387
|
-
return oci8_sym_delete_stmt;
|
388
|
-
case OCI_STMT_INSERT:
|
389
|
-
return oci8_sym_insert_stmt;
|
390
|
-
case OCI_STMT_CREATE:
|
391
|
-
return oci8_sym_create_stmt;
|
392
|
-
case OCI_STMT_DROP:
|
393
|
-
return oci8_sym_drop_stmt;
|
394
|
-
case OCI_STMT_ALTER:
|
395
|
-
return oci8_sym_alter_stmt;
|
396
|
-
case OCI_STMT_BEGIN:
|
397
|
-
return oci8_sym_begin_stmt;
|
398
|
-
case OCI_STMT_DECLARE:
|
399
|
-
return oci8_sym_declare_stmt;
|
400
|
-
default:
|
401
|
-
return stmt_type;
|
402
|
-
}
|
403
|
-
}
|
404
|
-
|
405
|
-
/*
|
406
|
-
* Returns the number of processed rows.
|
407
|
-
*/
|
408
|
-
static VALUE oci8_stmt_get_row_count(VALUE self)
|
409
|
-
{
|
410
|
-
oci8_base_t *base = oci8_get_handle(self, cOCIStmt);
|
411
|
-
return oci8_get_ub4_attr(base, OCI_ATTR_ROW_COUNT, base->hp.stmt);
|
412
|
-
}
|
413
|
-
|
414
|
-
/*
|
415
|
-
* Get the rowid of the last inserted/updated/deleted row.
|
295
|
+
* Get the rowid of the last inserted, updated or deleted row.
|
416
296
|
* This cannot be used for select statements.
|
417
297
|
*
|
418
|
-
* example
|
298
|
+
* @example
|
419
299
|
* cursor = conn.parse('INSERT INTO foo_table values(:1, :2)', 1, 2)
|
420
300
|
* cursor.exec
|
421
|
-
* cursor.rowid # => the inserted row's rowid
|
301
|
+
* cursor.rowid # => "AAAFlLAAEAAAAG9AAA", the inserted row's rowid
|
422
302
|
*
|
423
|
-
*
|
424
|
-
*
|
425
|
-
* [ruby-oci8 1.0.4 or upper] The return value is a String.
|
426
|
-
* [ruby-oci8 1.0.3 or lower] It returns an OCIRowid object.
|
303
|
+
* @return [String]
|
427
304
|
*/
|
428
305
|
static VALUE oci8_stmt_get_rowid(VALUE self)
|
429
306
|
{
|
@@ -431,158 +308,6 @@ static VALUE oci8_stmt_get_rowid(VALUE self)
|
|
431
308
|
return oci8_get_rowid_attr(base, OCI_ATTR_ROWID, base->hp.stmt);
|
432
309
|
}
|
433
310
|
|
434
|
-
static VALUE oci8_stmt_get_param_count(VALUE self)
|
435
|
-
{
|
436
|
-
oci8_base_t *base = oci8_get_handle(self, cOCIStmt);
|
437
|
-
return oci8_get_ub4_attr(base, OCI_ATTR_PARAM_COUNT, base->hp.stmt);
|
438
|
-
}
|
439
|
-
|
440
|
-
/*
|
441
|
-
* call-seq:
|
442
|
-
* [key]
|
443
|
-
*
|
444
|
-
* Gets the value of the bind variable.
|
445
|
-
*
|
446
|
-
* In case of binding explicitly, use same key with that of
|
447
|
-
* OCI8::Cursor#bind_param. A placeholder can be bound by
|
448
|
-
* name or position. If you bind by name, use that name. If you bind
|
449
|
-
* by position, use the position.
|
450
|
-
*
|
451
|
-
* example:
|
452
|
-
* cursor = conn.parse("BEGIN :out := 'BAR'; END;")
|
453
|
-
* cursor.bind_param(':out', 'FOO') # bind by name
|
454
|
-
* p cursor[':out'] # => 'FOO'
|
455
|
-
* p cursor[1] # => nil
|
456
|
-
* cursor.exec()
|
457
|
-
* p cursor[':out'] # => 'BAR'
|
458
|
-
* p cursor[1] # => nil
|
459
|
-
*
|
460
|
-
* example:
|
461
|
-
* cursor = conn.parse("BEGIN :out := 'BAR'; END;")
|
462
|
-
* cursor.bind_param(1, 'FOO') # bind by position
|
463
|
-
* p cursor[':out'] # => nil
|
464
|
-
* p cursor[1] # => 'FOO'
|
465
|
-
* cursor.exec()
|
466
|
-
* p cursor[':out'] # => nil
|
467
|
-
* p cursor[1] # => 'BAR'
|
468
|
-
*
|
469
|
-
* In case of binding by OCI8#exec or OCI8::Cursor#exec,
|
470
|
-
* get the value by position, which starts from 1.
|
471
|
-
*
|
472
|
-
* example:
|
473
|
-
* cursor = conn.exec("BEGIN :out := 'BAR'; END;", 'FOO')
|
474
|
-
* # 1st bind variable is bound as String with width 3. Its initial value is 'FOO'
|
475
|
-
* # After execute, the value become 'BAR'.
|
476
|
-
* p cursor[1] # => 'BAR'
|
477
|
-
*/
|
478
|
-
static VALUE oci8_stmt_aref(VALUE self, VALUE key)
|
479
|
-
{
|
480
|
-
oci8_stmt_t *stmt = TO_STMT(self);
|
481
|
-
VALUE obj = rb_hash_aref(stmt->binds, key);
|
482
|
-
if (NIL_P(obj)) {
|
483
|
-
return Qnil;
|
484
|
-
}
|
485
|
-
return oci8_bind_get_data(obj);
|
486
|
-
}
|
487
|
-
|
488
|
-
/*
|
489
|
-
* call-seq:
|
490
|
-
* [key] = val
|
491
|
-
*
|
492
|
-
* Sets the value to the bind variable. The way to specify the
|
493
|
-
* +key+ is same with OCI8::Cursor#[]. This is available
|
494
|
-
* to replace the value and execute many times.
|
495
|
-
*
|
496
|
-
* example1:
|
497
|
-
* cursor = conn.parse("INSERT INTO test(col1) VALUES(:1)")
|
498
|
-
* cursor.bind_params(1, nil, String, 3)
|
499
|
-
* ['FOO', 'BAR', 'BAZ'].each do |key|
|
500
|
-
* cursor[1] = key
|
501
|
-
* cursor.exec
|
502
|
-
* end
|
503
|
-
* cursor.close()
|
504
|
-
*
|
505
|
-
* example2:
|
506
|
-
* ['FOO', 'BAR', 'BAZ'].each do |key|
|
507
|
-
* conn.exec("INSERT INTO test(col1) VALUES(:1)", key)
|
508
|
-
* end
|
509
|
-
*
|
510
|
-
* Both example's results are same. But the former will use less resources.
|
511
|
-
*/
|
512
|
-
static VALUE oci8_stmt_aset(VALUE self, VALUE key, VALUE val)
|
513
|
-
{
|
514
|
-
long max_array_size;
|
515
|
-
long actual_array_size;
|
516
|
-
long bind_array_size;
|
517
|
-
|
518
|
-
oci8_stmt_t *stmt = TO_STMT(self);
|
519
|
-
VALUE obj = rb_hash_aref(stmt->binds, key);
|
520
|
-
if (NIL_P(obj)) {
|
521
|
-
return Qnil; /* ?? MUST BE ERROR? */
|
522
|
-
}
|
523
|
-
|
524
|
-
if(TYPE(val) == T_ARRAY) {
|
525
|
-
max_array_size = NUM2INT(rb_ivar_get(self, id_at_max_array_size));
|
526
|
-
actual_array_size = NUM2INT(rb_ivar_get(self, id_at_actual_array_size));
|
527
|
-
bind_array_size = RARRAY_LEN(val);
|
528
|
-
|
529
|
-
if(actual_array_size > 0 && bind_array_size != actual_array_size) {
|
530
|
-
rb_raise(rb_eRuntimeError, "all binding arrays hould be the same size");
|
531
|
-
}
|
532
|
-
if(bind_array_size <= max_array_size && actual_array_size == 0) {
|
533
|
-
rb_ivar_set(self, id_at_actual_array_size, INT2NUM(bind_array_size));
|
534
|
-
}
|
535
|
-
}
|
536
|
-
oci8_bind_set_data(obj, val);
|
537
|
-
return val;
|
538
|
-
}
|
539
|
-
|
540
|
-
/*
|
541
|
-
* call-seq:
|
542
|
-
* keys -> an Array
|
543
|
-
*
|
544
|
-
* Returns the keys of bind variables as array.
|
545
|
-
*/
|
546
|
-
static VALUE oci8_stmt_keys(VALUE self)
|
547
|
-
{
|
548
|
-
oci8_stmt_t *stmt = TO_STMT(self);
|
549
|
-
return rb_funcall(stmt->binds, oci8_id_keys, 0);
|
550
|
-
}
|
551
|
-
|
552
|
-
static VALUE oci8_stmt_defined_p(VALUE self, VALUE pos)
|
553
|
-
{
|
554
|
-
oci8_stmt_t *stmt = TO_STMT(self);
|
555
|
-
long position = NUM2INT(pos);
|
556
|
-
|
557
|
-
if (position - 1 < RARRAY_LEN(stmt->defns)) {
|
558
|
-
VALUE value = RARRAY_PTR(stmt->defns)[position - 1];
|
559
|
-
if (!NIL_P(value)) {
|
560
|
-
return Qtrue;
|
561
|
-
}
|
562
|
-
}
|
563
|
-
return Qfalse;
|
564
|
-
}
|
565
|
-
|
566
|
-
/*
|
567
|
-
* call-seq:
|
568
|
-
* prefetch_rows = aFixnum
|
569
|
-
*
|
570
|
-
* Set number of rows to be prefetched.
|
571
|
-
* This can reduce the number of network round trips when fetching
|
572
|
-
* many rows. The default value is one.
|
573
|
-
*
|
574
|
-
* FYI: Rails oracle adaptor uses 100 by default.
|
575
|
-
*/
|
576
|
-
static VALUE oci8_stmt_set_prefetch_rows(VALUE self, VALUE rows)
|
577
|
-
{
|
578
|
-
oci8_stmt_t *stmt = TO_STMT(self);
|
579
|
-
ub4 num = NUM2UINT(rows);
|
580
|
-
|
581
|
-
chker2(OCIAttrSet(stmt->base.hp.ptr, OCI_HTYPE_STMT, &num, 0, OCI_ATTR_PREFETCH_ROWS, oci8_errhp),
|
582
|
-
&stmt->base);
|
583
|
-
return Qfalse;
|
584
|
-
}
|
585
|
-
|
586
311
|
/*
|
587
312
|
* bind_stmt
|
588
313
|
*/
|
@@ -646,40 +371,13 @@ void Init_oci8_stmt(VALUE cOCI8)
|
|
646
371
|
#endif
|
647
372
|
cOCIStmt = oci8_define_class_under(cOCI8, "Cursor", &oci8_stmt_vtable);
|
648
373
|
|
649
|
-
|
650
|
-
oci8_sym_update_stmt = ID2SYM(rb_intern("update_stmt"));
|
651
|
-
oci8_sym_delete_stmt = ID2SYM(rb_intern("delete_stmt"));
|
652
|
-
oci8_sym_insert_stmt = ID2SYM(rb_intern("insert_stmt"));
|
653
|
-
oci8_sym_create_stmt = ID2SYM(rb_intern("create_stmt"));
|
654
|
-
oci8_sym_drop_stmt = ID2SYM(rb_intern("drop_stmt"));
|
655
|
-
oci8_sym_alter_stmt = ID2SYM(rb_intern("alter_stmt"));
|
656
|
-
oci8_sym_begin_stmt = ID2SYM(rb_intern("begin_stmt"));
|
657
|
-
oci8_sym_declare_stmt = ID2SYM(rb_intern("declare_stmt"));
|
658
|
-
id_at_column_metadata = rb_intern("@column_metadata");
|
659
|
-
id_at_actual_array_size = rb_intern("@actual_array_size");
|
660
|
-
id_at_max_array_size = rb_intern("@max_array_size");
|
661
|
-
id_each_value = rb_intern("each_value");
|
662
|
-
id_at_names = rb_intern("@names");
|
663
|
-
id_at_con = rb_intern("@con");
|
664
|
-
id_empty_p = rb_intern("empty?");
|
665
|
-
id_clear = rb_intern("clear");
|
666
|
-
|
667
|
-
rb_define_private_method(cOCIStmt, "initialize", oci8_stmt_initialize, -1);
|
374
|
+
rb_define_private_method(cOCIStmt, "__initialize", oci8_stmt_initialize, 2);
|
668
375
|
rb_define_private_method(cOCIStmt, "__define", oci8_define_by_pos, 2);
|
669
376
|
rb_define_private_method(cOCIStmt, "__bind", oci8_bind, 2);
|
670
377
|
rb_define_private_method(cOCIStmt, "__execute", oci8_stmt_execute, 1);
|
671
|
-
rb_define_private_method(cOCIStmt, "
|
672
|
-
rb_define_method(cOCIStmt, "fetch", oci8_stmt_fetch, 0);
|
378
|
+
rb_define_private_method(cOCIStmt, "__fetch", oci8_stmt_fetch, 1);
|
673
379
|
rb_define_private_method(cOCIStmt, "__paramGet", oci8_stmt_get_param, 1);
|
674
|
-
rb_define_method(cOCIStmt, "type", oci8_stmt_get_stmt_type, 0);
|
675
|
-
rb_define_method(cOCIStmt, "row_count", oci8_stmt_get_row_count, 0);
|
676
380
|
rb_define_method(cOCIStmt, "rowid", oci8_stmt_get_rowid, 0);
|
677
|
-
rb_define_private_method(cOCIStmt, "__param_count", oci8_stmt_get_param_count, 0);
|
678
|
-
rb_define_method(cOCIStmt, "[]", oci8_stmt_aref, 1);
|
679
|
-
rb_define_method(cOCIStmt, "[]=", oci8_stmt_aset, 2);
|
680
|
-
rb_define_method(cOCIStmt, "keys", oci8_stmt_keys, 0);
|
681
|
-
rb_define_private_method(cOCIStmt, "__defined?", oci8_stmt_defined_p, 1);
|
682
|
-
rb_define_method(cOCIStmt, "prefetch_rows=", oci8_stmt_set_prefetch_rows, 1);
|
683
381
|
|
684
382
|
oci8_define_bind_class("Cursor", &bind_stmt_vtable);
|
685
383
|
}
|