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.
- data/ChangeLog +366 -19
- data/Makefile +2 -8
- data/NEWS +111 -0
- data/README +4 -85
- data/VERSION +1 -1
- data/dist-files +9 -2
- data/ext/oci8/.document +1 -0
- data/ext/oci8/apiwrap.c.tmpl +12 -2
- data/ext/oci8/apiwrap.yml +37 -21
- data/ext/oci8/attr.c +23 -74
- data/ext/oci8/bind.c +93 -225
- data/ext/oci8/connection_pool.c +201 -0
- data/ext/oci8/encoding.c +117 -24
- data/ext/oci8/env.c +5 -10
- data/ext/oci8/error.c +171 -189
- data/ext/oci8/extconf.rb +6 -2
- data/ext/oci8/lob.c +81 -79
- data/ext/oci8/metadata.c +42 -177
- data/ext/oci8/object.c +55 -28
- data/ext/oci8/oci8.c +426 -294
- data/ext/oci8/oci8.h +84 -51
- data/ext/oci8/oci8lib.c +75 -53
- data/ext/oci8/ocidatetime.c +67 -88
- data/ext/oci8/ocihandle.c +78 -37
- data/ext/oci8/ocinumber.c +166 -109
- data/ext/oci8/oraconf.rb +68 -157
- data/ext/oci8/oradate.c +2 -7
- data/ext/oci8/stmt.c +40 -183
- data/ext/oci8/thread_util.c +85 -0
- data/ext/oci8/thread_util.h +30 -0
- data/lib/oci8.rb.in +19 -13
- data/lib/oci8/.document +2 -0
- data/lib/oci8/bindtype.rb +62 -45
- data/lib/oci8/connection_pool.rb +118 -0
- data/lib/oci8/datetime.rb +304 -320
- data/lib/oci8/encoding-init.rb +62 -30
- data/lib/oci8/encoding.yml +3 -3
- data/lib/oci8/metadata.rb +552 -497
- data/lib/oci8/object.rb +9 -9
- data/lib/oci8/oci8.rb +161 -2
- data/lib/oci8/ocihandle.rb +427 -0
- data/lib/oci8/properties.rb +31 -1
- data/ruby-oci8.gemspec +10 -3
- data/test/README +41 -3
- data/test/config.rb +16 -0
- data/test/test_all.rb +3 -0
- data/test/test_bind_string.rb +106 -0
- data/test/test_break.rb +33 -7
- data/test/test_clob.rb +13 -10
- data/test/test_connection_pool.rb +125 -0
- data/test/test_connstr.rb +2 -2
- data/test/test_datetime.rb +26 -66
- data/test/test_encoding.rb +7 -3
- data/test/test_error.rb +88 -0
- data/test/test_metadata.rb +1356 -204
- data/test/test_oci8.rb +27 -8
- data/test/test_oranumber.rb +41 -0
- metadata +34 -9
- data/ext/oci8/xmldb.c +0 -383
data/ext/oci8/oci8.h
CHANGED
@@ -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
|
-
#
|
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
|
193
|
-
/*
|
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
|
241
|
-
typedef struct
|
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
|
-
|
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
|
-
|
253
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
307
|
-
OCISession *
|
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
|
-
|
345
|
-
#define
|
346
|
-
|
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
|
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
|
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
|
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,
|
412
|
-
VALUE oci8_define_class_under(VALUE outer, const char *name,
|
413
|
-
VALUE oci8_define_bind_class(const char *name, const
|
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
|
data/ext/oci8/oci8lib.c
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
|
2
2
|
/*
|
3
|
-
* Copyright (C) 2002-
|
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
|
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->
|
38
|
-
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
|
-
|
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
|
-
|
115
|
-
|
116
|
-
|
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
|
-
|
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,
|
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,
|
163
|
-
rb_ivar_set(klass,
|
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,
|
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,
|
171
|
-
rb_ivar_set(klass,
|
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
|
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*)
|
179
|
-
rb_ivar_set(klass,
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
398
|
+
chker3(rv, &arg->svcctx->base, arg->stmtp);
|
377
399
|
}
|
378
400
|
return (VALUE)rv;
|
379
401
|
}
|