ruby-oci8-master 2.0.7

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 (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
+