ruby-staci 2.2.9

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 (115) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +14 -0
  3. data/COPYING +30 -0
  4. data/COPYING_old +64 -0
  5. data/ChangeLog +3826 -0
  6. data/Makefile +92 -0
  7. data/NEWS +1194 -0
  8. data/README.md +66 -0
  9. data/dist-files +113 -0
  10. data/docs/bind-array-to-in_cond.md +38 -0
  11. data/docs/conflicts-local-connections-and-processes.md +98 -0
  12. data/docs/hanging-after-inactivity.md +63 -0
  13. data/docs/install-binary-package.md +44 -0
  14. data/docs/install-full-client.md +111 -0
  15. data/docs/install-instant-client.md +194 -0
  16. data/docs/install-on-osx.md +133 -0
  17. data/docs/ldap-auth-and-function-interposition.md +123 -0
  18. data/docs/number-type-mapping.md +79 -0
  19. data/docs/osx-install-dev-tools.png +0 -0
  20. data/docs/platform-specific-issues.md +164 -0
  21. data/docs/report-installation-issue.md +50 -0
  22. data/docs/timeout-parameters.md +94 -0
  23. data/ext/oci8/.document +18 -0
  24. data/ext/oci8/MANIFEST +18 -0
  25. data/ext/oci8/apiwrap.c.tmpl +178 -0
  26. data/ext/oci8/apiwrap.h.tmpl +61 -0
  27. data/ext/oci8/apiwrap.rb +96 -0
  28. data/ext/oci8/apiwrap.yml +1322 -0
  29. data/ext/oci8/attr.c +57 -0
  30. data/ext/oci8/bind.c +838 -0
  31. data/ext/oci8/connection_pool.c +216 -0
  32. data/ext/oci8/encoding.c +196 -0
  33. data/ext/oci8/env.c +139 -0
  34. data/ext/oci8/error.c +385 -0
  35. data/ext/oci8/extconf.rb +219 -0
  36. data/ext/oci8/hook_funcs.c +407 -0
  37. data/ext/oci8/lob.c +1278 -0
  38. data/ext/oci8/metadata.c +279 -0
  39. data/ext/oci8/object.c +919 -0
  40. data/ext/oci8/oci8.c +1058 -0
  41. data/ext/oci8/oci8.h +556 -0
  42. data/ext/oci8/oci8lib.c +704 -0
  43. data/ext/oci8/ocidatetime.c +506 -0
  44. data/ext/oci8/ocihandle.c +852 -0
  45. data/ext/oci8/ocinumber.c +1922 -0
  46. data/ext/oci8/oraconf.rb +1145 -0
  47. data/ext/oci8/oradate.c +670 -0
  48. data/ext/oci8/oranumber_util.c +352 -0
  49. data/ext/oci8/oranumber_util.h +24 -0
  50. data/ext/oci8/plthook.h +66 -0
  51. data/ext/oci8/plthook_elf.c +702 -0
  52. data/ext/oci8/plthook_osx.c +505 -0
  53. data/ext/oci8/plthook_win32.c +391 -0
  54. data/ext/oci8/post-config.rb +5 -0
  55. data/ext/oci8/stmt.c +448 -0
  56. data/ext/oci8/thread_util.c +81 -0
  57. data/ext/oci8/thread_util.h +18 -0
  58. data/ext/oci8/util.c +71 -0
  59. data/ext/oci8/win32.c +117 -0
  60. data/lib/.document +1 -0
  61. data/lib/dbd/STACI.rb +591 -0
  62. data/lib/oci8/.document +8 -0
  63. data/lib/oci8/bindtype.rb +333 -0
  64. data/lib/oci8/check_load_error.rb +146 -0
  65. data/lib/oci8/compat.rb +117 -0
  66. data/lib/oci8/connection_pool.rb +179 -0
  67. data/lib/oci8/cursor.rb +605 -0
  68. data/lib/oci8/datetime.rb +605 -0
  69. data/lib/oci8/encoding-init.rb +45 -0
  70. data/lib/oci8/encoding.yml +537 -0
  71. data/lib/oci8/metadata.rb +2148 -0
  72. data/lib/oci8/object.rb +641 -0
  73. data/lib/oci8/oci8.rb +756 -0
  74. data/lib/oci8/ocihandle.rb +591 -0
  75. data/lib/oci8/oracle_version.rb +153 -0
  76. data/lib/oci8/properties.rb +196 -0
  77. data/lib/oci8/version.rb +3 -0
  78. data/lib/ruby-staci.rb +1 -0
  79. data/lib/staci.rb +190 -0
  80. data/metaconfig +142 -0
  81. data/pre-distclean.rb +7 -0
  82. data/ruby-aci.gemspec +83 -0
  83. data/setup.rb +1342 -0
  84. data/test/README.md +37 -0
  85. data/test/config.rb +201 -0
  86. data/test/setup_test_object.sql +199 -0
  87. data/test/setup_test_package.sql +59 -0
  88. data/test/test_all.rb +56 -0
  89. data/test/test_appinfo.rb +62 -0
  90. data/test/test_array_dml.rb +333 -0
  91. data/test/test_bind_array.rb +70 -0
  92. data/test/test_bind_boolean.rb +99 -0
  93. data/test/test_bind_integer.rb +47 -0
  94. data/test/test_bind_raw.rb +45 -0
  95. data/test/test_bind_string.rb +105 -0
  96. data/test/test_bind_time.rb +177 -0
  97. data/test/test_break.rb +124 -0
  98. data/test/test_clob.rb +86 -0
  99. data/test/test_connection_pool.rb +124 -0
  100. data/test/test_connstr.rb +220 -0
  101. data/test/test_datetime.rb +585 -0
  102. data/test/test_dbi.rb +365 -0
  103. data/test/test_dbi_clob.rb +53 -0
  104. data/test/test_encoding.rb +103 -0
  105. data/test/test_error.rb +87 -0
  106. data/test/test_metadata.rb +2674 -0
  107. data/test/test_object.rb +546 -0
  108. data/test/test_oci8.rb +624 -0
  109. data/test/test_oracle_version.rb +68 -0
  110. data/test/test_oradate.rb +255 -0
  111. data/test/test_oranumber.rb +786 -0
  112. data/test/test_package_type.rb +981 -0
  113. data/test/test_properties.rb +17 -0
  114. data/test/test_rowid.rb +32 -0
  115. metadata +158 -0
