ruby-oci8 2.1.2 → 2.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
}
|