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.
@@ -2,7 +2,7 @@
2
2
  /*
3
3
  * oci8.h - part of ruby-oci8
4
4
  *
5
- * Copyright (C) 2002-2011 KUBO Takehiro <kubo@jiubao.org>
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
- #define RB_GC_GUARD(v) (*(volatile VALUE *)&(v))
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(HAVE_NATIVETHREAD) || defined(HAVE_RB_THREAD_BLOCKING_REGION)
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 /* HAVE_RB_THREAD_BLOCKING_REGION */
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 HAVE_RB_THREAD_BLOCKING_REGION
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
- rb_blocking_function_t *execute;
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 oci8_blocking_region(oci8_svcctx_t *svcctx, rb_blocking_function_t func, void *data);
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
- VALUE Init_oci8(void);
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 */
@@ -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
- cOCI8 = Init_oci8();
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 HAVE_RB_THREAD_BLOCKING_REGION
205
+ #ifdef NATIVE_THREAD_WITH_GVL
205
206
 
206
- #if 0
207
- typedef struct {
208
- dvoid *hndlp;
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
- } ocibreak_arg_t;
217
+ OCILobLocator *lob;
218
+ } free_temp_lob_arg_t;
211
219
 
212
- static VALUE call_OCIBreak(void *user_data)
220
+ static void *free_temp_lob(void *user_data)
213
221
  {
214
- ocibreak_arg_t *arg = (ocibreak_arg_t *)user_data;
215
- OCIBreak(arg->hndlp, arg->errhp);
216
- return Qnil;
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
- static void oci8_unblock_func(void *user_data)
229
+ /* ruby 1.9 */
230
+ sword oci8_call_without_gvl(oci8_svcctx_t *svcctx, void *(*func)(void *), void *data)
220
231
  {
221
- oci8_svcctx_t *svcctx = (oci8_svcctx_t *)user_data;
222
- if (svcctx->base.hp.ptr != NULL) {
223
- ocibreak_arg_t arg;
224
- arg.hndlp = svcctx->base.hp.ptr;
225
- arg.errhp = oci8_errhp;
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
- static void oci8_unblock_func(void *user_data)
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
- rv = (sword)rb_thread_blocking_region(func, data, oci8_unblock_func, svcctx);
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(oci8_errhp) == 1013) {
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 /* HAVE_RB_THREAD_BLOCKING_REGION */
292
+ #else /* NATIVE_THREAD_WITH_GVL */
260
293
 
261
294
  /* ruby 1.8 */
262
295
  typedef struct {
263
296
  oci8_svcctx_t *svcctx;
264
- rb_blocking_function_t *func;
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
- rb_blocking_function_t *func = arg->func;
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 oci8_blocking_region(oci8_svcctx_t *svcctx, rb_blocking_function_t func, void *data)
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 /* HAVE_RB_THREAD_BLOCKING_REGION */
351
+ #endif /* NATIVE_THREAD_WITH_GVL */
319
352
 
320
353
  typedef struct {
321
354
  oci8_svcctx_t *svcctx;
@@ -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
- OCINumber *value;
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
- return oci8_make_integer(v.value, oci8_errhp);
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
  /*
@@ -32,7 +32,7 @@ static ID id_denominator;
32
32
  static ID id_Rational;
33
33
  static ID id_BigDecimal;
34
34
 
35
- #ifndef T_RATIONAL
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 T_RATIONAL
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 T_RATIONAL
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 {Integer} when <i>decplace</i> is not specified.
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 T_RATIONAL
1438
+ #ifdef rb_Rational2
1439
1439
  return rb_Rational(x, y);
1440
1440
  #else
1441
1441
  if (!cRational) {
@@ -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-2010 KUBO Takehiro <kubo@jiubao.org>
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
- static VALUE oci8_stmt_initialize(int argc, VALUE *argv, VALUE self)
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 (argc > 1 && oracle_client_version >= ORAVER_9_2) {
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 (argc > 1) {
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
- if (oci8_get_ub2_attr(&stmt->base, OCI_ATTR_STMT_TYPE, stmt->base.hp.stmt) == INT2FIX(OCI_STMT_SELECT)) {
243
- iters = 0;
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
- static VALUE each_value(VALUE obj)
258
- {
259
- return rb_funcall(obj, id_each_value, 0);
260
- }
261
-
262
- static VALUE clear_binds_iterator_proc(VALUE val, VALUE arg)
263
- {
264
- if(!NIL_P(val)) {
265
- oci8_base_free((oci8_base_t*)oci8_get_bind(val));
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 Qnil;
265
+ return Qfalse;
306
266
  }
307
267
  chker3(rv, &svcctx->base, stmt->base.hp.stmt);
308
- ary = rb_ary_new2(RARRAY_LEN(stmt->defns));
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
- * Gets fetched data as array. This is available for select
317
- * statement only.
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
- * example:
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
- * gets the type of SQL statement as follows.
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
- * <em>Changes between ruby-oci8 1.0.3 and 1.0.4.</em>
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
- oci8_sym_select_stmt = ID2SYM(rb_intern("select_stmt"));
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, "__clearBinds", oci8_stmt_clear_binds, 0);
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
  }