ruby-oci8-master 2.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. data/ChangeLog +2321 -0
  2. data/Makefile +88 -0
  3. data/NEWS +303 -0
  4. data/README +76 -0
  5. data/VERSION +1 -0
  6. data/dist-files +83 -0
  7. data/doc/api.en.html +527 -0
  8. data/doc/api.en.rd +554 -0
  9. data/doc/api.ja.html +525 -0
  10. data/doc/api.ja.rd +557 -0
  11. data/doc/manual.css +35 -0
  12. data/ext/oci8/.document +18 -0
  13. data/ext/oci8/MANIFEST +18 -0
  14. data/ext/oci8/apiwrap.c.tmpl +182 -0
  15. data/ext/oci8/apiwrap.h.tmpl +61 -0
  16. data/ext/oci8/apiwrap.rb +91 -0
  17. data/ext/oci8/apiwrap.yml +1455 -0
  18. data/ext/oci8/attr.c +105 -0
  19. data/ext/oci8/bind.c +366 -0
  20. data/ext/oci8/connection_pool.c +199 -0
  21. data/ext/oci8/encoding.c +289 -0
  22. data/ext/oci8/env.c +178 -0
  23. data/ext/oci8/error.c +378 -0
  24. data/ext/oci8/extconf.rb +179 -0
  25. data/ext/oci8/lob.c +805 -0
  26. data/ext/oci8/metadata.c +232 -0
  27. data/ext/oci8/object.c +727 -0
  28. data/ext/oci8/oci8.c +1156 -0
  29. data/ext/oci8/oci8.h +574 -0
  30. data/ext/oci8/oci8lib.c +527 -0
  31. data/ext/oci8/ocidatetime.c +484 -0
  32. data/ext/oci8/ocihandle.c +751 -0
  33. data/ext/oci8/ocinumber.c +1612 -0
  34. data/ext/oci8/oraconf.rb +1119 -0
  35. data/ext/oci8/oradate.c +611 -0
  36. data/ext/oci8/oranumber_util.c +352 -0
  37. data/ext/oci8/oranumber_util.h +24 -0
  38. data/ext/oci8/post-config.rb +5 -0
  39. data/ext/oci8/stmt.c +673 -0
  40. data/ext/oci8/thread_util.c +85 -0
  41. data/ext/oci8/thread_util.h +30 -0
  42. data/ext/oci8/win32.c +137 -0
  43. data/lib/.document +1 -0
  44. data/lib/dbd/OCI8.rb +591 -0
  45. data/lib/oci8.rb.in +94 -0
  46. data/lib/oci8/.document +8 -0
  47. data/lib/oci8/bindtype.rb +349 -0
  48. data/lib/oci8/compat.rb +113 -0
  49. data/lib/oci8/connection_pool.rb +99 -0
  50. data/lib/oci8/datetime.rb +611 -0
  51. data/lib/oci8/encoding-init.rb +74 -0
  52. data/lib/oci8/encoding.yml +537 -0
  53. data/lib/oci8/metadata.rb +2132 -0
  54. data/lib/oci8/object.rb +581 -0
  55. data/lib/oci8/oci8.rb +721 -0
  56. data/lib/oci8/ocihandle.rb +425 -0
  57. data/lib/oci8/oracle_version.rb +144 -0
  58. data/lib/oci8/properties.rb +73 -0
  59. data/metaconfig +142 -0
  60. data/pre-distclean.rb +7 -0
  61. data/ruby-oci8.gemspec +63 -0
  62. data/setup.rb +1331 -0
  63. data/test/README +4 -0
  64. data/test/config.rb +122 -0
  65. data/test/test_all.rb +51 -0
  66. data/test/test_appinfo.rb +63 -0
  67. data/test/test_array_dml.rb +333 -0
  68. data/test/test_bind_raw.rb +46 -0
  69. data/test/test_bind_time.rb +178 -0
  70. data/test/test_break.rb +96 -0
  71. data/test/test_clob.rb +82 -0
  72. data/test/test_connstr.rb +81 -0
  73. data/test/test_datetime.rb +582 -0
  74. data/test/test_dbi.rb +366 -0
  75. data/test/test_dbi_clob.rb +53 -0
  76. data/test/test_encoding.rb +100 -0
  77. data/test/test_error.rb +88 -0
  78. data/test/test_metadata.rb +1399 -0
  79. data/test/test_oci8.rb +434 -0
  80. data/test/test_oracle_version.rb +70 -0
  81. data/test/test_oradate.rb +256 -0
  82. data/test/test_oranumber.rb +746 -0
  83. data/test/test_rowid.rb +33 -0
  84. metadata +137 -0
