ruby-oci8 2.0.6 → 2.1.0

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.
Files changed (59) hide show
  1. data/ChangeLog +366 -19
  2. data/Makefile +2 -8
  3. data/NEWS +111 -0
  4. data/README +4 -85
  5. data/VERSION +1 -1
  6. data/dist-files +9 -2
  7. data/ext/oci8/.document +1 -0
  8. data/ext/oci8/apiwrap.c.tmpl +12 -2
  9. data/ext/oci8/apiwrap.yml +37 -21
  10. data/ext/oci8/attr.c +23 -74
  11. data/ext/oci8/bind.c +93 -225
  12. data/ext/oci8/connection_pool.c +201 -0
  13. data/ext/oci8/encoding.c +117 -24
  14. data/ext/oci8/env.c +5 -10
  15. data/ext/oci8/error.c +171 -189
  16. data/ext/oci8/extconf.rb +6 -2
  17. data/ext/oci8/lob.c +81 -79
  18. data/ext/oci8/metadata.c +42 -177
  19. data/ext/oci8/object.c +55 -28
  20. data/ext/oci8/oci8.c +426 -294
  21. data/ext/oci8/oci8.h +84 -51
  22. data/ext/oci8/oci8lib.c +75 -53
  23. data/ext/oci8/ocidatetime.c +67 -88
  24. data/ext/oci8/ocihandle.c +78 -37
  25. data/ext/oci8/ocinumber.c +166 -109
  26. data/ext/oci8/oraconf.rb +68 -157
  27. data/ext/oci8/oradate.c +2 -7
  28. data/ext/oci8/stmt.c +40 -183
  29. data/ext/oci8/thread_util.c +85 -0
  30. data/ext/oci8/thread_util.h +30 -0
  31. data/lib/oci8.rb.in +19 -13
  32. data/lib/oci8/.document +2 -0
  33. data/lib/oci8/bindtype.rb +62 -45
  34. data/lib/oci8/connection_pool.rb +118 -0
  35. data/lib/oci8/datetime.rb +304 -320
  36. data/lib/oci8/encoding-init.rb +62 -30
  37. data/lib/oci8/encoding.yml +3 -3
  38. data/lib/oci8/metadata.rb +552 -497
  39. data/lib/oci8/object.rb +9 -9
  40. data/lib/oci8/oci8.rb +161 -2
  41. data/lib/oci8/ocihandle.rb +427 -0
  42. data/lib/oci8/properties.rb +31 -1
  43. data/ruby-oci8.gemspec +10 -3
  44. data/test/README +41 -3
  45. data/test/config.rb +16 -0
  46. data/test/test_all.rb +3 -0
  47. data/test/test_bind_string.rb +106 -0
  48. data/test/test_break.rb +33 -7
  49. data/test/test_clob.rb +13 -10
  50. data/test/test_connection_pool.rb +125 -0
  51. data/test/test_connstr.rb +2 -2
  52. data/test/test_datetime.rb +26 -66
  53. data/test/test_encoding.rb +7 -3
  54. data/test/test_error.rb +88 -0
  55. data/test/test_metadata.rb +1356 -204
  56. data/test/test_oci8.rb +27 -8
  57. data/test/test_oranumber.rb +41 -0
  58. metadata +34 -9
  59. data/ext/oci8/xmldb.c +0 -383
@@ -29,9 +29,6 @@ extern "C"
29
29
  #ifdef __cplusplus
30
30
  }
31
31
  #endif
32
- #ifdef HAVE_XMLOTN_H
33
- #include "xmlotn.h"
34
- #endif
35
32
 
36
33
  #define ORAVERNUM(major, minor, update, patch, port_update) \
37
34
  (((major) << 24) | ((minor) << 20) | ((update) << 12) | ((patch) << 8) | (port_update))