data/ext/oci8/oci8.c ADDED
@@ -0,0 +1,1058 @@
1
+ /* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * oci8.c - part of ruby-oci8
4
+ *
5
+ * Copyright (C) 2002-2019 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 ACI_ATTR_CLIENT_IDENTIFIER
22
+ #define ACI_ATTR_CLIENT_IDENTIFIER 278
23
+ #endif
24
+ #ifndef ACI_ATTR_MODULE
25
+ #define ACI_ATTR_MODULE 366
26
+ #endif
27
+ #ifndef ACI_ATTR_ACTION
28
+ #define ACI_ATTR_ACTION 367
29
+ #endif
30
+ #ifndef ACI_ATTR_CLIENT_INFO
31
+ #define ACI_ATTR_CLIENT_INFO 368
32
+ #endif
33
+ #ifndef ACI_ATTR_TRANSACTION_IN_PROGRESS
34
+ #define ACI_ATTR_TRANSACTION_IN_PROGRESS 484
35
+ #endif
36
+
37
+ #define OCI8_STATE_SESSION_BEGIN_WAS_CALLED 0x01
38
+ #define OCI8_STATE_SERVER_ATTACH_WAS_CALLED 0x02
39
+ #define OCI8_STATE_CPOOL 0x04
40
+
41
+ static VALUE cOCI8;
42
+ static VALUE cSession;
43
+ static VALUE cServer;
44
+ static VALUE cEnvironment;
45
+ static VALUE cProcess;
46
+ static ID id_at_session_handle;
47
+ static ID id_at_server_handle;
48
+
49
+ static VALUE dummy_env_method_missing(int argc, VALUE *argv, VALUE self)
50
+ {
51
+ VALUE obj = rb_cv_get(cOCI8, "@@environment_handle");
52
+ VALUE method_id, args;
53
+
54
+ if (self == obj) {
55
+ oci8_base_t *base;
56
+ obj = rb_obj_alloc(cEnvironment);
57
+ base = DATA_PTR(obj);
58
+ base->type = ACI_HTYPE_ENV;
59
+ base->hp.ptr = oci8_envhp;
60
+ base->self = Qnil;
61
+ rb_cv_set(cOCI8, "@@environment_handle", obj);
62
+ }
63
+
64
+ rb_scan_args(argc, argv, "1*", &method_id, &args);
65
+ Check_Type(method_id, T_SYMBOL);
66
+ return rb_apply(obj, SYM2ID(method_id), args);
67
+ }
68
+
69
+ static void oci8_handle_dont_free(oci8_base_t *base)
70
+ {
71
+ base->type = 0;
72
+ base->closed = 1;
73
+ base->hp.ptr = NULL;
74
+ }
75
+
76
+ static const oci8_handle_data_type_t oci8_session_data_type = {
77
+ {
78
+ "STACI::Session",
79
+ {
80
+ NULL,
81
+ oci8_handle_cleanup,
82
+ oci8_handle_size,
83
+ },
84
+ &oci8_handle_data_type.rb_data_type, NULL,
85
+ #ifdef RUBY_TYPED_WB_PROTECTED
86
+ RUBY_TYPED_WB_PROTECTED,
87
+ #endif
88
+ },
89
+ oci8_handle_dont_free,
90
+ sizeof(oci8_base_t),
91
+ };
92
+
93
+ static VALUE oci8_session_alloc(VALUE klass)
94
+ {
95
+ return oci8_allocate_typeddata(klass, &oci8_session_data_type);
96
+ }
97
+
98
+ static const oci8_handle_data_type_t oci8_server_data_type = {
99
+ {
100
+ "STACI::Server",
101
+ {
102
+ NULL,
103
+ oci8_handle_cleanup,
104
+ oci8_handle_size,
105
+ },
106
+ &oci8_handle_data_type.rb_data_type, NULL,
107
+ #ifdef RUBY_TYPED_WB_PROTECTED
108
+ RUBY_TYPED_WB_PROTECTED,
109
+ #endif
110
+ },
111
+ oci8_handle_dont_free,
112
+ sizeof(oci8_base_t),
113
+ };
114
+
115
+ static VALUE oci8_server_alloc(VALUE klass)
116
+ {
117
+ return oci8_allocate_typeddata(klass, &oci8_server_data_type);
118
+ }
119
+
120
+ static const oci8_handle_data_type_t oci8_environment_data_type = {
121
+ {
122
+ "STACI::Environment",
123
+ {
124
+ NULL,
125
+ oci8_handle_cleanup,
126
+ oci8_handle_size,
127
+ },
128
+ &oci8_handle_data_type.rb_data_type, NULL,
129
+ #ifdef RUBY_TYPED_WB_PROTECTED
130
+ RUBY_TYPED_WB_PROTECTED,
131
+ #endif
132
+ },
133
+ oci8_handle_dont_free,
134
+ sizeof(oci8_base_t),
135
+ };
136
+
137
+ static VALUE oci8_environment_alloc(VALUE klass)
138
+ {
139
+ return oci8_allocate_typeddata(klass, &oci8_environment_data_type);
140
+ }
141
+
142
+ static const oci8_handle_data_type_t oci8_process_data_type = {
143
+ {
144
+ "STACI::Process",
145
+ {
146
+ NULL,
147
+ oci8_handle_cleanup,
148
+ oci8_handle_size,
149
+ },
150
+ &oci8_handle_data_type.rb_data_type, NULL,
151
+ #ifdef RUBY_TYPED_WB_PROTECTED
152
+ RUBY_TYPED_WB_PROTECTED,
153
+ #endif
154
+ },
155
+ oci8_handle_dont_free,
156
+ sizeof(oci8_base_t),
157
+ };
158
+
159
+ static VALUE oci8_process_alloc(VALUE klass)
160
+ {
161
+ return oci8_allocate_typeddata(klass, &oci8_process_data_type);
162
+ }
163
+
164
+ static void copy_session_handle(oci8_svcctx_t *svcctx)
165
+ {
166
+ VALUE obj = rb_ivar_get(svcctx->base.self, id_at_session_handle);
167
+ oci8_base_t *base = oci8_check_typeddata(obj, &oci8_session_data_type, 1);
168
+
169
+ base->type = ACI_HTYPE_SESSION;
170
+ base->hp.usrhp = svcctx->usrhp;
171
+ }
172
+
173
+ static void copy_server_handle(oci8_svcctx_t *svcctx)
174
+ {
175
+ VALUE obj = rb_ivar_get(svcctx->base.self, id_at_server_handle);
176
+ oci8_base_t *base = oci8_check_typeddata(obj, &oci8_server_data_type, 1);
177
+
178
+ base->type = ACI_HTYPE_SERVER;
179
+ base->hp.srvhp = svcctx->srvhp;
180
+ }
181
+
182
+ static void oci8_svcctx_free(oci8_base_t *base)
183
+ {
184
+ oci8_svcctx_t *svcctx = (oci8_svcctx_t *)base;
185
+ oci8_temp_lob_t *lob;
186
+
187
+ lob = svcctx->temp_lobs;
188
+ while (lob != NULL) {
189
+ oci8_temp_lob_t *lob_next = lob->next;
190
+
191
+ ACIDescriptorFree(lob->lob, ACI_DTYPE_LOB);
192
+ xfree(lob);
193
+ lob = lob_next;
194
+ }
195
+ svcctx->temp_lobs = NULL;
196
+
197
+ if (svcctx->logoff_strategy != NULL) {
198
+ const oci8_logoff_strategy_t *strategy = svcctx->logoff_strategy;
199
+ void *data = strategy->prepare(svcctx);
200
+ int rv;
201
+ svcctx->base.type = 0;
202
+ svcctx->base.closed = 1;
203
+ svcctx->logoff_strategy = NULL;
204
+ rv = oci8_run_native_thread(strategy->execute, data);
205
+ if (rv != 0) {
206
+ errno = rv;
207
+ #ifdef WIN32
208
+ rb_sys_fail("_beginthread");
209
+ #else
210
+ rb_sys_fail("pthread_create");
211
+ #endif
212
+ }
213
+ }
214
+ svcctx->base.type = 0;
215
+ svcctx->base.closed = 1;
216
+ }
217
+
218
+ static const oci8_handle_data_type_t oci8_svcctx_data_type = {
219
+ {
220
+ "STACI",
221
+ {
222
+ NULL,
223
+ oci8_handle_cleanup,
224
+ oci8_handle_size,
225
+ },
226
+ &oci8_handle_data_type.rb_data_type, NULL,
227
+ #ifdef RUBY_TYPED_WB_PROTECTED
228
+ RUBY_TYPED_WB_PROTECTED,
229
+ #endif
230
+ },
231
+ oci8_svcctx_free,
232
+ sizeof(oci8_svcctx_t),
233
+ };
234
+
235
+ static VALUE oci8_svcctx_alloc(VALUE klass)
236
+ {
237
+ VALUE self = oci8_allocate_typeddata(klass, &oci8_svcctx_data_type);
238
+ oci8_svcctx_t *svcctx = (oci8_svcctx_t *)RTYPEDDATA_DATA(self);
239
+ VALUE obj;
240
+
241
+ svcctx->executing_thread = Qnil;
242
+ /* set session handle */
243
+ obj = rb_obj_alloc(cSession);
244
+ rb_ivar_set(self, id_at_session_handle, obj);
245
+ oci8_link_to_parent(DATA_PTR(obj), &svcctx->base);
246
+ /* set server handle */
247
+ obj = rb_obj_alloc(cServer);
248
+ rb_ivar_set(self, id_at_server_handle, obj);
249
+ oci8_link_to_parent(DATA_PTR(obj), &svcctx->base);
250
+
251
+ svcctx->pid = getpid();
252
+ svcctx->is_autocommit = 0;
253
+ svcctx->non_blocking = 1;
254
+ svcctx->long_read_len = INT2FIX(65535);
255
+ return self;
256
+ }
257
+
258
+ static VALUE oracle_client_vernum; /* Oracle client version number */
259
+
260
+ /*
261
+ * @overload oracle_client_vernum
262
+ *
263
+ * Returns Oracle client version as <i>Integer</i>.
264
+ * The Oracle version is encoded in 32-bit integer.
265
+ * It is devided into 5 parts: 8, 4, 8, 4 and 8 bits.
266
+ *
267
+ * @example
268
+ * # Oracle 10.2.0.4
269
+ * oracle_client_vernum # => 0x0a200400
270
+ * # => 0x0a 2 00 4 00
271
+ * # => 10.2.0.4.0
272
+ *
273
+ * # Oracle 11.1.0.7.0
274
+ * oracle_client_vernum # => 0x0b100700
275
+ * # => 0x0b 1 00 7 00
276
+ * # => 11.1.0.7.0
277
+ *
278
+ * @return [Integer]
279
+ * @private
280
+ */
281
+ static VALUE oci8_s_oracle_client_vernum(VALUE klass)
282
+ {
283
+ return oracle_client_vernum;
284
+ }
285
+
286
+ /*
287
+ * @overload STACI.__get_prop(key)
288
+ *
289
+ * @param [Integer] key 1, 2 or 3
290
+ * @return [Object] depends on +key+.
291
+ * @private
292
+ */
293
+ static VALUE oci8_s_get_prop(VALUE klass, VALUE key)
294
+ {
295
+ switch (NUM2INT(key)) {
296
+ case 1:
297
+ return oci8_float_conversion_type_is_ruby ? Qtrue : Qfalse;
298
+ case 2:
299
+ return UINT2NUM(oci8_env_mode);
300
+ default:
301
+ rb_raise(rb_eArgError, "Unknown prop %d", NUM2INT(key));
302
+ }
303
+ }
304
+
305
+
306
+ /*
307
+ * @overload STACI.__set_prop(key, value)
308
+ *
309
+ * @param [Integer] key 1, 2 or 3
310
+ * @param [Object] value depends on +key+.
311
+ *
312
+ * @private
313
+ */
314
+ static VALUE oci8_s_set_prop(VALUE klass, VALUE key, VALUE val)
315
+ {
316
+ switch (NUM2INT(key)) {
317
+ case 1:
318
+ oci8_float_conversion_type_is_ruby = RTEST(val) ? 1 : 0;
319
+ break;
320
+ case 2:
321
+ /*
322
+ * Changes the OCI environment mode which will be passed to the second
323
+ * argument of the OCI function OCIEnvCreate.
324
+ */
325
+ if (oci8_global_envhp != NULL) {
326
+ rb_raise(rb_eRuntimeError, "The ACI Environment has been alreadly initialized. It cannot be changed after even one ACI function is called.");
327
+ }
328
+ oci8_env_mode = NUM2UINT(val);
329
+ break;
330
+ case 3:
331
+ if (oci8_cancel_read_at_exit == -1) {
332
+ rb_raise(rb_eNotImpError, "STACI.properties[:cancel_read_at_exit] isn't available.");
333
+ }
334
+ #ifdef HAVE_PLTHOOK
335
+ oci8_install_hook_functions();
336
+ oci8_cancel_read_at_exit = RTEST(val) ? 1 : 0;
337
+ #endif
338
+ break;
339
+ case 4:
340
+ if (oci8_tcp_keepalive_time == -1) {
341
+ rb_raise(rb_eNotImpError, "STACI.properties[:tcp_keepalive_time] isn't available.");
342
+ }
343
+ #ifdef HAVE_PLTHOOK
344
+ oci8_install_hook_functions();
345
+ oci8_tcp_keepalive_time = NIL_P(val) ? 0 : NUM2INT(val);
346
+ #endif
347
+ break;
348
+ default:
349
+ rb_raise(rb_eArgError, "Unknown prop %d", NUM2INT(key));
350
+ }
351
+ return klass;
352
+ }
353
+
354
+ /*
355
+ * @overload error_message(message_no)
356
+ *
357
+ * Get the Oracle error message specified by message_no.
358
+ * Its language depends on NLS_LANGUAGE.
359
+ *
360
+ * @example
361
+ * # When NLS_LANG is AMERICAN_AMERICA.AL32UTF8
362
+ * STACI.error_message(1) # => "ORA-00001: unique constraint (%s.%s) violated"
363
+ *
364
+ * # When NLS_LANG is FRENCH_FRANCE.AL32UTF8
365
+ * STACI.error_message(1) # => "ORA-00001: violation de contrainte unique (%s.%s)"
366
+ *
367
+ * @param [Integer] message_no Oracle error message number
368
+ * @return [String] Oracle error message
369
+ */
370
+ static VALUE oci8_s_error_message(VALUE klass, VALUE msgid)
371
+ {
372
+ return oci8_get_error_message(NUM2UINT(msgid), NULL);
373
+ }
374
+
375
+ #define CONN_STR_REGEX "/^([^(\\s|\\@)]*)\\/([^(\\s|\\@)]*)(?:\\@(\\S+))?(?:\\s+as\\s+(\\S*)\\s*)?$/i"
376
+ void oci8_do_parse_connect_string(VALUE conn_str, VALUE *user, VALUE *pass, VALUE *dbname, VALUE *mode)
377
+ {
378
+ static VALUE re = Qnil;
379
+ if (NIL_P(re)) {
380
+ rb_global_variable(&re);
381
+ re = rb_eval_string(CONN_STR_REGEX);
382
+ }
383
+ OCI8SafeStringValue(conn_str);
384
+ if (RTEST(rb_reg_match(re, conn_str))) {
385
+ *user = rb_reg_nth_match(1, rb_backref_get());
386
+ *pass = rb_reg_nth_match(2, rb_backref_get());
387
+ *dbname = rb_reg_nth_match(3, rb_backref_get());
388
+ *mode = rb_reg_nth_match(4, rb_backref_get());
389
+ if (RSTRING_LEN(*user) == 0 && RSTRING_LEN(*pass) == 0) {
390
+ /* external credential */
391
+ *user = Qnil;
392
+ *pass = Qnil;
393
+ }
394
+ if (!NIL_P(*mode)) {
395
+ *mode = ID2SYM(rb_to_id(rb_funcall(*mode, rb_intern("upcase"), 0)));
396
+ }
397
+ } else {
398
+ rb_raise(rb_eArgError, "invalid connect string \"%s\" (expect \"username/password[@(tns_name|//host[:port]/service_name)][ as (sysdba|sysoper)]\"", RSTRING_PTR(conn_str));
399
+ }
400
+ }
401
+
402
+ /*
403
+ * @overload parse_connect_string(connect_string)
404
+ *
405
+ * Extracts +username+, +password+, +dbname+ and +privilege+ from +connect_string+.
406
+ *
407
+ * @example
408
+ * "scott/tiger" -> ["scott", "tiger", nil, nil],
409
+ * "scott/tiger@oradb.example.com" -> ["scott", "tiger", "oradb.example.com", nil]
410
+ * "sys/change_on_install as sysdba" -> ["sys", "change_on_install", nil, :SYSDBA]
411
+ *
412
+ * @param [String] connect_string
413
+ * @return [Array] [username, password, dbname]
414
+ * @private
415
+ */
416
+ static VALUE oci8_parse_connect_string(VALUE self, VALUE conn_str)
417
+ {
418
+ VALUE user;
419
+ VALUE pass;
420
+ VALUE dbname;
421
+ VALUE mode;
422
+
423
+ oci8_do_parse_connect_string(conn_str, &user, &pass, &dbname, &mode);
424
+ return rb_ary_new3(4, user, pass, dbname, mode);
425
+ }
426
+
427
+ /*
428
+ * Logoff strategy for sessions connected by OCIServerAttach and OCISessionBegin.
429
+ */
430
+
431
+ typedef struct {
432
+ ACISvcCtx *svchp;
433
+ ACISession *usrhp;
434
+ ACIServer *srvhp;
435
+ unsigned char state;
436
+ } complex_logoff_arg_t;
437
+
438
+ static void *complex_logoff_prepare(oci8_svcctx_t *svcctx)
439
+ {
440
+ complex_logoff_arg_t *cla = xmalloc(sizeof(complex_logoff_arg_t));
441
+ cla->svchp = svcctx->base.hp.svc;
442
+ cla->usrhp = svcctx->usrhp;
443
+ cla->srvhp = svcctx->srvhp;
444
+ cla->state = svcctx->state;
445
+ svcctx->usrhp = NULL;
446
+ svcctx->srvhp = NULL;
447
+ svcctx->state = 0;
448
+ return cla;
449
+ }
450
+
451
+ static void *complex_logoff_execute(void *arg)
452
+ {
453
+ complex_logoff_arg_t *cla = (complex_logoff_arg_t *)arg;
454
+ ACIError *errhp = oci8_errhp;
455
+ boolean txn = TRUE;
456
+ sword rv = ACI_SUCCESS;
457
+
458
+ if (oracle_client_version >= ORAVER_12_1) {
459
+ ACIAttrGet(cla->usrhp, ACI_HTYPE_SESSION, &txn, NULL, ACI_ATTR_TRANSACTION_IN_PROGRESS, errhp);
460
+ }
461
+ if (txn) {
462
+ ACITransRollback(cla->svchp, errhp, ACI_DEFAULT);
463
+ }
464
+
465
+ if (cla->state & OCI8_STATE_SESSION_BEGIN_WAS_CALLED) {
466
+ rv = ACISessionEnd(cla->svchp, oci8_errhp, cla->usrhp, ACI_DEFAULT);
467
+ cla->state &= ~OCI8_STATE_SESSION_BEGIN_WAS_CALLED;
468
+ }
469
+ if (cla->state & OCI8_STATE_SERVER_ATTACH_WAS_CALLED) {
470
+ rv = ACIServerDetach(cla->srvhp, oci8_errhp, ACI_DEFAULT);
471
+ cla->state &= ~OCI8_STATE_SERVER_ATTACH_WAS_CALLED;
472
+ }
473
+ if (cla->usrhp != NULL) {
474
+ ACIHandleFree(cla->usrhp, ACI_HTYPE_SESSION);
475
+ }
476
+ if (cla->srvhp != NULL) {
477
+ ACIHandleFree(cla->srvhp, ACI_HTYPE_SERVER);
478
+ }
479
+ if (cla->svchp != NULL) {
480
+ ACIHandleFree(cla->svchp, ACI_HTYPE_SVCCTX);
481
+ }
482
+ xfree(cla);
483
+ return (void*)(VALUE)rv;
484
+ }
485
+
486
+ static const oci8_logoff_strategy_t complex_logoff = {
487
+ complex_logoff_prepare,
488
+ complex_logoff_execute,
489
+ };
490
+
491
+ /*
492
+ * @overload allocate_handles()
493
+ *
494
+ * Allocates a service context handle, a session handle and a
495
+ * server handle to use explicit attach and begin-session calls.
496
+ *
497
+ * @private
498
+ */
499
+ static VALUE oci8_allocate_handles(VALUE self)
500
+ {
501
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(self);
502
+ sword rv;
503
+
504
+ if (svcctx->logoff_strategy != NULL) {
505
+ rb_raise(rb_eRuntimeError, "Could not reuse the session.");
506
+ }
507
+ svcctx->logoff_strategy = &complex_logoff;
508
+ svcctx->state = 0;
509
+
510
+ /* allocate a service context handle */
511
+ rv = ACIHandleAlloc(oci8_envhp, &svcctx->base.hp.ptr, ACI_HTYPE_SVCCTX, 0, 0);
512
+ if (rv != ACI_SUCCESS)
513
+ oci8_env_raise(oci8_envhp, rv);
514
+ svcctx->base.type = ACI_HTYPE_SVCCTX;
515
+
516
+ /* alocalte a session handle */
517
+ rv = ACIHandleAlloc(oci8_envhp, (void*)&svcctx->usrhp, ACI_HTYPE_SESSION, 0, 0);
518
+ if (rv != ACI_SUCCESS)
519
+ oci8_env_raise(oci8_envhp, rv);
520
+ copy_session_handle(svcctx);
521
+
522
+ /* alocalte a server handle */
523
+ rv = ACIHandleAlloc(oci8_envhp, (void*)&svcctx->srvhp, ACI_HTYPE_SERVER, 0, 0);
524
+ if (rv != ACI_SUCCESS)
525
+ oci8_env_raise(oci8_envhp, rv);
526
+ copy_server_handle(svcctx);
527
+ return self;
528
+ }
529
+
530
+ /*
531
+ * @overload server_attach(dbname, mode)
532
+ *
533
+ * Attachs to the server by the OCI function OCIServerAttach().
534
+ *
535
+ * @param [String] dbname
536
+ * @param [Integer] mode
537
+ * @private
538
+ */
539
+ static VALUE oci8_server_attach(VALUE self, VALUE dbname, VALUE attach_mode)
540
+ {
541
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(self);
542
+ ub4 mode = NUM2UINT(attach_mode);
543
+
544
+ if (svcctx->logoff_strategy != &complex_logoff) {
545
+ rb_raise(rb_eRuntimeError, "Use this method only for the service context handle created by STACI#server_handle().");
546
+ }
547
+ if (svcctx->state & OCI8_STATE_SERVER_ATTACH_WAS_CALLED) {
548
+ rb_raise(rb_eRuntimeError, "Could not use this method twice.");
549
+ }
550
+
551
+ /* check arguments */
552
+ if (!NIL_P(dbname)) {
553
+ OCI8SafeStringValue(dbname);
554
+ }
555
+
556
+ /* attach to the server */
557
+ chker2(ACIServerAttach_nb(svcctx, svcctx->srvhp, oci8_errhp,
558
+ NIL_P(dbname) ? NULL : RSTRING_ORATEXT(dbname),
559
+ NIL_P(dbname) ? 0 : RSTRING_LEN(dbname),
560
+ mode),
561
+ &svcctx->base);
562
+ chker2(ACIAttrSet(svcctx->base.hp.ptr, ACI_HTYPE_SVCCTX,
563
+ svcctx->srvhp, 0, ACI_ATTR_SERVER,
564
+ oci8_errhp),
565
+ &svcctx->base);
566
+ svcctx->state |= OCI8_STATE_SERVER_ATTACH_WAS_CALLED;
567
+ if (mode & ACI_CPOOL) {
568
+ svcctx->state |= OCI8_STATE_CPOOL;
569
+ }
570
+ return self;
571
+ }
572
+
573
+ /*
574
+ * @overload session_begin(cred, mode)
575
+ *
576
+ * Begins the session by the OCI function OCISessionBegin().
577
+ *
578
+ * @param [Integer] cred
579
+ * @param [Integer] mode
580
+ * @private
581
+ */
582
+ static VALUE oci8_session_begin(VALUE self, VALUE cred, VALUE mode)
583
+ {
584
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(self);
585
+ char buf[100];
586
+ ub4 version;
587
+
588
+ if (svcctx->logoff_strategy != &complex_logoff) {
589
+ rb_raise(rb_eRuntimeError, "Use this method only for the service context handle created by STACI#server_handle().");
590
+ }
591
+ if (svcctx->state & OCI8_STATE_SESSION_BEGIN_WAS_CALLED) {
592
+ rb_raise(rb_eRuntimeError, "Could not use this method twice.");
593
+ }
594
+
595
+ /* check arguments */
596
+ Check_Type(cred, T_FIXNUM);
597
+ Check_Type(mode, T_FIXNUM);
598
+
599
+ /* begin session */
600
+ chker2(ACISessionBegin_nb(svcctx, svcctx->base.hp.ptr, oci8_errhp,
601
+ svcctx->usrhp, FIX2UINT(cred),
602
+ FIX2UINT(mode)),
603
+ &svcctx->base);
604
+ chker2(ACIAttrSet(svcctx->base.hp.ptr, ACI_HTYPE_SVCCTX,
605
+ svcctx->usrhp, 0, ACI_ATTR_SESSION,
606
+ oci8_errhp),
607
+ &svcctx->base);
608
+ svcctx->state |= OCI8_STATE_SESSION_BEGIN_WAS_CALLED;
609
+ /* if (have_OCIServerRelease2) {
610
+ chker2(OCIServerRelease2(svcctx->base.hp.ptr, oci8_errhp, (text*)buf,
611
+ sizeof(buf), (ub1)svcctx->base.type, &version, ACI_DEFAULT),
612
+ &svcctx->base);
613
+ } else {
614
+ chker2(OCIServerRelease(svcctx->base.hp.ptr, oci8_errhp, (text*)buf,
615
+ sizeof(buf), (ub1)svcctx->base.type, &version),
616
+ &svcctx->base);
617
+ }*/
618
+ svcctx->server_version = version;
619
+ return Qnil;
620
+ }
621
+
622
+ /*
623
+ * @overload logoff
624
+ *
625
+ * Disconnects from the Oracle server. The uncommitted transaction is
626
+ * rollbacked.
627
+ */
628
+ static VALUE oci8_svcctx_logoff(VALUE self)
629
+ {
630
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(self);
631
+
632
+ while (svcctx->base.children != NULL) {
633
+ oci8_base_free(svcctx->base.children);
634
+ }
635
+ if (svcctx->logoff_strategy != NULL) {
636
+ const oci8_logoff_strategy_t *strategy = svcctx->logoff_strategy;
637
+ void *data = strategy->prepare(svcctx);
638
+ svcctx->base.type = 0;
639
+ svcctx->base.closed = 1;
640
+ svcctx->logoff_strategy = NULL;
641
+ chker2(oci8_call_without_gvl(svcctx, strategy->execute, data), &svcctx->base);
642
+ }
643
+ return Qtrue;
644
+ }
645
+
646
+ /*
647
+ * @overload commit
648
+ *
649
+ * Commits the transaction.
650
+ */
651
+ static VALUE oci8_commit(VALUE self)
652
+ {
653
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(self);
654
+ chker2(ACITransCommit_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, ACI_DEFAULT), &svcctx->base);
655
+ return self;
656
+ }
657
+
658
+ /*
659
+ * @overload rollback
660
+ *
661
+ * Rollbacks the transaction.
662
+ */
663
+ static VALUE oci8_rollback(VALUE self)
664
+ {
665
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(self);
666
+ chker2(ACITransRollback_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, ACI_DEFAULT), &svcctx->base);
667
+ return self;
668
+ }
669
+
670
+ /*
671
+ * @overload non_blocking?
672
+ *
673
+ * Returns +true+ if the connection is in non-blocking mode, +false+
674
+ * otherwise.
675
+ *
676
+ * @see #non_blocking=
677
+ */
678
+ static VALUE oci8_non_blocking_p(VALUE self)
679
+ {
680
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(self);
681
+ return svcctx->non_blocking ? Qtrue : Qfalse;
682
+ }
683
+
684
+ /*
685
+ * @overload non_blocking=(non_blocking_mode)
686
+ *
687
+ * Sets +true+ to enable non-blocking mode, +false+ otherwise.
688
+ * The default value is +true+ except ruby 1.8.
689
+ *
690
+ * When the connection is in non-blocking mode (non_blocking = true),
691
+ * an SQL execution blocks the thread running the SQL.
692
+ * It does't prevent other threads. The blocking thread can be canceled
693
+ * by {STACI#break}.
694
+ *
695
+ * When in blocking mode (non_blocking = false), an SQL execution blocks
696
+ * not only the thread, but also the ruby process itself. It makes the
697
+ * whole application stop until the SQL finishes.
698
+ *
699
+ * @param [Boolean] non_blocking_mode
700
+ */
701
+ static VALUE oci8_set_non_blocking(VALUE self, VALUE val)
702
+ {
703
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(self);
704
+ svcctx->non_blocking = RTEST(val);
705
+ return val;
706
+ }
707
+
708
+ /*
709
+ * @overload autocommit?
710
+ *
711
+ * Returns +true+ if the connection is in autocommit mode, +false+
712
+ * otherwise. The default value is +false+.
713
+ */
714
+ static VALUE oci8_autocommit_p(VALUE self)
715
+ {
716
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(self);
717
+ return svcctx->is_autocommit ? Qtrue : Qfalse;
718
+ }
719
+
720
+ /*
721
+ * @overload autocommit=(autocommit_mode)
722
+ *
723
+ * Sets the autocommit mode. The default value is +false+.
724
+ *
725
+ * @param [Boolean] autocommit_mode
726
+ */
727
+ static VALUE oci8_set_autocommit(VALUE self, VALUE val)
728
+ {
729
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(self);
730
+ svcctx->is_autocommit = RTEST(val);
731
+ return val;
732
+ }
733
+
734
+ /*
735
+ * @overload long_read_len
736
+ *
737
+ * @deprecated This has no effect since ruby-oci8 2.2.7.
738
+ * LONG, LONG RAW and XMLTYPE columns are fetched up to 4 gigabytes
739
+ * without this parameter.
740
+ *
741
+ * @return [Integer]
742
+ * @see #long_read_len=
743
+ */
744
+ static VALUE oci8_long_read_len(VALUE self)
745
+ {
746
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(self);
747
+ rb_warning("STACI.long_read_len has no effect since ruby-oci8 2.2.7");
748
+ return svcctx->long_read_len;
749
+ }
750
+
751
+ /*
752
+ * @overload long_read_len=(length)
753
+ *
754
+ * @deprecated This has no effect since ruby-oci8 2.2.7.
755
+ * LONG, LONG RAW and XMLTYPE columns are fetched up to 4 gigabytes
756
+ * without this parameter.
757
+ *
758
+ * @param [Integer] length
759
+ * @see #long_read_len
760
+ */
761
+ static VALUE oci8_set_long_read_len(VALUE self, VALUE val)
762
+ {
763
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(self);
764
+ Check_Type(val, T_FIXNUM);
765
+ RB_OBJ_WRITE(self, &svcctx->long_read_len, val);
766
+ rb_warning("STACI.long_read_len= has no effect since ruby-oci8 2.2.7");
767
+ return val;
768
+ }
769
+
770
+ /*
771
+ * @overload break
772
+ *
773
+ * Cancels the executing SQL.
774
+ *
775
+ * Note that this doesn't work when the following cases.
776
+ *
777
+ * * The Oracle server runs on Windows.
778
+ * * {Out-of-band data}[http://en.wikipedia.org/wiki/Transmission_Control_Protocol#Out-of-band_data] are blocked by a firewall or by a VPN.
779
+ *
780
+ * In the latter case, create an sqlnet.ora file in the path specified
781
+ * by the TNS_ADMIN environment variable that sets {DISABLE_OOB=on}[http://www.orafaq.com/wiki/SQL*Net_FAQ#What_are_inband_and_out_of_band_breaks.3F].
782
+ *
783
+ * @see STACI#non_blocking=
784
+ */
785
+ static VALUE oci8_break(VALUE self)
786
+ {
787
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(self);
788
+
789
+ if (NIL_P(svcctx->executing_thread)) {
790
+ return Qfalse;
791
+ }
792
+ rb_thread_wakeup(svcctx->executing_thread);
793
+ return Qtrue;
794
+ }
795
+
796
+ /*
797
+ * @overload oracle_server_vernum
798
+ *
799
+ * Returns a numerical format of the Oracle server version.
800
+ *
801
+ * @return [Integer]
802
+ * @see STACI#oracle_server_version
803
+ * @since 2.0.1
804
+ * @private
805
+ */
806
+ static VALUE oci8_oracle_server_vernum(VALUE self)
807
+ {
808
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(self);
809
+
810
+ return UINT2NUM(svcctx->server_version);
811
+ }
812
+
813
+ /*
814
+ * @overload ping
815
+ *
816
+ * Makes a round trip call to the server to confirm that the connection and
817
+ * the server are active.
818
+ *
819
+ * This also flushes all the pending OCI client-side calls such as {STACI#action=},
820
+ * {STACI#client_identifier=}, {STACI#client_info=} and {STACI#module=}.
821
+ *
822
+ * === Oracle 10.2 client or upper
823
+ * A dummy round trip call is made by the OCI function
824
+ * OCIPing[http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14250/oci16msc007.htm#sthref3540] added in Oracle 10.2.
825
+ *
826
+ * === Oracle 10.1 client or lower
827
+ * A simple PL/SQL block "BEGIN NULL; END;" is executed to make a round trip call.
828
+ *
829
+ * @return [Boolean]
830
+ * @since 2.0.2
831
+ */
832
+ static VALUE oci8_ping(VALUE self)
833
+ {
834
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(self);
835
+ sword rv;
836
+
837
+ if (have_ACIPing_nb) {
838
+ /* Oracle 10.2 or upper */
839
+ rv = ACIPing_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, ACI_DEFAULT);
840
+ } else {
841
+ /* Oracle 10.1 or lower */
842
+ rv = oci8_exec_sql(svcctx, "BEGIN NULL; END;", 0U, NULL, 0U, NULL, 0);
843
+ }
844
+ return rv == ACI_SUCCESS ? Qtrue : FALSE;
845
+ }
846
+
847
+ /*
848
+ * @overload client_identifier=(client_identifier)
849
+ *
850
+ * Sets the specified value to {V$SESSION.CLIENT_IDENTIFIER}[http://docs.oracle.com/database/121/REFRN/refrn30223.htm#r62c1-t21].
851
+ *
852
+ * The specified value is sent to the server by piggybacking on the next network
853
+ * round trip issued by {STACI#exec}, {STACI#ping} and so on.
854
+ *
855
+ * @param [String] client_identifier
856
+ * @since 2.0.3
857
+ */
858
+ static VALUE oci8_set_client_identifier(VALUE self, VALUE val)
859
+ {
860
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(self);
861
+ const char *ptr;
862
+ ub4 size;
863
+
864
+ if (!NIL_P(val)) {
865
+ OCI8SafeStringValue(val);
866
+ ptr = RSTRING_PTR(val);
867
+ size = RSTRING_LEN(val);
868
+ } else {
869
+ ptr = "";
870
+ size = 0;
871
+ }
872
+
873
+ if (size > 0 && ptr[0] == ':') {
874
+ rb_raise(rb_eArgError, "client identifier should not start with ':'.");
875
+ }
876
+ chker2(ACIAttrSet(svcctx->usrhp, ACI_HTYPE_SESSION, (dvoid*)ptr,
877
+ size, ACI_ATTR_CLIENT_IDENTIFIER, oci8_errhp),
878
+ &svcctx->base);
879
+ return val;
880
+ }
881
+
882
+ /*
883
+ * @overload module=(module)
884
+ *
885
+ * Sets the specified value to {V$SESSION.MODULE}[http://docs.oracle.com/database/121/REFRN/refrn30223.htm#r40c1-t21].
886
+ * This is also stored in {V$SQL.MODULE}[http://docs.oracle.com/database/121/REFRN/refrn30246.htm#r49c1-t58]
887
+ * and {V$SQLAREA.MODULE}[http://docs.oracle.com/database/121/REFRN/refrn30259.htm#r46c1-t94]
888
+ * when an SQL statement is first parsed in the Oracle server.
889
+ *
890
+ * @param [String] module
891
+ * @since 2.0.3
892
+ */
893
+ static VALUE oci8_set_module(VALUE self, VALUE val)
894
+ {
895
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(self);
896
+ const char *ptr;
897
+ ub4 size;
898
+
899
+ if (!NIL_P(val)) {
900
+ OCI8SafeStringValue(val);
901
+ ptr = RSTRING_PTR(val);
902
+ size = RSTRING_LEN(val);
903
+ } else {
904
+ ptr = "";
905
+ size = 0;
906
+ }
907
+ chker2(ACIAttrSet(svcctx->usrhp, ACI_HTYPE_SESSION, (dvoid*)ptr,
908
+ size, ACI_ATTR_MODULE, oci8_errhp),
909
+ &svcctx->base);
910
+ return self;
911
+ }
912
+
913
+ /*
914
+ * @overload action=(action)
915
+ *
916
+ * Sets the specified value to {V$SESSION.ACTION}[http://docs.oracle.com/database/121/REFRN/refrn30223.htm#r42c1-t21].
917
+ * This is also stored in {V$SQL.ACTION}[http://docs.oracle.com/database/121/REFRN/refrn30246.htm#r51c1-t58]
918
+ * and {V$SQLAREA.ACTION}[http://docs.oracle.com/database/121/REFRN/refrn30259.htm#r48c1-t94]
919
+ * when an SQL statement is first parsed in the Oracle server.
920
+ *
921
+ * The specified value is sent to the server by piggybacking on the next network
922
+ * round trip issued by {STACI#exec}, {STACI#ping} and so on.
923
+ *
924
+ * @param [String] action
925
+ * @since 2.0.3
926
+ */
927
+ static VALUE oci8_set_action(VALUE self, VALUE val)
928
+ {
929
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(self);
930
+ const char *ptr;
931
+ ub4 size;
932
+
933
+ if (!NIL_P(val)) {
934
+ OCI8SafeStringValue(val);
935
+ ptr = RSTRING_PTR(val);
936
+ size = RSTRING_LEN(val);
937
+ } else {
938
+ ptr = "";
939
+ size = 0;
940
+ }
941
+ chker2(ACIAttrSet(svcctx->usrhp, ACI_HTYPE_SESSION, (dvoid*)ptr,
942
+ size, ACI_ATTR_ACTION, oci8_errhp),
943
+ &svcctx->base);
944
+ return val;
945
+ }
946
+
947
+ /*
948
+ * @overload client_info=(client_info)
949
+ *
950
+ * Sets the specified value to {V$SESSION.CLIENT_INFO}[http://docs.oracle.com/database/121/REFRN/refrn30223.htm#r44c1-t21].
951
+ *
952
+ * The specified value is sent to the server by piggybacking on the next network
953
+ * round trip issued by {STACI#exec}, {STACI#ping} and so on.
954
+ *
955
+ * @param [String] client_info
956
+ * @since 2.0.3
957
+ */
958
+ static VALUE oci8_set_client_info(VALUE self, VALUE val)
959
+ {
960
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(self);
961
+ const char *ptr;
962
+ ub4 size;
963
+
964
+ if (!NIL_P(val)) {
965
+ OCI8SafeStringValue(val);
966
+ ptr = RSTRING_PTR(val);
967
+ size = RSTRING_LEN(val);
968
+ } else {
969
+ ptr = "";
970
+ size = 0;
971
+ }
972
+ chker2(ACIAttrSet(svcctx->usrhp, ACI_HTYPE_SESSION, (dvoid*)ptr,
973
+ size, ACI_ATTR_CLIENT_INFO, oci8_errhp),
974
+ &svcctx->base);
975
+ return val;
976
+ }
977
+
978
+ void Init_oci8(VALUE *out)
979
+ {
980
+ VALUE obj;
981
+ oci8_base_t *base;
982
+ #if /* for yard */ 0
983
+ oci8_cOCIHandle = rb_define_class("ACIHandle", rb_cObject);
984
+ cOCI8 = rb_define_class("STACI", oci8_cOCIHandle);
985
+ #endif
986
+ cOCI8 = oci8_define_class("STACI", &oci8_svcctx_data_type, oci8_svcctx_alloc);
987
+ cSession = oci8_define_class_under(cOCI8, "Session", &oci8_session_data_type, oci8_session_alloc);
988
+ cServer = oci8_define_class_under(cOCI8, "Server", &oci8_server_data_type, oci8_server_alloc);
989
+ cEnvironment = oci8_define_class_under(cOCI8, "Environment", &oci8_environment_data_type, oci8_environment_alloc);
990
+ cProcess = oci8_define_class_under(cOCI8, "Process", &oci8_process_data_type, oci8_process_alloc);
991
+ id_at_session_handle = rb_intern("@session_handle");
992
+ id_at_server_handle = rb_intern("@server_handle");
993
+
994
+ /* setup a dummy environment handle to lazily initialize the environment handle */
995
+ obj = rb_obj_alloc(rb_cObject);
996
+ rb_define_singleton_method(obj, "method_missing", dummy_env_method_missing, -1);
997
+ rb_cv_set(cOCI8, "@@environment_handle", obj);
998
+
999
+ /* setup the process handle */
1000
+ obj = rb_obj_alloc(cProcess);
1001
+ base = DATA_PTR(obj);
1002
+ base->type = ACI_HTYPE_PROC;
1003
+ base->self = Qnil;
1004
+ rb_cv_set(cOCI8, "@@process_handle", obj);
1005
+
1006
+ oracle_client_vernum = INT2FIX(oracle_client_version);
1007
+ if (have_ACIClientVersion) {
1008
+ sword major, minor, update, patch, port_update;
1009
+ ACIClientVersion(&major, &minor, &update, &patch, &port_update);
1010
+ oracle_client_vernum = INT2FIX(ORAVERNUM(major, minor, update, patch, port_update));
1011
+ }
1012
+
1013
+ rb_define_const(cOCI8, "LIB_VERSION", rb_obj_freeze(rb_usascii_str_new_cstr(OCI8LIB_VERSION)));
1014
+ rb_define_singleton_method_nodoc(cOCI8, "oracle_client_vernum", oci8_s_oracle_client_vernum, 0);
1015
+ rb_define_singleton_method_nodoc(cOCI8, "__get_prop", oci8_s_get_prop, 1);
1016
+ rb_define_singleton_method_nodoc(cOCI8, "__set_prop", oci8_s_set_prop, 2);
1017
+ rb_define_singleton_method(cOCI8, "error_message", oci8_s_error_message, 1);
1018
+ rb_define_private_method(cOCI8, "parse_connect_string", oci8_parse_connect_string, 1);
1019
+ rb_define_private_method(cOCI8, "allocate_handles", oci8_allocate_handles, 0);
1020
+ rb_define_private_method(cOCI8, "server_attach", oci8_server_attach, 2);
1021
+ rb_define_private_method(cOCI8, "session_begin", oci8_session_begin, 2);
1022
+ rb_define_method(cOCI8, "logoff", oci8_svcctx_logoff, 0);
1023
+ rb_define_method(cOCI8, "commit", oci8_commit, 0);
1024
+ rb_define_method(cOCI8, "rollback", oci8_rollback, 0);
1025
+ rb_define_method(cOCI8, "non_blocking?", oci8_non_blocking_p, 0);
1026
+ rb_define_method(cOCI8, "non_blocking=", oci8_set_non_blocking, 1);
1027
+ rb_define_method(cOCI8, "autocommit?", oci8_autocommit_p, 0);
1028
+ rb_define_method(cOCI8, "autocommit=", oci8_set_autocommit, 1);
1029
+ rb_define_method(cOCI8, "long_read_len", oci8_long_read_len, 0);
1030
+ rb_define_method(cOCI8, "long_read_len=", oci8_set_long_read_len, 1);
1031
+ rb_define_method(cOCI8, "break", oci8_break, 0);
1032
+ rb_define_private_method(cOCI8, "oracle_server_vernum", oci8_oracle_server_vernum, 0);
1033
+ rb_define_method(cOCI8, "ping", oci8_ping, 0);
1034
+ rb_define_method(cOCI8, "client_identifier=", oci8_set_client_identifier, 1);
1035
+ rb_define_method(cOCI8, "module=", oci8_set_module, 1);
1036
+ rb_define_method(cOCI8, "action=", oci8_set_action, 1);
1037
+ rb_define_method(cOCI8, "client_info=", oci8_set_client_info, 1);
1038
+ *out = cOCI8;
1039
+ }
1040
+
1041
+ oci8_svcctx_t *oci8_get_svcctx(VALUE obj)
1042
+ {
1043
+ return (oci8_svcctx_t *)oci8_check_typeddata(obj, &oci8_svcctx_data_type, 1);
1044
+ }
1045
+
1046
+ ACISession *oci8_get_oci_session(VALUE obj)
1047
+ {
1048
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(obj);
1049
+ return svcctx->usrhp;
1050
+ }
1051
+
1052
+ void oci8_check_pid_consistency(oci8_svcctx_t *svcctx)
1053
+ {
1054
+ if (svcctx->pid != getpid()) {
1055
+ rb_raise(rb_eRuntimeError, "The connection cannot be reused in the forked process.");
1056
+ }
1057
+ }
1058
+