@@ -0,0 +1,1156 @@
1
+ /* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * oci8.c - part of ruby-oci8
4
+ *
5
+ * Copyright (C) 2002-2011 KUBO Takehiro <kubo@jiubao.org>
6
+ *
7
+ */
8
+ #include "oci8.h"
9
+ #include <errno.h>
10
+ #ifdef HAVE_UNISTD_H
11
+ #include <unistd.h> /* getpid() */
12
+ #endif
13
+
14
+ #ifdef WIN32
15
+ #ifndef getpid
16
+ extern rb_pid_t rb_w32_getpid(void);
17
+ #define getpid() rb_w32_getpid()
18
+ #endif
19
+ #endif
20
+
21
+ #ifndef OCI_ATTR_CLIENT_IDENTIFIER
22
+ #define OCI_ATTR_CLIENT_IDENTIFIER 278
23
+ #endif
24
+ #ifndef OCI_ATTR_MODULE
25
+ #define OCI_ATTR_MODULE 366
26
+ #endif
27
+ #ifndef OCI_ATTR_ACTION
28
+ #define OCI_ATTR_ACTION 367
29
+ #endif
30
+ #ifndef OCI_ATTR_CLIENT_INFO
31
+ #define OCI_ATTR_CLIENT_INFO 368
32
+ #endif
33
+
34
+ #define OCI8_STATE_SESSION_BEGIN_WAS_CALLED 0x01
35
+ #define OCI8_STATE_SERVER_ATTACH_WAS_CALLED 0x02
36
+
37
+ static VALUE cOCI8;
38
+ static VALUE cSession;
39
+ static VALUE cServer;
40
+ static ID id_at_session_handle;
41
+ static ID id_at_server_handle;
42
+
43
+ typedef struct oci8_svcctx_associate {
44
+ oci8_base_t base;
45
+ oci8_svcctx_t *svcctx;
46
+ } oci8_svcctx_associate_t;
47
+
48
+ static void oci8_svcctx_associate_free(oci8_base_t *base)
49
+ {
50
+ base->type = 0;
51
+ base->hp.ptr = NULL;
52
+ }
53
+
54
+ static oci8_base_vtable_t oci8_svcctx_associate_vtable = {
55
+ NULL,
56
+ oci8_svcctx_associate_free,
57
+ sizeof(oci8_svcctx_associate_t),
58
+ };
59
+
60
+ static void copy_session_handle(oci8_svcctx_t *svcctx)
61
+ {
62
+ VALUE obj = rb_ivar_get(svcctx->base.self, id_at_session_handle);
63
+ oci8_base_t *base;
64
+
65
+ Check_Handle(obj, cSession, base);
66
+ base->type = OCI_HTYPE_SESSION;
67
+ base->hp.usrhp = svcctx->usrhp;
68
+ }
69
+
70
+ static void copy_server_handle(oci8_svcctx_t *svcctx)
71
+ {
72
+ VALUE obj = rb_ivar_get(svcctx->base.self, id_at_server_handle);
73
+ oci8_base_t *base;
74
+
75
+ Check_Handle(obj, cServer, base);
76
+ base->type = OCI_HTYPE_SERVER;
77
+ base->hp.srvhp = svcctx->srvhp;
78
+ }
79
+
80
+ static void oci8_svcctx_free(oci8_base_t *base)
81
+ {
82
+ oci8_svcctx_t *svcctx = (oci8_svcctx_t *)base;
83
+ if (svcctx->logoff_strategy != NULL) {
84
+ const oci8_logoff_strategy_t *strategy = svcctx->logoff_strategy;
85
+ void *data = strategy->prepare(svcctx);
86
+ int rv;
87
+ svcctx->base.type = 0;
88
+ svcctx->logoff_strategy = NULL;
89
+ rv = oci8_run_native_thread(strategy->execute, data);
90
+ if (rv != 0) {
91
+ errno = rv;
92
+ #ifdef WIN32
93
+ rb_sys_fail("_beginthread");
94
+ #else
95
+ rb_sys_fail("pthread_create");
96
+ #endif
97
+ }
98
+ }
99
+ svcctx->base.type = 0;
100
+ }
101
+
102
+ static void oci8_svcctx_init(oci8_base_t *base)
103
+ {
104
+ oci8_svcctx_t *svcctx = (oci8_svcctx_t *)base;
105
+ VALUE obj;
106
+
107
+ svcctx->executing_thread = Qnil;
108
+ /* set session handle */
109
+ obj = rb_obj_alloc(cSession);
110
+ rb_ivar_set(base->self, id_at_session_handle, obj);
111
+ oci8_link_to_parent(DATA_PTR(obj), base);
112
+ /* set server handle */
113
+ obj = rb_obj_alloc(cServer);
114
+ rb_ivar_set(base->self, id_at_server_handle, obj);
115
+ oci8_link_to_parent(DATA_PTR(obj), base);
116
+
117
+ svcctx->pid = getpid();
118
+ svcctx->is_autocommit = 0;
119
+ #ifdef HAVE_RB_THREAD_BLOCKING_REGION
120
+ svcctx->non_blocking = 1;
121
+ #endif
122
+ svcctx->long_read_len = INT2FIX(65535);
123
+ }
124
+
125
+ static oci8_base_vtable_t oci8_svcctx_vtable = {
126
+ NULL,
127
+ oci8_svcctx_free,
128
+ sizeof(oci8_svcctx_t),
129
+ oci8_svcctx_init,
130
+ };
131
+
132
+ static VALUE oracle_client_vernum; /* Oracle client version number */
133
+ static VALUE sym_SYSDBA;
134
+ static VALUE sym_SYSOPER;
135
+ static ID id_at_prefetch_rows;
136
+ static ID id_set_prefetch_rows;
137
+
138
+ static VALUE oci8_s_oracle_client_vernum(VALUE klass)
139
+ {
140
+ return oracle_client_vernum;
141
+ }
142
+
143
+ static VALUE oci8_s_set_property(VALUE klass, VALUE name, VALUE val)
144
+ {
145
+ const char *name_str;
146
+
147
+ Check_Type(name, T_SYMBOL);
148
+ name_str = rb_id2name(SYM2ID(name));
149
+ if (strcmp(name_str, "float_conversion_type") == 0) {
150
+ const char *val_str;
151
+ Check_Type(val, T_SYMBOL);
152
+ val_str = rb_id2name(SYM2ID(val));
153
+ if (strcmp(val_str, "ruby") == 0) {
154
+ oci8_float_conversion_type_is_ruby = 1;
155
+ } else if (strcmp(val_str, "oracle") == 0) {
156
+ oci8_float_conversion_type_is_ruby = 0;
157
+ } else {
158
+ rb_raise(rb_eArgError, "float_conversion_type's value should be either :ruby or :oracle.");
159
+ }
160
+ }
161
+ return Qnil;
162
+ }
163
+
164
+ /*
165
+ * call-seq:
166
+ * OCI8.error_message(message_no) -> string
167
+ *
168
+ * Get the Oracle error message specified by message_no.
169
+ * Its language depends on NLS_LANGUAGE.
170
+ *
171
+ * Note: This method is unavailable if the Oracle client version is 8.0.
172
+ *
173
+ * example:
174
+ * # When NLS_LANG is AMERICAN_AMERICA.AL32UTF8
175
+ * OCI8.error_message(1) # => "ORA-00001: unique constraint (%s.%s) violated"
176
+ *
177
+ * # When NLS_LANG is FRENCH_FRANCE.AL32UTF8
178
+ * OCI8.error_message(1) # => "ORA-00001: violation de contrainte unique (%s.%s)"
179
+ *
180
+ */
181
+ static VALUE oci8_s_error_message(VALUE klass, VALUE msgid)
182
+ {
183
+ return oci8_get_error_message(NUM2UINT(msgid), NULL);
184
+ }
185
+
186
+ #define CONN_STR_REGEX "/^([^(\\s|\\@)]*)\\/([^(\\s|\\@)]*)(?:\\@(\\S+))?(?:\\s+as\\s+(\\S*)\\s*)?$/i"
187
+ void oci8_do_parse_connect_string(VALUE conn_str, VALUE *user, VALUE *pass, VALUE *dbname, VALUE *mode)
188
+ {
189
+ static VALUE re = Qnil;
190
+ if (NIL_P(re)) {
191
+ re = rb_eval_string(CONN_STR_REGEX);
192
+ rb_global_variable(&re);
193
+ }
194
+ OCI8SafeStringValue(conn_str);
195
+ if (RTEST(rb_reg_match(re, conn_str))) {
196
+ *user = rb_reg_nth_match(1, rb_backref_get());
197
+ *pass = rb_reg_nth_match(2, rb_backref_get());
198
+ *dbname = rb_reg_nth_match(3, rb_backref_get());
199
+ *mode = rb_reg_nth_match(4, rb_backref_get());
200
+ if (RSTRING_LEN(*user) == 0 && RSTRING_LEN(*pass) == 0) {
201
+ /* external credential */
202
+ *user = Qnil;
203
+ *pass = Qnil;
204
+ }
205
+ if (!NIL_P(*mode)) {
206
+ char *ptr;
207
+ SafeStringValue(*mode);
208
+ ptr = RSTRING_PTR(*mode);
209
+ if (strcasecmp(ptr, "SYSDBA") == 0) {
210
+ *mode = sym_SYSDBA;
211
+ } else if (strcasecmp(ptr, "SYSOPER") == 0) {
212
+ *mode = sym_SYSOPER;
213
+ }
214
+ }
215
+ } else {
216
+ rb_raise(rb_eArgError, "invalid connect string \"%s\" (expect \"username/password[@(tns_name|//host[:port]/service_name)][ as (sysdba|sysoper)]\"", RSTRING_PTR(conn_str));
217
+ }
218
+ }
219
+
220
+ /*
221
+ * call-seq:
222
+ * parse_connect_string(string) -> [username, password, dbname, privilege]
223
+ *
224
+ * Extracts +username+, +password+, +dbname+ and +privilege+ from the specified +string+.
225
+ *
226
+ * example:
227
+ * "scott/tiger" -> ["scott", "tiger", nil, nil],
228
+ * "scott/tiger@oradb.example.com" -> ["scott", "tiger", "oradb.example.com", nil]
229
+ * "sys/change_on_install as sysdba" -> ["sys", "change_on_install", nil, :SYSDBA]
230
+ *
231
+ */
232
+ static VALUE oci8_parse_connect_string(VALUE self, VALUE conn_str)
233
+ {
234
+ VALUE user;
235
+ VALUE pass;
236
+ VALUE dbname;
237
+ VALUE mode;
238
+
239
+ oci8_do_parse_connect_string(conn_str, &user, &pass, &dbname, &mode);
240
+ return rb_ary_new3(4, user, pass, dbname, mode);
241
+ }
242
+
243
+ /*
244
+ * Logoff strategy for sessions connected by OCILogon.
245
+ */
246
+ typedef struct {
247
+ OCISvcCtx *svchp;
248
+ OCISession *usrhp;
249
+ OCIServer *srvhp;
250
+ } simple_logoff_arg_t;
251
+
252
+ static void *simple_logoff_prepare(oci8_svcctx_t *svcctx)
253
+ {
254
+ simple_logoff_arg_t *sla = xmalloc(sizeof(simple_logoff_arg_t));
255
+ sla->svchp = svcctx->base.hp.svc;
256
+ sla->usrhp = svcctx->usrhp;
257
+ sla->srvhp = svcctx->srvhp;
258
+ svcctx->usrhp = NULL;
259
+ svcctx->srvhp = NULL;
260
+ return sla;
261
+ }
262
+
263
+ static VALUE simple_logoff_execute(void *arg)
264
+ {
265
+ simple_logoff_arg_t *sla = (simple_logoff_arg_t *)arg;
266
+ OCIError *errhp = oci8_errhp;
267
+ sword rv;
268
+
269
+ OCITransRollback(sla->svchp, errhp, OCI_DEFAULT);
270
+ rv = OCILogoff(sla->svchp, errhp);
271
+ xfree(sla);
272
+ return (VALUE)rv;
273
+ }
274
+
275
+ static const oci8_logoff_strategy_t simple_logoff = {
276
+ simple_logoff_prepare,
277
+ simple_logoff_execute,
278
+ };
279
+
280
+ /*
281
+ * Logoff strategy for sessions connected by OCIServerAttach and OCISessionBegin.
282
+ */
283
+
284
+ typedef struct {
285
+ OCISvcCtx *svchp;
286
+ OCISession *usrhp;
287
+ OCIServer *srvhp;
288
+ unsigned char state;
289
+ } complex_logoff_arg_t;
290
+
291
+ static void *complex_logoff_prepare(oci8_svcctx_t *svcctx)
292
+ {
293
+ complex_logoff_arg_t *cla = xmalloc(sizeof(complex_logoff_arg_t));
294
+ cla->svchp = svcctx->base.hp.svc;
295
+ cla->usrhp = svcctx->usrhp;
296
+ cla->srvhp = svcctx->srvhp;
297
+ cla->state = svcctx->state;
298
+ svcctx->usrhp = NULL;
299
+ svcctx->srvhp = NULL;
300
+ svcctx->state = 0;
301
+ return cla;
302
+ }
303
+
304
+ static VALUE complex_logoff_execute(void *arg)
305
+ {
306
+ complex_logoff_arg_t *cla = (complex_logoff_arg_t *)arg;
307
+ OCIError *errhp = oci8_errhp;
308
+ sword rv = OCI_SUCCESS;
309
+
310
+ OCITransRollback(cla->svchp, errhp, OCI_DEFAULT);
311
+
312
+ if (cla->state & OCI8_STATE_SESSION_BEGIN_WAS_CALLED) {
313
+ rv = OCISessionEnd(cla->svchp, oci8_errhp, cla->usrhp, OCI_DEFAULT);
314
+ cla->state &= ~OCI8_STATE_SESSION_BEGIN_WAS_CALLED;
315
+ }
316
+ if (cla->state & OCI8_STATE_SERVER_ATTACH_WAS_CALLED) {
317
+ rv = OCIServerDetach(cla->srvhp, oci8_errhp, OCI_DEFAULT);
318
+ cla->state &= ~OCI8_STATE_SERVER_ATTACH_WAS_CALLED;
319
+ }
320
+ if (cla->usrhp != NULL) {
321
+ OCIHandleFree(cla->usrhp, OCI_HTYPE_SESSION);
322
+ }
323
+ if (cla->srvhp != NULL) {
324
+ OCIHandleFree(cla->srvhp, OCI_HTYPE_SERVER);
325
+ }
326
+ if (cla->svchp != NULL) {
327
+ OCIHandleFree(cla->svchp, OCI_HTYPE_SVCCTX);
328
+ }
329
+ xfree(cla);
330
+ return (VALUE)rv;
331
+ }
332
+
333
+ static const oci8_logoff_strategy_t complex_logoff = {
334
+ complex_logoff_prepare,
335
+ complex_logoff_execute,
336
+ };
337
+
338
+ /*
339
+ * call-seq:
340
+ * logon(username, password, dbname) -> connection
341
+ *
342
+ * <b>internal use only</b>
343
+ *
344
+ * Creates a simple logon session by the OCI function OCILogon().
345
+ */
346
+ static VALUE oci8_logon(VALUE self, VALUE username, VALUE password, VALUE dbname)
347
+ {
348
+ oci8_svcctx_t *svcctx = DATA_PTR(self);
349
+
350
+ if (svcctx->logoff_strategy != NULL) {
351
+ rb_raise(rb_eRuntimeError, "Could not reuse the session.");
352
+ }
353
+
354
+ /* check arugmnets */
355
+ OCI8SafeStringValue(username);
356
+ OCI8SafeStringValue(password);
357
+ if (!NIL_P(dbname)) {
358
+ OCI8SafeStringValue(dbname);
359
+ }
360
+
361
+ /* logon */
362
+ svcctx->base.type = OCI_HTYPE_SVCCTX;
363
+ chker2(OCILogon_nb(svcctx, oci8_envhp, oci8_errhp, &svcctx->base.hp.svc,
364
+ RSTRING_ORATEXT(username), RSTRING_LEN(username),
365
+ RSTRING_ORATEXT(password), RSTRING_LEN(password),
366
+ NIL_P(dbname) ? NULL : RSTRING_ORATEXT(dbname),
367
+ NIL_P(dbname) ? 0 : RSTRING_LEN(dbname)),
368
+ &svcctx->base);
369
+ svcctx->logoff_strategy = &simple_logoff;
370
+
371
+ /* setup the session handle */
372
+ chker2(OCIAttrGet(svcctx->base.hp.ptr, OCI_HTYPE_SVCCTX, &svcctx->usrhp, 0, OCI_ATTR_SESSION, oci8_errhp),
373
+ &svcctx->base);
374
+ copy_session_handle(svcctx);
375
+
376
+ /* setup the server handle */
377
+ chker2(OCIAttrGet(svcctx->base.hp.ptr, OCI_HTYPE_SVCCTX, &svcctx->srvhp, 0, OCI_ATTR_SERVER, oci8_errhp),
378
+ &svcctx->base);
379
+ copy_server_handle(svcctx);
380
+
381
+ return Qnil;
382
+ }
383
+
384
+ /*
385
+ * call-seq:
386
+ * allocate_handles()
387
+ *
388
+ * <b>internal use only</b>
389
+ *
390
+ * Allocates a service context handle, a session handle and a
391
+ * server handle to use explicit attach and begin-session calls.
392
+ */
393
+ static VALUE oci8_allocate_handles(VALUE self)
394
+ {
395
+ oci8_svcctx_t *svcctx = DATA_PTR(self);
396
+ sword rv;
397
+
398
+ if (svcctx->logoff_strategy != NULL) {
399
+ rb_raise(rb_eRuntimeError, "Could not reuse the session.");
400
+ }
401
+ svcctx->logoff_strategy = &complex_logoff;
402
+ svcctx->state = 0;
403
+
404
+ /* allocate a service context handle */
405
+ rv = OCIHandleAlloc(oci8_envhp, &svcctx->base.hp.ptr, OCI_HTYPE_SVCCTX, 0, 0);
406
+ if (rv != OCI_SUCCESS)
407
+ oci8_env_raise(oci8_envhp, rv);
408
+ svcctx->base.type = OCI_HTYPE_SVCCTX;
409
+
410
+ /* alocalte a session handle */
411
+ rv = OCIHandleAlloc(oci8_envhp, (void*)&svcctx->usrhp, OCI_HTYPE_SESSION, 0, 0);
412
+ if (rv != OCI_SUCCESS)
413
+ oci8_env_raise(oci8_envhp, rv);
414
+ copy_session_handle(svcctx);
415
+
416
+ /* alocalte a server handle */
417
+ rv = OCIHandleAlloc(oci8_envhp, (void*)&svcctx->srvhp, OCI_HTYPE_SERVER, 0, 0);
418
+ if (rv != OCI_SUCCESS)
419
+ oci8_env_raise(oci8_envhp, rv);
420
+ copy_server_handle(svcctx);
421
+ return self;
422
+ }
423
+
424
+ /*
425
+ * call-seq:
426
+ * session_handle -> a session handle
427
+ *
428
+ * <b>internal use only</b>
429
+ *
430
+ * Returns a session handle associated with the service context handle.
431
+ */
432
+ static VALUE oci8_get_session_handle(VALUE self)
433
+ {
434
+ return rb_ivar_get(self, id_at_session_handle);
435
+ }
436
+
437
+ /*
438
+ * call-seq:
439
+ * server_handle -> a server handle
440
+ *
441
+ * <b>internal use only</b>
442
+ *
443
+ * Returns a server handle associated with the service context handle.
444
+ */
445
+ static VALUE oci8_get_server_handle(VALUE self)
446
+ {
447
+ return rb_ivar_get(self, id_at_server_handle);
448
+ }
449
+
450
+ /*
451
+ * call-seq:
452
+ * server_attach(dbname, mode)
453
+ *
454
+ * <b>internal use only</b>
455
+ *
456
+ * Attachs to the server by the OCI function OCIServerAttach().
457
+ */
458
+ static VALUE oci8_server_attach(VALUE self, VALUE dbname, VALUE mode)
459
+ {
460
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(self);
461
+
462
+ if (svcctx->logoff_strategy != &complex_logoff) {
463
+ rb_raise(rb_eRuntimeError, "Use this method only for the service context handle created by OCI8#server_handle().");
464
+ }
465
+ if (svcctx->state & OCI8_STATE_SERVER_ATTACH_WAS_CALLED) {
466
+ rb_raise(rb_eRuntimeError, "Could not use this method twice.");
467
+ }
468
+
469
+ /* check arguments */
470
+ if (!NIL_P(dbname)) {
471
+ OCI8SafeStringValue(dbname);
472
+ }
473
+ Check_Type(mode, T_FIXNUM);
474
+
475
+ /* attach to the server */
476
+ chker2(OCIServerAttach_nb(svcctx, svcctx->srvhp, oci8_errhp,
477
+ NIL_P(dbname) ? NULL : RSTRING_ORATEXT(dbname),
478
+ NIL_P(dbname) ? 0 : RSTRING_LEN(dbname),
479
+ FIX2UINT(mode)),
480
+ &svcctx->base);
481
+ chker2(OCIAttrSet(svcctx->base.hp.ptr, OCI_HTYPE_SVCCTX,
482
+ svcctx->srvhp, 0, OCI_ATTR_SERVER,
483
+ oci8_errhp),
484
+ &svcctx->base);
485
+ svcctx->state |= OCI8_STATE_SERVER_ATTACH_WAS_CALLED;
486
+ return self;
487
+ }
488
+
489
+ /*
490
+ * call-seq:
491
+ * session_begin(cred, mode)
492
+ *
493
+ * <b>internal use only</b>
494
+ *
495
+ * Begins the session by the OCI function OCISessionBegin().
496
+ */
497
+ static VALUE oci8_session_begin(VALUE self, VALUE cred, VALUE mode)
498
+ {
499
+ oci8_svcctx_t *svcctx = DATA_PTR(self);
500
+
501
+ if (svcctx->logoff_strategy != &complex_logoff) {
502
+ rb_raise(rb_eRuntimeError, "Use this method only for the service context handle created by OCI8#server_handle().");
503
+ }
504
+ if (svcctx->state & OCI8_STATE_SESSION_BEGIN_WAS_CALLED) {
505
+ rb_raise(rb_eRuntimeError, "Could not use this method twice.");
506
+ }
507
+
508
+ /* check arguments */
509
+ Check_Type(cred, T_FIXNUM);
510
+ Check_Type(mode, T_FIXNUM);
511
+
512
+ /* begin session */
513
+ chker2(OCISessionBegin_nb(svcctx, svcctx->base.hp.ptr, oci8_errhp,
514
+ svcctx->usrhp, FIX2UINT(cred),
515
+ FIX2UINT(mode)),
516
+ &svcctx->base);
517
+ chker2(OCIAttrSet(svcctx->base.hp.ptr, OCI_HTYPE_SVCCTX,
518
+ svcctx->usrhp, 0, OCI_ATTR_SESSION,
519
+ oci8_errhp),
520
+ &svcctx->base);
521
+ svcctx->state |= OCI8_STATE_SESSION_BEGIN_WAS_CALLED;
522
+ return Qnil;
523
+ }
524
+
525
+ /*
526
+ * call-seq:
527
+ * logoff
528
+ *
529
+ * Disconnects from the Oracle server. The uncommitted transaction is
530
+ * rollbacked.
531
+ */
532
+ static VALUE oci8_svcctx_logoff(VALUE self)
533
+ {
534
+ oci8_svcctx_t *svcctx = (oci8_svcctx_t *)DATA_PTR(self);
535
+
536
+ while (svcctx->base.children != NULL) {
537
+ oci8_base_free(svcctx->base.children);
538
+ }
539
+ if (svcctx->logoff_strategy != NULL) {
540
+ const oci8_logoff_strategy_t *strategy = svcctx->logoff_strategy;
541
+ void *data = strategy->prepare(svcctx);
542
+ svcctx->base.type = 0;
543
+ svcctx->logoff_strategy = NULL;
544
+ chker2(oci8_blocking_region(svcctx, strategy->execute, data), &svcctx->base);
545
+ }
546
+ return Qtrue;
547
+ }
548
+
549
+ /*
550
+ * call-seq:
551
+ * commit
552
+ *
553
+ * Commits the transaction.
554
+ */
555
+ static VALUE oci8_commit(VALUE self)
556
+ {
557
+ oci8_svcctx_t *svcctx = DATA_PTR(self);
558
+ chker2(OCITransCommit_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, OCI_DEFAULT), &svcctx->base);
559
+ return self;
560
+ }
561
+
562
+ /*
563
+ * call-seq:
564
+ * rollback
565
+ *
566
+ * Rollbacks the transaction.
567
+ */
568
+ static VALUE oci8_rollback(VALUE self)
569
+ {
570
+ oci8_svcctx_t *svcctx = DATA_PTR(self);
571
+ chker2(OCITransRollback_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, OCI_DEFAULT), &svcctx->base);
572
+ return self;
573
+ }
574
+
575
+ /*
576
+ * call-seq:
577
+ * non_blocking? -> true or false
578
+ *
579
+ * Returns +true+ if the connection is in non-blocking mode, +false+
580
+ * otherwise.
581
+ *
582
+ * See also #non_blocking=.
583
+ */
584
+ static VALUE oci8_non_blocking_p(VALUE self)
585
+ {
586
+ oci8_svcctx_t *svcctx = DATA_PTR(self);
587
+ #ifdef HAVE_RB_THREAD_BLOCKING_REGION
588
+ return svcctx->non_blocking ? Qtrue : Qfalse;
589
+ #else
590
+ sb1 non_blocking;
591
+
592
+ chker2(OCIAttrGet(svcctx->srvhp, OCI_HTYPE_SERVER, &non_blocking, 0, OCI_ATTR_NONBLOCKING_MODE, oci8_errhp), &svcctx->base);
593
+ return non_blocking ? Qtrue : Qfalse;
594
+ #endif
595
+ }
596
+
597
+ /*
598
+ * call-seq:
599
+ * non_blocking = true or false
600
+ *
601
+ * Sets +true+ to enable non-blocking mode, +false+ otherwise.
602
+ * The default setting depends on the ruby version and ruby-oci8
603
+ * version.
604
+ *
605
+ * When the connection is in blocking mode (non_blocking = false),
606
+ * SQL executions block not only the thread, but also the ruby
607
+ * process. It makes the whole application stop while a SQL execution
608
+ * needs long time.
609
+ *
610
+ * When in non-blocking mode (non_blocking = true), SQL executions
611
+ * block only the thread. It does't prevent other threads.
612
+ * A SQL execution which blocks a thread can be canceled by
613
+ * OCI8#break.
614
+ *
615
+ * === ruby 1.9
616
+ * The default setting is +true+ if the ruby-oci8 version is 2.0.3 or
617
+ * upper, +false+ otherwise.
618
+ *
619
+ * Ruby-oci8 makes the connection non-blocking by releasing ruby
620
+ * interpreter's GVL (Global VM Lock or Giant VM Lock) while OCI
621
+ * functions which may need more than one network round trips are in
622
+ * execution.
623
+ *
624
+ * === ruby 1.8
625
+ * The default setting is +false+.
626
+ *
627
+ * Ruby-oci8 makes the connection non-blocking by polling the return
628
+ * values of OCI functions. When an OCI function returns
629
+ * OCI_STILL_EXECUTING, the thread sleeps for 10 milli seconds to make
630
+ * a time for other threads to run. The sleep time is doubled up to
631
+ * 640 milli seconds as the function returns the same value.
632
+ *
633
+ */
634
+ static VALUE oci8_set_non_blocking(VALUE self, VALUE val)
635
+ {
636
+ oci8_svcctx_t *svcctx = DATA_PTR(self);
637
+ #ifdef HAVE_RB_THREAD_BLOCKING_REGION
638
+ svcctx->non_blocking = RTEST(val);
639
+ #else
640
+ sb1 non_blocking;
641
+
642
+ chker2(OCIAttrGet(svcctx->srvhp, OCI_HTYPE_SERVER, &non_blocking, 0, OCI_ATTR_NONBLOCKING_MODE, oci8_errhp), &svcctx->base);
643
+ if ((RTEST(val) && !non_blocking) || (!RTEST(val) && non_blocking)) {
644
+ /* toggle blocking / non-blocking. */
645
+ chker2(OCIAttrSet(svcctx->srvhp, OCI_HTYPE_SERVER, 0, 0, OCI_ATTR_NONBLOCKING_MODE, oci8_errhp), &svcctx->base);
646
+ }
647
+ #endif
648
+ return val;
649
+ }
650
+
651
+ /*
652
+ * call-seq:
653
+ * autocommit? -> true or false
654
+ *
655
+ * Returns +true+ if the connection is in autocommit mode, +false+
656
+ * otherwise. The default value is +false+.
657
+ */
658
+ static VALUE oci8_autocommit_p(VALUE self)
659
+ {
660
+ oci8_svcctx_t *svcctx = DATA_PTR(self);
661
+ return svcctx->is_autocommit ? Qtrue : Qfalse;
662
+ }
663
+
664
+ /*
665
+ * call-seq:
666
+ * autocommit = true or false
667
+ *
668
+ * Sets the autocommit mode. The default value is +false+.
669
+ */
670
+ static VALUE oci8_set_autocommit(VALUE self, VALUE val)
671
+ {
672
+ oci8_svcctx_t *svcctx = DATA_PTR(self);
673
+ svcctx->is_autocommit = RTEST(val);
674
+ return val;
675
+ }
676
+
677
+ /*
678
+ * call-seq:
679
+ * long_read_len -> fixnum
680
+ *
681
+ * Gets the maximum length in bytes to fetch a LONG or LONG RAW
682
+ * column. The default value is 65535.
683
+ *
684
+ * If the actual data length is longer than long_read_len,
685
+ * "ORA-01406: fetched column value was truncated" is raised.
686
+ *
687
+ * Note: long_read_len is also used for XMLTYPE data type in 2.0.
688
+ */
689
+ static VALUE oci8_long_read_len(VALUE self)
690
+ {
691
+ oci8_svcctx_t *svcctx = DATA_PTR(self);
692
+ return svcctx->long_read_len;
693
+ }
694
+
695
+ /*
696
+ * call-seq:
697
+ * long_read_len = fixnum
698
+ *
699
+ * Sets the maximum length in bytes to fetch a LONG or LONG RAW
700
+ * column.
701
+ *
702
+ * See also #long_read_len
703
+ *
704
+ */
705
+ static VALUE oci8_set_long_read_len(VALUE self, VALUE val)
706
+ {
707
+ oci8_svcctx_t *svcctx = DATA_PTR(self);
708
+ Check_Type(val, T_FIXNUM);
709
+ svcctx->long_read_len = val;
710
+ return val;
711
+ }
712
+
713
+ /*
714
+ * call-seq:
715
+ * break
716
+ *
717
+ * Cancels the executing SQL.
718
+ *
719
+ * See also #non_blocking=.
720
+ */
721
+ static VALUE oci8_break(VALUE self)
722
+ {
723
+ oci8_svcctx_t *svcctx = DATA_PTR(self);
724
+
725
+ if (NIL_P(svcctx->executing_thread)) {
726
+ return Qfalse;
727
+ }
728
+ #ifndef HAVE_RB_THREAD_BLOCKING_REGION
729
+ chker2(OCIBreak(svcctx->base.hp.ptr, oci8_errhp), &svcctx->base);
730
+ #endif
731
+ rb_thread_wakeup(svcctx->executing_thread);
732
+ return Qtrue;
733
+ }
734
+
735
+ /*
736
+ * call-seq:
737
+ * prefetch_rows = number
738
+ *
739
+ * Sets the prefetch rows size. The default value is one.
740
+ * When a select statement is executed, the OCI library allocate
741
+ * prefetch buffer to reduce the number of network round trips by
742
+ * retrieving specified number of rows in one round trip.
743
+ *
744
+ * Note: Active record adaptors set 100 by default.
745
+ */
746
+ static VALUE oci8_set_prefetch_rows(VALUE self, VALUE val)
747
+ {
748
+ rb_ivar_set(self, id_at_prefetch_rows, val);
749
+ return val;
750
+ }
751
+
752
+ /*
753
+ * call-seq:
754
+ * oracle_server_vernum -> an integer
755
+ *
756
+ * <b>(new in 2.0.1)</b>
757
+ *
758
+ * Returns a numerical format of the Oracle server version.
759
+ *
760
+ * See also: #oracle_server_version
761
+ */
762
+ static VALUE oci8_oracle_server_vernum(VALUE self)
763
+ {
764
+ oci8_svcctx_t *svcctx = DATA_PTR(self);
765
+ char buf[100];
766
+ ub4 version;
767
+
768
+ chker2(OCIServerRelease(svcctx->base.hp.ptr, oci8_errhp, (text*)buf, sizeof(buf), (ub1)svcctx->base.type, &version), &svcctx->base);
769
+ return UINT2NUM(version);
770
+ }
771
+
772
+ /*
773
+ * call-seq:
774
+ * ping -> true or false
775
+ *
776
+ * <b>(new in 2.0.2)</b>
777
+ *
778
+ * Makes a round trip call to the server to confirm that the connection and
779
+ * the server are active.
780
+ *
781
+ * OCI8#ping also can be used to flush all the pending OCI client-side calls
782
+ * to the server if any exist.
783
+ *
784
+ * === Oracle 10.2 client or upper
785
+ * A dummy round trip call is made by a newly added OCI function
786
+ * OCIPing[http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14250/oci16msc007.htm#sthref3540] in Oracle 10.2.
787
+ *
788
+ * === Oracle 10.1 client or lower
789
+ * A simple PL/SQL block "BEGIN NULL; END;" is executed to make a round trip call.
790
+ */
791
+ static VALUE oci8_ping(VALUE self)
792
+ {
793
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(self);
794
+ sword rv;
795
+
796
+ if (have_OCIPing_nb) {
797
+ /* Oracle 10.2 or upper */
798
+ rv = OCIPing_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, OCI_DEFAULT);
799
+ } else {
800
+ /* Oracle 10.1 or lower */
801
+ rv = oci8_exec_sql(svcctx, "BEGIN NULL; END;", 0U, NULL, 0U, NULL, 0);
802
+ }
803
+ return rv == OCI_SUCCESS ? Qtrue : FALSE;
804
+ }
805
+
806
+ /*
807
+ * call-seq:
808
+ * client_identifier = string or nil
809
+ *
810
+ * <b>(new in 2.0.3)</b>
811
+ *
812
+ * Sets the client ID. This information is stored in the V$SESSION
813
+ * view.
814
+ *
815
+ * === Oracle 9i client or upper
816
+ *
817
+ * This doesn't perform network round trips. The change is reflected
818
+ * to the server by the next round trip such as OCI8#exec, OCI8#ping,
819
+ * etc.
820
+ *
821
+ * === Oracle 8i client or lower
822
+ *
823
+ * This executes the following PL/SQL block internally.
824
+ * The change is reflected immediately by a network round trip.
825
+ *
826
+ * BEGIN
827
+ * DBMS_SESSION.SET_IDENTIFIER(:client_id);
828
+ * END;
829
+ *
830
+ * See {Oracle Manual: Oracle Database PL/SQL Packages and Types Reference}[http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14258/d_sessio.htm#i996935]
831
+ *
832
+ */
833
+ static VALUE oci8_set_client_identifier(VALUE self, VALUE val)
834
+ {
835
+ char *ptr;
836
+ ub4 size;
837
+
838
+ if (!NIL_P(val)) {
839
+ OCI8SafeStringValue(val);
840
+ ptr = RSTRING_PTR(val);
841
+ size = RSTRING_LEN(val);
842
+ } else {
843
+ ptr = "";
844
+ size = 0;
845
+ }
846
+
847
+ if (oracle_client_version >= ORAVERNUM(9, 2, 0, 3, 0) || size > 0) {
848
+ if (size > 0 && ptr[0] == ':') {
849
+ rb_raise(rb_eArgError, "client identifier should not start with ':'.");
850
+ }
851
+ chker2(OCIAttrSet(oci8_get_oci_session(self), OCI_HTYPE_SESSION, ptr,
852
+ size, OCI_ATTR_CLIENT_IDENTIFIER, oci8_errhp),
853
+ DATA_PTR(self));
854
+ } else {
855
+ /* Workaround for Bug 2449486 */
856
+ oci8_exec_sql_var_t bind_vars[1];
857
+
858
+ /* :client_id */
859
+ bind_vars[0].valuep = ptr;
860
+ bind_vars[0].value_sz = size;
861
+ bind_vars[0].dty = SQLT_CHR;
862
+ bind_vars[0].indp = NULL;
863
+ bind_vars[0].alenp = NULL;
864
+
865
+ oci8_exec_sql(oci8_get_svcctx(self),
866
+ "BEGIN\n"
867
+ " DBMS_SESSION.SET_IDENTIFIER(:client_id);\n"
868
+ "END;\n", 0, NULL, 1, bind_vars, 1);
869
+ }
870
+ return val;
871
+ }
872
+
873
+ /*
874
+ * call-seq:
875
+ * module = string or nil
876
+ *
877
+ * <b>(new in 2.0.3)</b>
878
+ *
879
+ * Sets the name of the current module. This information is
880
+ * stored in the V$SESSION view and is also stored in the V$SQL view
881
+ * and the V$SQLAREA view when a SQL statement is executed and the SQL
882
+ * statement is first parsed in the Oracle server.
883
+ *
884
+ * === Oracle 10g client or upper
885
+ *
886
+ * This doesn't perform network round trips. The change is reflected
887
+ * to the server by the next round trip such as OCI8#exec, OCI8#ping,
888
+ * etc.
889
+ *
890
+ * === Oracle 9i client or lower
891
+ *
892
+ * This executes the following PL/SQL block internally.
893
+ * The change is reflected immediately by a network round trip.
894
+ *
895
+ * DECLARE
896
+ * action VARCHAR2(32);
897
+ * BEGIN
898
+ * -- retrieve action name.
899
+ * SELECT SYS_CONTEXT('USERENV','ACTION') INTO action FROM DUAL;
900
+ * -- change module name without modifying the action name.
901
+ * DBMS_APPLICATION_INFO.SET_MODULE(:module, action);
902
+ * END;
903
+ *
904
+ * See {Oracle Manual: Oracle Database PL/SQL Packages and Types Reference}[http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14258/d_appinf.htm#i999254]
905
+ *
906
+ */
907
+ static VALUE oci8_set_module(VALUE self, VALUE val)
908
+ {
909
+ char *ptr;
910
+ ub4 size;
911
+
912
+ if (!NIL_P(val)) {
913
+ OCI8SafeStringValue(val);
914
+ ptr = RSTRING_PTR(val);
915
+ size = RSTRING_LEN(val);
916
+ } else {
917
+ ptr = "";
918
+ size = 0;
919
+ }
920
+ if (oracle_client_version >= ORAVER_10_1) {
921
+ /* Oracle 10g or upper */
922
+ chker2(OCIAttrSet(oci8_get_oci_session(self), OCI_HTYPE_SESSION, ptr,
923
+ size, OCI_ATTR_MODULE, oci8_errhp),
924
+ DATA_PTR(self));
925
+ } else {
926
+ /* Oracle 9i or lower */
927
+ oci8_exec_sql_var_t bind_vars[1];
928
+
929
+ /* :module */
930
+ bind_vars[0].valuep = ptr;
931
+ bind_vars[0].value_sz = size;
932
+ bind_vars[0].dty = SQLT_CHR;
933
+ bind_vars[0].indp = NULL;
934
+ bind_vars[0].alenp = NULL;
935
+
936
+ oci8_exec_sql(oci8_get_svcctx(self),
937
+ "DECLARE\n"
938
+ " action VARCHAR2(32);\n"
939
+ "BEGIN\n"
940
+ " SELECT SYS_CONTEXT('USERENV','ACTION') INTO action FROM DUAL;\n"
941
+ " DBMS_APPLICATION_INFO.SET_MODULE(:module, action);\n"
942
+ "END;\n", 0, NULL, 1, bind_vars, 1);
943
+ }
944
+ return self;
945
+ }
946
+
947
+ /*
948
+ * call-seq:
949
+ * action = string or nil
950
+ *
951
+ * <b>(new in 2.0.3)</b>
952
+ *
953
+ * Sets the name of the current action within the current module.
954
+ * This information is stored in the V$SESSION view and is also
955
+ * stored in the V$SQL view and the V$SQLAREA view when a SQL
956
+ * statement is executed and the SQL statement is first parsed
957
+ * in the Oracle server.
958
+ *
959
+ * === Oracle 10g client or upper
960
+ *
961
+ * This doesn't perform network round trips. The change is reflected
962
+ * to the server by the next round trip such as OCI8#exec, OCI8#ping,
963
+ * etc.
964
+ *
965
+ * === Oracle 9i client or lower
966
+ *
967
+ * This executes the following PL/SQL block internally.
968
+ * The change is reflected immediately by a network round trip.
969
+ *
970
+ * BEGIN
971
+ * DBMS_APPLICATION_INFO.SET_ACTION(:action);
972
+ * END;
973
+ *
974
+ * See {Oracle Manual: Oracle Database PL/SQL Packages and Types Reference}[http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14258/d_appinf.htm#i999254]
975
+ *
976
+ */
977
+ static VALUE oci8_set_action(VALUE self, VALUE val)
978
+ {
979
+ char *ptr;
980
+ ub4 size;
981
+
982
+ if (!NIL_P(val)) {
983
+ OCI8SafeStringValue(val);
984
+ ptr = RSTRING_PTR(val);
985
+ size = RSTRING_LEN(val);
986
+ } else {
987
+ ptr = "";
988
+ size = 0;
989
+ }
990
+ if (oracle_client_version >= ORAVER_10_1) {
991
+ /* Oracle 10g or upper */
992
+ chker2(OCIAttrSet(oci8_get_oci_session(self), OCI_HTYPE_SESSION, ptr,
993
+ size, OCI_ATTR_ACTION, oci8_errhp),
994
+ DATA_PTR(self));
995
+ } else {
996
+ /* Oracle 9i or lower */
997
+ oci8_exec_sql_var_t bind_vars[1];
998
+
999
+ /* :action */
1000
+ bind_vars[0].valuep = ptr;
1001
+ bind_vars[0].value_sz = size;
1002
+ bind_vars[0].dty = SQLT_CHR;
1003
+ bind_vars[0].indp = NULL;
1004
+ bind_vars[0].alenp = NULL;
1005
+
1006
+ oci8_exec_sql(oci8_get_svcctx(self),
1007
+ "BEGIN\n"
1008
+ " DBMS_APPLICATION_INFO.SET_ACTION(:action);\n"
1009
+ "END;\n", 0, NULL, 1, bind_vars, 1);
1010
+ }
1011
+ return val;
1012
+ }
1013
+
1014
+ /*
1015
+ * call-seq:
1016
+ * client_info = string or nil
1017
+ *
1018
+ * <b>(new in 2.0.3)</b>
1019
+ *
1020
+ * Sets additional information about the client application.
1021
+ * This information is stored in the V$SESSION view.
1022
+ *
1023
+ * === Oracle 10g client or upper
1024
+ *
1025
+ * This doesn't perform network round trips. The change is reflected
1026
+ * to the server by the next round trip such as OCI8#exec, OCI8#ping,
1027
+ * etc.
1028
+ *
1029
+ * === Oracle 9i client or lower
1030
+ *
1031
+ * This executes the following PL/SQL block internally.
1032
+ * The change is reflected immediately by a network round trip.
1033
+ *
1034
+ * BEGIN
1035
+ * DBMS_APPLICATION_INFO.SET_CLIENT_INFO(:client_info);
1036
+ * END;
1037
+ *
1038
+ * See {Oracle Manual: Oracle Database PL/SQL Packages and Types Reference}[http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14258/d_appinf.htm#CHEJCFGG]
1039
+ */
1040
+ static VALUE oci8_set_client_info(VALUE self, VALUE val)
1041
+ {
1042
+ char *ptr;
1043
+ ub4 size;
1044
+
1045
+ if (!NIL_P(val)) {
1046
+ OCI8SafeStringValue(val);
1047
+ ptr = RSTRING_PTR(val);
1048
+ size = RSTRING_LEN(val);
1049
+ } else {
1050
+ ptr = "";
1051
+ size = 0;
1052
+ }
1053
+ if (oracle_client_version >= ORAVER_10_1) {
1054
+ /* Oracle 10g or upper */
1055
+ chker2(OCIAttrSet(oci8_get_oci_session(self), OCI_HTYPE_SESSION, ptr,
1056
+ size, OCI_ATTR_CLIENT_INFO, oci8_errhp),
1057
+ DATA_PTR(self));
1058
+ } else {
1059
+ /* Oracle 9i or lower */
1060
+ oci8_exec_sql_var_t bind_vars[1];
1061
+
1062
+ /* :client_info */
1063
+ bind_vars[0].valuep = ptr;
1064
+ bind_vars[0].value_sz = size;
1065
+ bind_vars[0].dty = SQLT_CHR;
1066
+ bind_vars[0].indp = NULL;
1067
+ bind_vars[0].alenp = NULL;
1068
+
1069
+ oci8_exec_sql(oci8_get_svcctx(self),
1070
+ "BEGIN\n"
1071
+ " DBMS_APPLICATION_INFO.SET_CLIENT_INFO(:client_info);\n"
1072
+ "END;\n", 0, NULL, 1, bind_vars, 1);
1073
+ }
1074
+ return val;
1075
+ }
1076
+
1077
+ VALUE Init_oci8(void)
1078
+ {
1079
+ #if 0
1080
+ oci8_cOCIHandle = rb_define_class("OCIHandle", rb_cObject);
1081
+ cOCI8 = rb_define_class("OCI8", oci8_cOCIHandle);
1082
+ #endif
1083
+ cOCI8 = oci8_define_class("OCI8", &oci8_svcctx_vtable);
1084
+ cSession = oci8_define_class_under(cOCI8, "Session", &oci8_svcctx_associate_vtable);
1085
+ cServer = oci8_define_class_under(cOCI8, "Server", &oci8_svcctx_associate_vtable);
1086
+ id_at_session_handle = rb_intern("@session_handle");
1087
+ id_at_server_handle = rb_intern("@server_handle");
1088
+
1089
+ oracle_client_vernum = INT2FIX(oracle_client_version);
1090
+ if (have_OCIClientVersion) {
1091
+ sword major, minor, update, patch, port_update;
1092
+ OCIClientVersion(&major, &minor, &update, &patch, &port_update);
1093
+ oracle_client_vernum = INT2FIX(ORAVERNUM(major, minor, update, patch, port_update));
1094
+ }
1095
+
1096
+ sym_SYSDBA = ID2SYM(rb_intern("SYSDBA"));
1097
+ sym_SYSOPER = ID2SYM(rb_intern("SYSOPER"));
1098
+ id_at_prefetch_rows = rb_intern("@prefetch_rows");
1099
+ id_set_prefetch_rows = rb_intern("prefetch_rows=");
1100
+
1101
+ rb_define_const(cOCI8, "VERSION", rb_obj_freeze(rb_usascii_str_new_cstr(OCI8LIB_VERSION)));
1102
+ rb_define_singleton_method_nodoc(cOCI8, "oracle_client_vernum", oci8_s_oracle_client_vernum, 0);
1103
+ rb_define_singleton_method_nodoc(cOCI8, "__set_property", oci8_s_set_property, 2);
1104
+ rb_define_singleton_method(cOCI8, "error_message", oci8_s_error_message, 1);
1105
+ rb_define_private_method(cOCI8, "parse_connect_string", oci8_parse_connect_string, 1);
1106
+ rb_define_private_method(cOCI8, "logon", oci8_logon, 3);
1107
+ rb_define_private_method(cOCI8, "allocate_handles", oci8_allocate_handles, 0);
1108
+ rb_define_private_method(cOCI8, "session_handle", oci8_get_session_handle, 0);
1109
+ rb_define_private_method(cOCI8, "server_handle", oci8_get_server_handle, 0);
1110
+ rb_define_private_method(cOCI8, "server_attach", oci8_server_attach, 2);
1111
+ rb_define_private_method(cOCI8, "session_begin", oci8_session_begin, 2);
1112
+ rb_define_method(cOCI8, "logoff", oci8_svcctx_logoff, 0);
1113
+ rb_define_method(cOCI8, "commit", oci8_commit, 0);
1114
+ rb_define_method(cOCI8, "rollback", oci8_rollback, 0);
1115
+ rb_define_method(cOCI8, "non_blocking?", oci8_non_blocking_p, 0);
1116
+ rb_define_method(cOCI8, "non_blocking=", oci8_set_non_blocking, 1);
1117
+ rb_define_method(cOCI8, "autocommit?", oci8_autocommit_p, 0);
1118
+ rb_define_method(cOCI8, "autocommit=", oci8_set_autocommit, 1);
1119
+ rb_define_method(cOCI8, "long_read_len", oci8_long_read_len, 0);
1120
+ rb_define_method(cOCI8, "long_read_len=", oci8_set_long_read_len, 1);
1121
+ rb_define_method(cOCI8, "break", oci8_break, 0);
1122
+ rb_define_method(cOCI8, "prefetch_rows=", oci8_set_prefetch_rows, 1);
1123
+ rb_define_private_method(cOCI8, "oracle_server_vernum", oci8_oracle_server_vernum, 0);
1124
+ rb_define_method(cOCI8, "ping", oci8_ping, 0);
1125
+ rb_define_method(cOCI8, "client_identifier=", oci8_set_client_identifier, 1);
1126
+ rb_define_method(cOCI8, "module=", oci8_set_module, 1);
1127
+ rb_define_method(cOCI8, "action=", oci8_set_action, 1);
1128
+ rb_define_method(cOCI8, "client_info=", oci8_set_client_info, 1);
1129
+ rb_define_attr(cOCI8, "last_error", 1, 1);
1130
+ return cOCI8;
1131
+ }
1132
+
1133
+ oci8_svcctx_t *oci8_get_svcctx(VALUE obj)
1134
+ {
1135
+ return (oci8_svcctx_t *)oci8_get_handle(obj, cOCI8);
1136
+ }
1137
+
1138
+ OCISvcCtx *oci8_get_oci_svcctx(VALUE obj)
1139
+ {
1140
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(obj);
1141
+ return svcctx->base.hp.svc;
1142
+ }
1143
+
1144
+ OCISession *oci8_get_oci_session(VALUE obj)
1145
+ {
1146
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(obj);
1147
+ return svcctx->usrhp;
1148
+ }
1149
+
1150
+ void oci8_check_pid_consistency(oci8_svcctx_t *svcctx)
1151
+ {
1152
+ if (svcctx->pid != getpid()) {
1153
+ rb_raise(rb_eRuntimeError, "The connection cannot be reused in the forked process.");
1154
+ }
1155
+ }
1156
+