@@ -93,9 +90,15 @@ typedef sb4 (*OCICallbackLobWrite2)(dvoid *ctxp, dvoid *bufp, oraub8 *lenp,
93
90
  #if !defined HAVE_TYPE_OCIADMIN_ && !defined HAVE_TYPE_OCIADMINP
94
91
  typedef struct OCIAdmin OCIAdmin;
95
92
  #endif
93
+ #if !defined HAVE_TYPE_OCIAUTHINFO_ && !defined HAVE_TYPE_OCIAUTHINFOP
94
+ typedef struct OCIAuthInfo OCIAuthInfo;
95
+ #endif
96
96
  #if !defined HAVE_TYPE_OCIMSG_ && !defined HAVE_TYPE_OCIMSGP
97
97
  typedef struct OCIMsg OCIMsg;
98
98
  #endif
99
+ #if !defined HAVE_TYPE_OCICPOOL_ && !defined HAVE_TYPE_OCICPOOLP
100
+ typedef struct OCICPool OCICPool;
101
+ #endif
99
102
 
100
103
  /* new macros in ruby 1.8.6.
101
104
  * define compatible macros for ruby 1.8.5 or lower.
@@ -132,7 +135,7 @@ typedef struct OCIMsg OCIMsg;
132
135
  #if !defined(HAVE_RB_ERRINFO) && defined(HAVE_RUBY_ERRINFO)
133
136
  #define rb_errinfo() ruby_errinfo
134
137
  #endif
135
- #ifndef HAVE_TYPE_RB_BLOCKING_FUNCTION_T
138
+ #if !defined HAVE_TYPE_RB_BLOCKING_FUNCTION_T_ && !defined HAVE_TYPE_RB_BLOCKING_FUNCTION_TP
136
139
  typedef VALUE rb_blocking_function_t(void *);
137
140
  #endif
138
141
 
@@ -157,6 +160,14 @@ typedef VALUE rb_blocking_function_t(void *);
157
160
  #endif
158
161
  #endif
159
162
 
163
+ #if defined(HAVE_NATIVETHREAD) || defined(HAVE_RB_THREAD_BLOCKING_REGION)
164
+ /*
165
+ * oci8_errhp is a thread local object in ruby 1.9, rubinius
166
+ * and ruby 1.8 configured with --enable-pthread.
167
+ */
168
+ #define USE_THREAD_LOCAL_ERRHP 1
169
+ #endif
170
+
160
171
  /* macros depends on the compiler.
161
172
  * LIKELY(x) hint for the compiler that 'x' is 1(TRUE) in many cases.
162
173
  * UNLIKELY(x) hint for the compiler that 'x' is 0(FALSE) in many cases.
@@ -189,8 +200,8 @@ typedef VALUE rb_blocking_function_t(void *);
189
200
  * set a value to the key.
190
201
  *
191
202
  */
192
- #ifdef HAVE_RB_THREAD_BLOCKING_REGION
193
- /* ruby 1.9 */
203
+ #ifdef USE_THREAD_LOCAL_ERRHP
204
+ /* rubies with native-thread support. */
194
205
  #if defined(_WIN32)
195
206
  #include <windows.h>
196
207
  #define oci8_tls_key_t DWORD
@@ -209,17 +220,23 @@ typedef VALUE rb_blocking_function_t(void *);
209
220
  #define IS_OCI_ERROR(v) (((v) != OCI_SUCCESS) && ((v) != OCI_SUCCESS_WITH_INFO))
210
221
  #ifdef ALWAYS_INLINE
211
222
  #define TO_ORATEXT to_oratext
223
+ #define TO_CONST_ORATEXT to_const_oratext
212
224
  #define TO_CHARPTR to_charptr
213
225
  static ALWAYS_INLINE OraText *to_oratext(char *c)
214
226
  {
215
227
  return (OraText*)c;
216
228
  }
229
+ static ALWAYS_INLINE const OraText *to_const_oratext(const char *c)
230
+ {
231
+ return (const OraText*)c;
232
+ }
217
233
  static ALWAYS_INLINE char *to_charptr(OraText *c)
218
234
  {
219
235
  return (char*)c;
220
236
  }
221
237
  #else
222
238
  #define TO_ORATEXT(c) ((OraText*)(c))
239
+ #define TO_CONST_ORATEXT(c) ((const OraText*)(c))
223
240
  #define TO_CHARPTR(c) ((char*)(c))
224
241
  #endif
225
242
  #define RSTRING_ORATEXT(obj) TO_ORATEXT(RSTRING_PTR(obj))
@@ -237,36 +254,47 @@ typedef struct {
237
254
  char buf[1];
238
255
  } oci8_vstr_t;
239
256
 
240
- typedef struct oci8_base_class oci8_base_class_t;
241
- typedef struct oci8_bind_class oci8_bind_class_t;
257
+ typedef struct oci8_base_vtable oci8_base_vtable_t;
258
+ typedef struct oci8_bind_vtable oci8_bind_vtable_t;
242
259
 
243
260
  typedef struct oci8_base oci8_base_t;
244
261
  typedef struct oci8_bind oci8_bind_t;
245
262
 
246
- struct oci8_base_class {
263
+ /* The virtual method table of oci8_base_t */
264
+ struct oci8_base_vtable {
247
265
  void (*mark)(oci8_base_t *base);
248
266
  void (*free)(oci8_base_t *base);
249
267
  size_t size;
268
+ void (*init)(oci8_base_t *base);
250
269
  };
251
270
 
252
- struct oci8_bind_class {
253
- oci8_base_class_t base;
271
+ /* The virtual method table of oci8_bind_t */
272
+ struct oci8_bind_vtable {
273
+ oci8_base_vtable_t base;
254
274
  VALUE (*get)(oci8_bind_t *obind, void *data, void *null_struct);
255
275
  void (*set)(oci8_bind_t *obind, void *data, void **null_structp, VALUE val);
256
276
  void (*init)(oci8_bind_t *obind, VALUE svc, VALUE val, VALUE length);
257
277
  void (*init_elem)(oci8_bind_t *obind, VALUE svc);
258
- ub1 (*in)(oci8_bind_t *obind, ub4 idx, ub1 piece, void **valuepp, ub4 **alenpp, void **indpp);
259
- void (*out)(oci8_bind_t *obind, ub4 idx, ub1 piece, void **valuepp, ub4 **alenpp, void **indpp);
260
278
  void (*pre_fetch_hook)(oci8_bind_t *obind, VALUE svc);
261
279
  ub2 dty;
262
- ub1 csfrm;
280
+ void (*post_bind_hook)(oci8_bind_t *obind);
263
281
  };
264
282
 
283
+ /* Class structure implemented by C language.
284
+ * oci8_base_t represents OCIHandle and its subclasses.
285
+ *
286
+ * The vptr member points to a virtual method table.
287
+ * See: http://en.wikipedia.org/wiki/Virtual_method_table
288
+ */
265
289
  struct oci8_base {
290
+ const oci8_base_vtable_t *vptr;
266
291
  ub4 type;
267
292
  union {
268
293
  dvoid *ptr;
269
294
  OCISvcCtx *svc;
295
+ OCICPool *poolhp;
296
+ OCIServer *srvhp;
297
+ OCISession *usrhp;
270
298
  OCIStmt *stmt;
271
299
  OCIDefine *dfn;
272
300
  OCIBind *bnd;
@@ -276,13 +304,18 @@ struct oci8_base {
276
304
  OCIDescribe *dschp;
277
305
  } hp;
278
306
  VALUE self;
279
- const oci8_base_class_t *klass;
280
307
  oci8_base_t *parent;
281
308
  oci8_base_t *next;
282
309
  oci8_base_t *prev;
283
310
  oci8_base_t *children;
284
311
  };
285
312
 
313
+ /* Class structure implemented by C language.
314
+ * This represents OCI8::BindType::Base's subclasses.
315
+ *
316
+ * This is a subclass of oci8_base_t because the first member
317
+ * base is oci8_base_t itself.
318
+ */
286
319
  struct oci8_bind {
287
320
  oci8_base_t base;
288
321
  void *valuep;
@@ -298,15 +331,16 @@ struct oci8_bind {
298
331
  } u;
299
332
  };
300
333
 
301
- enum logon_type_t {T_NOT_LOGIN = 0, T_IMPLICIT, T_EXPLICIT};
334
+ typedef struct oci8_logoff_strategy oci8_logoff_strategy_t;
302
335
 
303
- typedef struct {
336
+ typedef struct oci8_svcctx {
304
337
  oci8_base_t base;
305
338
  volatile VALUE executing_thread;
306
- enum logon_type_t logon_type;
307
- OCISession *authhp;
339
+ const oci8_logoff_strategy_t *logoff_strategy;
340
+ OCISession *usrhp;
308
341
  OCIServer *srvhp;
309
342
  rb_pid_t pid;
343
+ unsigned char state;
310
344
  char is_autocommit;
311
345
  #ifdef HAVE_RB_THREAD_BLOCKING_REGION
312
346
  char non_blocking;
@@ -314,6 +348,11 @@ typedef struct {
314
348
  VALUE long_read_len;
315
349
  } oci8_svcctx_t;
316
350
 
351
+ struct oci8_logoff_strategy {
352
+ void *(*prepare)(oci8_svcctx_t *svcctx);
353
+ rb_blocking_function_t *execute;
354
+ };
355
+
317
356
  typedef struct {
318
357
  dvoid *hp; /* OCIBind* or OCIDefine* */
319
358
  dvoid *valuep;
@@ -341,13 +380,9 @@ typedef struct {
341
380
  #define oci8_raise_init_error() oci8_do_raise_init_error(__FILE__, __LINE__)
342
381
  #define oci8_raise_by_msgno(msgno, default_msg) oci8_do_raise_by_msgno(msgno, default_msg, __FILE__, __LINE__)
343
382
 
344
- /* raise on error */
345
- #define oci_lc(rv) do { \
346
- sword __rv = (rv); \
347
- if (__rv != OCI_SUCCESS) { \
348
- oci8_raise(oci8_errhp, __rv, NULL); \
349
- } \
350
- } while(0)
383
+ #define chkerr(status) oci8_check_error_((status), NULL, NULL, __FILE__, __LINE__)
384
+ #define chker2(status, base) oci8_check_error_((status), (base), NULL, __FILE__, __LINE__)
385
+ #define chker3(status, base, stmt) oci8_check_error_((status), (base), (stmt), __FILE__, __LINE__)
351
386
 
352
387
  #if SIZEOF_LONG > 4
353
388
  #define UB4_TO_NUM INT2FIX
@@ -362,7 +397,7 @@ typedef struct {
362
397
  * extern OCIError *oci8_errhp;
363
398
  */
364
399
  #define oci8_envhp (LIKELY(oci8_global_envhp != NULL) ? oci8_global_envhp : oci8_make_envhp())
365
- #ifdef HAVE_RB_THREAD_BLOCKING_REGION
400
+ #ifdef USE_THREAD_LOCAL_ERRHP
366
401
  #define oci8_errhp oci8_get_errhp()
367
402
  #else
368
403
  #define oci8_errhp (LIKELY(oci8_global_errhp != NULL) ? oci8_global_errhp : oci8_make_errhp())
@@ -372,7 +407,7 @@ typedef struct {
372
407
  extern ub4 oci8_env_mode;
373
408
  extern OCIEnv *oci8_global_envhp;
374
409
  OCIEnv *oci8_make_envhp(void);
375
- #ifdef HAVE_RB_THREAD_BLOCKING_REGION
410
+ #ifdef USE_THREAD_LOCAL_ERRHP
376
411
  extern oci8_tls_key_t oci8_tls_key; /* native thread key */
377
412
  OCIError *oci8_make_errhp(void);
378
413
 
@@ -389,11 +424,12 @@ OCIError *oci8_make_errhp(void);
389
424
  void Init_oci8_env(void);
390
425
 
391
426
  /* oci8lib.c */
427
+ extern ID oci8_id_at_last_error;
392
428
  extern ID oci8_id_new;
393
429
  extern ID oci8_id_get;
394
430
  extern ID oci8_id_set;
395
431
  extern ID oci8_id_keys;
396
- extern ID oci8_id_oci8_class;
432
+ extern ID oci8_id_oci8_vtable;
397
433
  #ifdef CHAR_IS_NOT_A_SHORTCUT_TO_ID
398
434
  extern ID oci8_id_add_op; /* ID of the addition operator '+' */
399
435
  extern ID oci8_id_sub_op; /* ID of the subtraction operator '-' */
@@ -408,9 +444,9 @@ extern ID oci8_id_div_op; /* ID of the division operator '/' */
408
444
  extern int oci8_in_finalizer;
409
445
  extern VALUE oci8_cOCIHandle;
410
446
  void oci8_base_free(oci8_base_t *base);
411
- VALUE oci8_define_class(const char *name, oci8_base_class_t *klass);
412
- VALUE oci8_define_class_under(VALUE outer, const char *name, oci8_base_class_t *klass);
413
- VALUE oci8_define_bind_class(const char *name, const oci8_bind_class_t *oci8_bind_class);
447
+ VALUE oci8_define_class(const char *name, oci8_base_vtable_t *vptr);
448
+ VALUE oci8_define_class_under(VALUE outer, const char *name, oci8_base_vtable_t *vptr);
449
+ VALUE oci8_define_bind_class(const char *name, const oci8_bind_vtable_t *vptr);
414
450
  void oci8_link_to_parent(oci8_base_t *base, oci8_base_t *parent);
415
451
  void oci8_unlink_from_parent(oci8_base_t *base);
416
452
  sword oci8_blocking_region(oci8_svcctx_t *svcctx, rb_blocking_function_t func, void *data);
@@ -424,18 +460,19 @@ oci8_base_t *oci8_get_handle(VALUE obj, VALUE klass);
424
460
  extern VALUE eOCIException;
425
461
  extern VALUE eOCIBreak;
426
462
  void Init_oci8_error(void);
427
- NORETURN(void oci8_do_raise(OCIError *, sword status, OCIStmt *, const char *file, int line));
428
463
  NORETURN(void oci8_do_env_raise(OCIEnv *, sword status, const char *file, int line));
429
464
  NORETURN(void oci8_do_raise_init_error(const char *file, int line));
430
465
  sb4 oci8_get_error_code(OCIError *errhp);
431
466
  VALUE oci8_get_error_message(ub4 msgno, const char *default_msg);
432
467
  NORETURN(void oci8_do_raise_by_msgno(ub4 msgno, const char *default_msg, const char *file, int line));
468
+ void oci8_check_error_(sword status, oci8_base_t *base, OCIStmt *stmthp, const char *file, int line);
433
469
 
434
470
  /* ocihandle.c */
435
471
  void Init_oci8_handle(void);
436
472
 
437
473
  /* oci8.c */
438
474
  VALUE Init_oci8(void);
475
+ void oci8_do_parse_connect_string(VALUE conn_str, VALUE *user, VALUE *pass, VALUE *dbname, VALUE *mode);
439
476
  oci8_svcctx_t *oci8_get_svcctx(VALUE obj);
440
477
  OCISvcCtx *oci8_get_oci_svcctx(VALUE obj);
441
478
  OCISession *oci8_get_oci_session(VALUE obj);
@@ -443,6 +480,9 @@ void oci8_check_pid_consistency(oci8_svcctx_t *svcctx);
443
480
  #define TO_SVCCTX oci8_get_oci_svcctx
444
481
  #define TO_SESSION oci8_get_oci_session
445
482
 
483
+ /* connection_pool.c */
484
+ void Init_oci8_connection_pool(VALUE cOCI8);
485
+
446
486
  /* stmt.c */
447
487
  extern VALUE cOCIStmt;
448
488
  void Init_oci8_stmt(VALUE cOCI8);
@@ -479,6 +519,7 @@ void oci8_assign_bfile(oci8_svcctx_t *svcctx, VALUE lob, OCILobLocator **dest);
479
519
  void Init_ora_date(void);
480
520
 
481
521
  /* ocinumber.c */
522
+ extern int oci8_float_conversion_type_is_ruby;
482
523
  void Init_oci_number(VALUE mOCI, OCIError *errhp);
483
524
  OCINumber *oci8_get_ocinumber(VALUE num);
484
525
  VALUE oci8_make_ocinumber(OCINumber *s, OCIError *errhp);
@@ -486,6 +527,8 @@ VALUE oci8_make_integer(OCINumber *s, OCIError *errhp);
486
527
  VALUE oci8_make_float(OCINumber *s, OCIError *errhp);
487
528
  OCINumber *oci8_set_ocinumber(OCINumber *result, VALUE self, OCIError *errhp);
488
529
  OCINumber *oci8_set_integer(OCINumber *result, VALUE self, OCIError *errhp);
530
+ double oci8_onum_to_dbl(OCINumber *s, OCIError *errhp);
531
+ OCINumber *oci8_dbl_to_onum(OCINumber *result, double dbl, OCIError *errhp);
489
532
 
490
533
  /* ocidatetim.c */
491
534
  void Init_oci_datetime(void);
@@ -499,29 +542,18 @@ VALUE oci8_make_interval_ds(OCIInterval *s);
499
542
  /* object.c */
500
543
  void Init_oci_object(VALUE mOCI);
501
544
 
502
- /* xmldb.c */
503
- #ifndef XMLCTX_DEFINED
504
- #define XMLCTX_DEFINED
505
- struct xmlctx;
506
- typedef struct xmlctx xmlctx;
507
- #endif
508
- #ifndef XML_TYPES
509
- typedef struct xmlnode xmlnode;
510
- #endif
511
- void Init_oci_xmldb(void);
512
- VALUE oci8_make_rexml(struct xmlctx *xctx, xmlnode *node);
513
-
514
545
  /* attr.c */
515
- VALUE oci8_get_sb1_attr(oci8_base_t *base, ub4 attrtype);
516
- VALUE oci8_get_ub2_attr(oci8_base_t *base, ub4 attrtype);
517
- VALUE oci8_get_sb2_attr(oci8_base_t *base, ub4 attrtype);
518
- VALUE oci8_get_ub4_attr(oci8_base_t *base, ub4 attrtype);
519
- VALUE oci8_get_string_attr(oci8_base_t *base, ub4 attrtype);
520
- VALUE oci8_get_rowid_attr(oci8_base_t *base, ub4 attrtype);
546
+ VALUE oci8_get_sb1_attr(oci8_base_t *base, ub4 attrtype, OCIStmt *stmtp);
547
+ VALUE oci8_get_ub2_attr(oci8_base_t *base, ub4 attrtype, OCIStmt *stmtp);
548
+ VALUE oci8_get_sb2_attr(oci8_base_t *base, ub4 attrtype, OCIStmt *stmtp);
549
+ VALUE oci8_get_ub4_attr(oci8_base_t *base, ub4 attrtype, OCIStmt *stmtp);
550
+ VALUE oci8_get_string_attr(oci8_base_t *base, ub4 attrtype, OCIStmt *stmtp);
551
+ VALUE oci8_get_rowid_attr(oci8_base_t *base, ub4 attrtype, OCIStmt *stmtp);
521
552
 
522
553
  /* encoding.c */
523
554
  void Init_oci8_encoding(VALUE cOCI8);
524
555
  VALUE oci8_charset_id2name(VALUE svc, VALUE charset_id);
556
+ extern int oci8_nls_ratio;
525
557
 
526
558
  /* win32.c */
527
559
  void Init_oci8_win32(VALUE cOCI8);
@@ -542,6 +574,7 @@ extern rb_encoding *oci8_encoding;
542
574
  #define OCI8SafeStringValue(v) SafeStringValue(v)
543
575
  #endif
544
576
 
577
+ #include "thread_util.h"
545
578
  #include "apiwrap.h"
546
579
 
547
580
  #endif
@@ -1,6 +1,6 @@
1
1
  /* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
2
2
  /*
3
- * Copyright (C) 2002-2009 KUBO Takehiro <kubo@jiubao.org>
3
+ * Copyright (C) 2002-2011 KUBO Takehiro <kubo@jiubao.org>
4
4
  */
5
5
 
6
6
  #include "oci8.h"
@@ -10,11 +10,12 @@
10
10
  #include <signal.h>
11
11
  #endif
12
12
 
13
+ ID oci8_id_at_last_error;
13
14
  ID oci8_id_new;
14
15
  ID oci8_id_get;
15
16
  ID oci8_id_set;
16
17
  ID oci8_id_keys;
17
- ID oci8_id_oci8_class;
18
+ ID oci8_id_oci8_vtable;
18
19
  #ifdef CHAR_IS_NOT_A_SHORTCUT_TO_ID
19
20
  ID oci8_id_add_op;
20
21
  ID oci8_id_sub_op;
@@ -34,8 +35,8 @@ void oci8_base_free(oci8_base_t *base)
34
35
  oci8_base_free(base->children);
35
36
  }
36
37
  oci8_unlink_from_parent(base);
37
- if (base->klass->free != NULL)
38
- base->klass->free(base);
38
+ if (base->vptr->free != NULL)
39
+ base->vptr->free(base);
39
40
  if (base->type >= OCI_DTYPE_FIRST)
40
41
  OCIDescriptorFree(base->hp.ptr, base->type);
41
42
  else if (base->type >= OCI_HTYPE_FIRST)
@@ -64,6 +65,10 @@ Init_oci8lib()
64
65
 
65
66
  #ifdef RUNTIME_API_CHECK
66
67
  Init_oci8_apiwrap();
68
+ if (oracle_client_version < ORAVER_9_0) {
69
+ rb_raise(rb_eLoadError, "Oracle 8 (8.0) and Oracle 8i (8.1) is not supported anymore!");
70
+ }
71
+
67
72
  if (have_OCIClientVersion) {
68
73
  sword major, minor, update, patch, port_update;
69
74
  OCIClientVersion(&major, &minor, &update, &patch, &port_update);
@@ -71,11 +76,12 @@ Init_oci8lib()
71
76
  }
72
77
  #endif
73
78
 
79
+ oci8_id_at_last_error = rb_intern("@last_error");
74
80
  oci8_id_new = rb_intern("new");
75
81
  oci8_id_get = rb_intern("get");
76
82
  oci8_id_set = rb_intern("set");
77
83
  oci8_id_keys = rb_intern("keys");
78
- oci8_id_oci8_class = rb_intern("__oci8_class__");
84
+ oci8_id_oci8_vtable = rb_intern("__oci8_vtable__");
79
85
  #ifdef CHAR_IS_NOT_A_SHORTCUT_TO_ID
80
86
  oci8_id_add_op = rb_intern("+");
81
87
  oci8_id_sub_op = rb_intern("-");
@@ -86,6 +92,7 @@ Init_oci8lib()
86
92
  rb_set_end_proc(at_exit_func, Qnil);
87
93
  #endif
88
94
 
95
+ Init_oci8_thread_util();
89
96
  Init_oci8_error();
90
97
  Init_oci8_env();
91
98
 
@@ -94,6 +101,10 @@ Init_oci8lib()
94
101
 
95
102
  /* OCI8 class */
96
103
  cOCI8 = Init_oci8();
104
+
105
+ /* OCI8::ConnectionPool class */
106
+ Init_oci8_connection_pool(cOCI8);
107
+
97
108
  /* OCI8::BindType module */
98
109
  mOCI8BindType = rb_define_module_under(cOCI8, "BindType");
99
110
  /* OCI8::BindType::Base class */
@@ -111,37 +122,20 @@ Init_oci8lib()
111
122
  Init_oci8_lob(cOCI8);
112
123
 
113
124
  /* allocate a temporary errhp to pass Init_oci_number() */
114
- if (have_OCIEnvCreate) {
115
- rv = OCIEnvCreate(&envhp, oci8_env_mode, NULL, NULL, NULL, NULL, 0, NULL);
116
- if (rv != OCI_SUCCESS) {
117
- oci8_raise_init_error();
118
- }
119
- } else {
120
- rv = OCIInitialize(oci8_env_mode, NULL, NULL, NULL, NULL);
121
- if (rv != OCI_SUCCESS) {
122
- oci8_raise_init_error();
123
- }
124
- rv = OCIEnvInit(&envhp, OCI_DEFAULT, 0, NULL);
125
- if (rv != OCI_SUCCESS) {
126
- oci8_raise_init_error();
127
- }
125
+ rv = OCIEnvCreate(&envhp, oci8_env_mode, NULL, NULL, NULL, NULL, 0, NULL);
126
+ if (rv != OCI_SUCCESS) {
127
+ oci8_raise_init_error();
128
128
  }
129
129
  rv = OCIHandleAlloc(envhp, (dvoid *)&errhp, OCI_HTYPE_ERROR, 0, NULL);
130
130
  if (rv != OCI_SUCCESS)
131
131
  oci8_env_raise(envhp, rv);
132
132
  Init_oci_number(cOCI8, errhp);
133
133
  OCIHandleFree(errhp, OCI_HTYPE_ERROR);
134
- if (have_OCIEnvCreate) {
135
- OCIHandleFree(envhp, OCI_HTYPE_ENV);
136
- } else {
137
- /* Delayed OCIEnv initialization cannot be used on Oracle 8.0. */
138
- oci8_global_envhp = envhp;
139
- }
134
+ OCIHandleFree(envhp, OCI_HTYPE_ENV);
140
135
 
141
136
  Init_ora_date();
142
137
  Init_oci_datetime();
143
138
  Init_oci_object(cOCI8);
144
- Init_oci_xmldb();
145
139
 
146
140
  #ifdef USE_WIN32_C
147
141
  Init_oci8_win32(cOCI8);
@@ -150,33 +144,29 @@ Init_oci8lib()
150
144
  #ifdef DEBUG_CORE_FILE
151
145
  signal(SIGSEGV, SIG_DFL);
152
146
  #endif
153
-
154
- if (have_OCIEnvCreate && oci8_global_envhp != NULL) {
155
- rb_raise(rb_eRuntimeError, "Internal Error: OCIEnv should not be initialized here.");
156
- }
157
147
  }
158
148
 
159
- VALUE oci8_define_class(const char *name, oci8_base_class_t *base_class)
149
+ VALUE oci8_define_class(const char *name, oci8_base_vtable_t *vptr)
160
150
  {
161
151
  VALUE klass = rb_define_class(name, oci8_cOCIHandle);
162
- VALUE obj = Data_Wrap_Struct(rb_cObject, 0, 0, base_class);
163
- rb_ivar_set(klass, oci8_id_oci8_class, obj);
152
+ VALUE obj = Data_Wrap_Struct(rb_cObject, 0, 0, vptr);
153
+ rb_ivar_set(klass, oci8_id_oci8_vtable, obj);
164
154
  return klass;
165
155
  }
166
156
 
167
- VALUE oci8_define_class_under(VALUE outer, const char *name, oci8_base_class_t *base_class)
157
+ VALUE oci8_define_class_under(VALUE outer, const char *name, oci8_base_vtable_t *vptr)
168
158
  {
169
159
  VALUE klass = rb_define_class_under(outer, name, oci8_cOCIHandle);
170
- VALUE obj = Data_Wrap_Struct(rb_cObject, 0, 0, base_class);
171
- rb_ivar_set(klass, oci8_id_oci8_class, obj);
160
+ VALUE obj = Data_Wrap_Struct(rb_cObject, 0, 0, vptr);
161
+ rb_ivar_set(klass, oci8_id_oci8_vtable, obj);
172
162
  return klass;
173
163
  }
174
164
 
175
- VALUE oci8_define_bind_class(const char *name, const oci8_bind_class_t *bind_class)
165
+ VALUE oci8_define_bind_class(const char *name, const oci8_bind_vtable_t *vptr)
176
166
  {
177
167
  VALUE klass = rb_define_class_under(mOCI8BindType, name, cOCI8BindTypeBase);
178
- VALUE obj = Data_Wrap_Struct(rb_cObject, 0, 0, (void*)bind_class);
179
- rb_ivar_set(klass, oci8_id_oci8_class, obj);
168
+ VALUE obj = Data_Wrap_Struct(rb_cObject, 0, 0, (void*)vptr);
169
+ rb_ivar_set(klass, oci8_id_oci8_vtable, obj);
180
170
  return klass;
181
171
  }
182
172
 
@@ -258,8 +248,8 @@ sword oci8_blocking_region(oci8_svcctx_t *svcctx, rb_blocking_function_t func, v
258
248
  rb_raise(rb_eRuntimeError /* FIXME */, "executing in another thread");
259
249
  }
260
250
  svcctx->executing_thread = rb_thread_current();
251
+ /* Note: executing_thread is cleard at the end of the blocking function. */
261
252
  rv = (sword)rb_thread_blocking_region(func, data, oci8_unblock_func, svcctx);
262
- svcctx->executing_thread = Qnil;
263
253
  if (rv == OCI_ERROR) {
264
254
  if (oci8_get_error_code(oci8_errhp) == 1013) {
265
255
  rb_raise(eOCIBreak, "Canceled by user request.");
@@ -273,14 +263,20 @@ sword oci8_blocking_region(oci8_svcctx_t *svcctx, rb_blocking_function_t func, v
273
263
  #else /* HAVE_RB_THREAD_BLOCKING_REGION */
274
264
 
275
265
  /* ruby 1.8 */
276
- sword oci8_blocking_region(oci8_svcctx_t *svcctx, rb_blocking_function_t func, void *data)
266
+ typedef struct {
267
+ oci8_svcctx_t *svcctx;
268
+ rb_blocking_function_t *func;
269
+ void *data;
270
+ } blocking_region_arg_t;
271
+
272
+ static VALUE blocking_function_execute(blocking_region_arg_t *arg)
277
273
  {
274
+ oci8_svcctx_t *svcctx = arg->svcctx;
275
+ rb_blocking_function_t *func = arg->func;
276
+ void *data = arg->data;
278
277
  struct timeval tv;
279
278
  sword rv;
280
279
 
281
- if (!NIL_P(svcctx->executing_thread)) {
282
- rb_raise(rb_eRuntimeError /* FIXME */, "executing in another thread");
283
- }
284
280
  tv.tv_sec = 0;
285
281
  tv.tv_usec = 10000;
286
282
  svcctx->executing_thread = rb_thread_current();
@@ -291,8 +287,7 @@ sword oci8_blocking_region(oci8_svcctx_t *svcctx, rb_blocking_function_t func, v
291
287
  }
292
288
  if (rv == OCI_ERROR) {
293
289
  if (oci8_get_error_code(oci8_errhp) == 1013) {
294
- if (have_OCIReset)
295
- OCIReset(svcctx->base.hp.ptr, oci8_errhp);
290
+ OCIReset(svcctx->base.hp.ptr, oci8_errhp);
296
291
  svcctx->executing_thread = Qnil;
297
292
  rb_raise(eOCIBreak, "Canceled by user request.");
298
293
  }
@@ -300,6 +295,30 @@ sword oci8_blocking_region(oci8_svcctx_t *svcctx, rb_blocking_function_t func, v
300
295
  svcctx->executing_thread = Qnil;
301
296
  return rv;
302
297
  }
298
+
299
+ static VALUE blocking_function_ensure(oci8_svcctx_t *svcctx)
300
+ {
301
+ if (!NIL_P(svcctx->executing_thread)) {
302
+ /* The thread is killed. */
303
+ OCIBreak(svcctx->base.hp.ptr, oci8_errhp);
304
+ OCIReset(svcctx->base.hp.ptr, oci8_errhp);
305
+ svcctx->executing_thread = Qnil;
306
+ }
307
+ return Qnil;
308
+ }
309
+
310
+ sword oci8_blocking_region(oci8_svcctx_t *svcctx, rb_blocking_function_t func, void *data)
311
+ {
312
+ blocking_region_arg_t arg;
313
+
314
+ arg.svcctx = svcctx;
315
+ arg.func = func;
316
+ arg.data = data;
317
+ if (!NIL_P(svcctx->executing_thread)) {
318
+ rb_raise(rb_eRuntimeError, "executing in another thread");
319
+ }
320
+ return (sword)rb_ensure(blocking_function_execute, (VALUE)&arg, blocking_function_ensure, (VALUE)svcctx);
321
+ }
303
322
  #endif /* HAVE_RB_THREAD_BLOCKING_REGION */
304
323
 
305
324
  typedef struct {
@@ -344,23 +363,26 @@ static VALUE exec_sql(cb_arg_t *arg)
344
363
  if (rv != OCI_SUCCESS) {
345
364
  oci8_env_raise(oci8_envhp, rv);
346
365
  }
347
- oci_lc(OCIStmtPrepare(arg->stmtp, oci8_errhp, (text*)arg->sql_text,
348
- strlen(arg->sql_text), OCI_NTV_SYNTAX, OCI_DEFAULT));
366
+ chker2(OCIStmtPrepare(arg->stmtp, oci8_errhp, (text*)arg->sql_text,
367
+ strlen(arg->sql_text), OCI_NTV_SYNTAX, OCI_DEFAULT),
368
+ &arg->svcctx->base);
349
369
  for (pos = 0; pos < arg->num_define_vars; pos++) {
350
370
  arg->define_vars[pos].hp = NULL;
351
- oci_lc(OCIDefineByPos(arg->stmtp, (OCIDefine**)&arg->define_vars[pos].hp,
371
+ chker3(OCIDefineByPos(arg->stmtp, (OCIDefine**)&arg->define_vars[pos].hp,
352
372
  oci8_errhp, pos + 1, arg->define_vars[pos].valuep,
353
373
  arg->define_vars[pos].value_sz,
354
374
  arg->define_vars[pos].dty, arg->define_vars[pos].indp,
355
- arg->define_vars[pos].alenp, NULL, OCI_DEFAULT));
375
+ arg->define_vars[pos].alenp, NULL, OCI_DEFAULT),
376
+ &arg->svcctx->base, arg->stmtp);
356
377
  }
357
378
  for (pos = 0; pos < arg->num_bind_vars; pos++) {
358
379
  arg->bind_vars[pos].hp = NULL;
359
- oci_lc(OCIBindByPos(arg->stmtp, (OCIBind**)&arg->bind_vars[pos].hp,
380
+ chker3(OCIBindByPos(arg->stmtp, (OCIBind**)&arg->bind_vars[pos].hp,
360
381
  oci8_errhp, pos + 1, arg->bind_vars[pos].valuep,
361
382
  arg->bind_vars[pos].value_sz, arg->bind_vars[pos].dty,
362
383
  arg->bind_vars[pos].indp, arg->bind_vars[pos].alenp,
363
- NULL, 0, NULL, OCI_DEFAULT));
384
+ NULL, 0, NULL, OCI_DEFAULT),
385
+ &arg->svcctx->base, arg->stmtp);
364
386
  }
365
387
  rv = OCIStmtExecute_nb(arg->svcctx, arg->svcctx->base.hp.svc, arg->stmtp, oci8_errhp, 1, 0, NULL, NULL, OCI_DEFAULT);
366
388
  if (rv == OCI_ERROR) {
@@ -373,7 +395,7 @@ static VALUE exec_sql(cb_arg_t *arg)
373
395
  }
374
396
  }
375
397
  if (arg->raise_on_error) {
376
- oci_lc(rv);
398
+ chker3(rv, &arg->svcctx->base, arg->stmtp);
377
399
  }
378
400
  return (VALUE)rv;
379
401
  }