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
@@ -0,0 +1,704 @@
1
+ /* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * Copyright (C) 2002-2015 Kubo Takehiro <kubo@jiubao.org>
4
+ */
5
+
6
+ #include "oci8.h"
7
+ #ifdef HAVE_RUBY_THREAD_H
8
+ #include <ruby/thread.h>
9
+ #endif
10
+ #if defined(HAVE_PLTHOOK) && !defined(WIN32)
11
+ #include <dlfcn.h>
12
+ #include "plthook.h"
13
+ #endif
14
+
15
+ ID oci8_id_at_last_error;
16
+ ID oci8_id_get;
17
+ ID oci8_id_set;
18
+ #ifdef CHAR_IS_NOT_A_SHORTCUT_TO_ID
19
+ ID oci8_id_add_op;
20
+ ID oci8_id_sub_op;
21
+ ID oci8_id_mul_op;
22
+ ID oci8_id_div_op;
23
+ #endif
24
+ int oci8_in_finalizer = 0;
25
+ VALUE oci8_cOCIHandle;
26
+
27
+ #if defined __sun && defined __i386 && defined __GNUC__
28
+ /* When a main function is invisible from Oracle instant
29
+ * client 11.2.0.3 for Solaris x86 (32-bit), OCIEnvCreate()
30
+ * fails by unknown reasons. We export it from ruby-oci8 instead
31
+ * of ruby itself.
32
+ */
33
+ int main() { return 0; }
34
+ #endif
35
+
36
+ static VALUE mOCI8BindType;
37
+ static VALUE cOCI8BindTypeBase;
38
+
39
+ void oci8_base_free(oci8_base_t *base)
40
+ {
41
+ while (base->children != NULL) {
42
+ oci8_base_free(base->children);
43
+ }
44
+ oci8_unlink_from_parent(base);
45
+ if (base->data_type->free != NULL)
46
+ base->data_type->free(base);
47
+ if (base->type >= ACI_DTYPE_FIRST) {
48
+ ACIDescriptorFree(base->hp.ptr, base->type);
49
+ } else if (base->type == ACI_HTYPE_BIND || base->type == ACI_HTYPE_DEFINE) {
50
+ ; /* Do nothing. Bind handles and define handles are freed when
51
+ * associating statement handles are freed.
52
+ */
53
+ } else if (base->type >= ACI_HTYPE_FIRST) {
54
+ ACIHandleFree(base->hp.ptr, base->type);
55
+ }
56
+ base->type = 0;
57
+ base->closed = 1;
58
+ base->hp.ptr = NULL;
59
+ }
60
+
61
+ static void at_exit_func(VALUE val)
62
+ {
63
+ oci8_in_finalizer = 1;
64
+ #ifdef HAVE_PLTHOOK
65
+ oci8_shutdown_sockets();
66
+ #endif
67
+ }
68
+
69
+ static VALUE bind_base_alloc(VALUE klass)
70
+ {
71
+ rb_raise(rb_eNameError, "private method `new' called for %s:Class", rb_class2name(klass));
72
+ }
73
+
74
+ #if defined(HAVE_PLTHOOK) && !defined(WIN32) && !defined(__CYGWIN__)
75
+ static const char *find_libclntsh(void *handle)
76
+ {
77
+ void *symaddr = dlsym(handle, "ACIEnvCreate");
78
+ Dl_info info;
79
+ #ifdef __APPLE__
80
+ const char *basename = "libclntsh.dylib";
81
+ #else
82
+ const char *basename = "libclntsh.so";
83
+ #endif
84
+ const char *p;
85
+
86
+ if (symaddr == NULL) {
87
+ return NULL;
88
+ }
89
+ if (dladdr(symaddr, &info) == 0) {
90
+ return NULL;
91
+ }
92
+ if ((p = strrchr(info.dli_fname, '/')) == NULL) {
93
+ return NULL;
94
+ }
95
+ if (strncmp(p + 1, basename, strlen(basename)) != 0) {
96
+ return NULL;
97
+ }
98
+ return info.dli_fname;
99
+ }
100
+
101
+ /*
102
+ * Symbol prefix depends on the platform.
103
+ * Linux x86_64 - no prefix
104
+ * Linux x86_32 - "_"
105
+ * macOS - "@_"
106
+ */
107
+ static const char *find_symbol_prefix(plthook_t *ph, size_t *len)
108
+ {
109
+ unsigned int pos = 0;
110
+ const char *name;
111
+ void **addr;
112
+
113
+ while (plthook_enum(ph, &pos, &name, &addr) == 0) {
114
+ const char *p = strstr(name, "ACIEnvCreate");
115
+ if (p != NULL) {
116
+ *len = p - name;
117
+ return name;
118
+ }
119
+ }
120
+ return NULL;
121
+ }
122
+
123
+ /*
124
+ * Fix PLT entries against function interposition.
125
+ * See: http://www.rubydoc.info/github/kubo/ruby-oci8/file/docs/ldap-auth-and-function-interposition.md
126
+ */
127
+ static void rebind_internal_symbols(void)
128
+ {
129
+ const char *libfile;
130
+ void *handle;
131
+ int flags = RTLD_LAZY | RTLD_NOLOAD;
132
+ plthook_t *ph;
133
+ unsigned int pos = 0;
134
+ const char *name;
135
+ void **addr;
136
+ const char *prefix;
137
+ size_t prefix_len;
138
+
139
+ #ifdef RTLD_FIRST
140
+ flags |= RTLD_FIRST; /* for macOS */
141
+ #endif
142
+
143
+ libfile = find_libclntsh(RTLD_DEFAULT); /* normal case */
144
+ if (libfile == NULL) {
145
+ libfile = find_libclntsh(RTLD_NEXT); /* special case when OCIEnvCreate is hooked by LD_PRELOAD */
146
+ }
147
+ if (libfile == NULL) {
148
+ return;
149
+ }
150
+ handle = dlopen(libfile, flags);
151
+ if (handle == NULL) {
152
+ return;
153
+ }
154
+ if (plthook_open(&ph, libfile) != 0) {
155
+ dlclose(handle);
156
+ return;
157
+ }
158
+ prefix = find_symbol_prefix(ph, &prefix_len);
159
+ if (prefix == NULL) {
160
+ dlclose(handle);
161
+ plthook_close(ph);
162
+ return;
163
+ }
164
+ while (plthook_enum(ph, &pos, &name, &addr) == 0) {
165
+ void *funcaddr;
166
+ if (prefix_len != 0) {
167
+ if (strncmp(name, prefix, prefix_len) != 0) {
168
+ continue;
169
+ }
170
+ name += prefix_len;
171
+ }
172
+ if (strncmp(name, "ACI", 3) == 0) {
173
+ /* exclude functions starting with ACI not to prevent LD_PRELOAD hooking */
174
+ continue;
175
+ }
176
+ funcaddr = dlsym(handle, name);
177
+ if (funcaddr != NULL && *addr != funcaddr) {
178
+ /* If libclntsh.so exports and imports same functions, their
179
+ * PLT entries are forcedly modified to point to itself not
180
+ * to use functions in other libraries.
181
+ */
182
+ *addr = funcaddr;
183
+ }
184
+ }
185
+ plthook_close(ph);
186
+ dlclose(handle);
187
+ }
188
+ #endif
189
+
190
+ #ifdef _WIN32
191
+ __declspec(dllexport)
192
+ #endif
193
+ void
194
+ Init_oci8lib()
195
+ {
196
+ VALUE cOCI8;
197
+ ACIEnv *envhp = NULL;
198
+ ACIError *errhp;
199
+ sword rv;
200
+
201
+ #ifdef RUNTIME_API_CHECK
202
+ Init_oci8_apiwrap();
203
+ if (oracle_client_version < ORAVER_10_1) {
204
+ const char *oraver;
205
+ const char *ruby_oci8_ver;
206
+ if (oracle_client_version >= ORAVER_9_2) {
207
+ oraver = "9iR2";
208
+ ruby_oci8_ver = "2.1.x";
209
+ } else if (oracle_client_version >= ORAVER_9_0) {
210
+ oraver = "9iR1";
211
+ ruby_oci8_ver = "2.1.x";
212
+ } else if (oracle_client_version >= ORAVER_8_1) {
213
+ oraver = "8i";
214
+ ruby_oci8_ver = "2.0.x";
215
+ } else {
216
+ oraver = "8";
217
+ ruby_oci8_ver = "2.0.x";
218
+ }
219
+ rb_raise(rb_eLoadError, "Ruby-oci8 %s doesn't support Oracle %s. Use ruby-oci8 %s instead.",
220
+ OCI8LIB_VERSION, oraver, ruby_oci8_ver);
221
+ }
222
+
223
+ if (have_OCIClientVersion) {
224
+ sword major, minor, update, patch, port_update;
225
+ ACIClientVersion(&major, &minor, &update, &patch, &port_update);
226
+ oracle_client_version = ORAVERNUM(major, minor, update, patch, port_update);
227
+ }
228
+ #endif
229
+ #if defined(HAVE_PLTHOOK) && !defined(WIN32) && !defined(__CYGWIN__)
230
+ rebind_internal_symbols();
231
+ #endif
232
+
233
+ oci8_id_at_last_error = rb_intern("@last_error");
234
+ oci8_id_get = rb_intern("get");
235
+ oci8_id_set = rb_intern("set");
236
+ #ifdef CHAR_IS_NOT_A_SHORTCUT_TO_ID
237
+ oci8_id_add_op = rb_intern("+");
238
+ oci8_id_sub_op = rb_intern("-");
239
+ oci8_id_mul_op = rb_intern("*");
240
+ oci8_id_div_op = rb_intern("/");
241
+ #endif
242
+ rb_set_end_proc(at_exit_func, Qnil);
243
+
244
+ Init_oci8_thread_util();
245
+ Init_oci8_error();
246
+ Init_oci8_env();
247
+
248
+ /* OCIHandle class */
249
+ Init_oci8_handle();
250
+
251
+ /* STACI class */
252
+ Init_oci8(&cOCI8);
253
+
254
+ /* STACI::ConnectionPool class */
255
+ Init_oci8_connection_pool(cOCI8);
256
+
257
+ /* STACI::BindType module */
258
+ mOCI8BindType = rb_define_module_under(cOCI8, "BindType");
259
+ /* STACI::BindType::Base class */
260
+ cOCI8BindTypeBase = oci8_define_class_under(mOCI8BindType, "Base", &oci8_bind_data_type, bind_base_alloc);
261
+
262
+ /* Handle */
263
+ Init_oci8_bind(cOCI8BindTypeBase);
264
+ Init_oci8_stmt(cOCI8);
265
+
266
+ /* Encoding */
267
+ Init_oci8_encoding(cOCI8);
268
+
269
+ /* register allocators */
270
+ Init_oci8_metadata(cOCI8);
271
+ Init_oci8_lob(cOCI8);
272
+
273
+ /* STACI::Util */
274
+ Init_oci8_util(cOCI8);
275
+
276
+ /* allocate a temporary errhp to pass Init_oci_number() */
277
+ rv = ACIEnvCreate(&envhp, oci8_env_mode, NULL, NULL, NULL, NULL, 0, NULL);
278
+ if (rv != ACI_SUCCESS) {
279
+ if (envhp != NULL) {
280
+ oci8_env_free_and_raise(envhp, rv);
281
+ } else {
282
+ oci8_raise_init_error();
283
+ }
284
+ }
285
+ rv = ACIHandleAlloc(envhp, (dvoid *)&errhp, ACI_HTYPE_ERROR, 0, NULL);
286
+ if (rv != ACI_SUCCESS)
287
+ oci8_env_raise(envhp, rv);
288
+ Init_oci_number(cOCI8, errhp);
289
+ ACIHandleFree(errhp, ACI_HTYPE_ERROR);
290
+ ACIHandleFree(envhp, ACI_HTYPE_ENV);
291
+
292
+ Init_ora_date();
293
+ Init_oci_datetime();
294
+ Init_oci_object(cOCI8);
295
+
296
+ #ifdef USE_WIN32_C
297
+ Init_oci8_win32(cOCI8);
298
+ #endif
299
+ }
300
+
301
+ VALUE oci8_define_class(const char *name, const oci8_handle_data_type_t *data_type, VALUE (*alloc_func)(VALUE))
302
+ {
303
+ VALUE parent_class = rb_eval_string(data_type->rb_data_type.parent->wrap_struct_name);
304
+ VALUE klass = rb_define_class(name, parent_class);
305
+
306
+ rb_define_alloc_func(klass, alloc_func);
307
+ return klass;
308
+ }
309
+
310
+ VALUE oci8_define_class_under(VALUE outer, const char *name, const oci8_handle_data_type_t *data_type, VALUE (*alloc_func)(VALUE))
311
+ {
312
+ VALUE parent_class = rb_eval_string(data_type->rb_data_type.parent->wrap_struct_name);
313
+ VALUE klass = rb_define_class_under(outer, name, parent_class);
314
+
315
+ rb_define_alloc_func(klass, alloc_func);
316
+ return klass;
317
+ }
318
+
319
+ VALUE oci8_define_bind_class(const char *name, const oci8_bind_data_type_t *data_type, VALUE (*alloc_func)(VALUE))
320
+ {
321
+ VALUE parent_class = rb_eval_string(data_type->base.rb_data_type.parent->wrap_struct_name);
322
+ VALUE klass = rb_define_class_under(mOCI8BindType, name, parent_class);
323
+
324
+ rb_define_alloc_func(klass, alloc_func);
325
+ return klass;
326
+ }
327
+
328
+ void oci8_link_to_parent(oci8_base_t *base, oci8_base_t *parent)
329
+ {
330
+ VALUE old_parent = Qundef;
331
+
332
+ if (base->parent != NULL) {
333
+ old_parent = base->parent->self;
334
+ oci8_unlink_from_parent(base);
335
+ }
336
+ if (parent->children == NULL) {
337
+ parent->children = base;
338
+ } else {
339
+ base->next = parent->children;
340
+ base->prev = parent->children->prev;
341
+ parent->children->prev->next = base;
342
+ parent->children->prev = base;
343
+ }
344
+ base->parent = parent;
345
+ RB_OBJ_WRITTEN(parent->self, Qundef, base->self);
346
+ RB_OBJ_WRITTEN(base->self, old_parent, parent->self);
347
+ }
348
+
349
+ void oci8_unlink_from_parent(oci8_base_t *base)
350
+ {
351
+ if (base->parent == NULL) {
352
+ return;
353
+ }
354
+ if (base->next == base) {
355
+ base->parent->children = NULL;
356
+ } else {
357
+ if (base->parent->children == base) {
358
+ base->parent->children = base->next;
359
+ }
360
+ base->next->prev = base->prev;
361
+ base->prev->next = base->next;
362
+ base->next = base;
363
+ base->prev = base;
364
+ }
365
+ base->parent = NULL;
366
+ }
367
+
368
+ static void oci8_unblock_func(void *user_data)
369
+ {
370
+ oci8_svcctx_t *svcctx = (oci8_svcctx_t *)user_data;
371
+ ACIBreak(svcctx->base.hp.ptr, oci8_errhp);
372
+ }
373
+
374
+ typedef struct free_temp_lob_arg_t {
375
+ oci8_svcctx_t *svcctx;
376
+ ACISvcCtx *svchp;
377
+ ACIError *errhp;
378
+ ACILobLocator *lob;
379
+ } free_temp_lob_arg_t;
380
+
381
+ static void *free_temp_lob(void *user_data)
382
+ {
383
+ free_temp_lob_arg_t *data = (free_temp_lob_arg_t *)user_data;
384
+ sword rv = ACILobFreeTemporary(data->svchp, data->errhp, data->lob);
385
+
386
+ data->svcctx->executing_thread = Qnil;
387
+ return (void*)(VALUE)rv;
388
+ }
389
+
390
+ typedef struct protected_call_arg {
391
+ void *(*func)(void *);
392
+ void *data;
393
+ oci8_svcctx_t *svcctx;
394
+ } protected_call_arg_t;
395
+
396
+ static VALUE protected_call(VALUE data)
397
+ {
398
+ struct protected_call_arg *parg = (struct protected_call_arg*)data;
399
+ VALUE rv;
400
+
401
+ if (!NIL_P(parg->svcctx->executing_thread)) {
402
+ rb_raise(rb_eRuntimeError, "executing in another thread");
403
+ }
404
+ RB_OBJ_WRITE(parg->svcctx->base.self, &parg->svcctx->executing_thread, rb_thread_current());
405
+ #ifdef HAVE_RB_THREAD_CALL_WITHOUT_GVL
406
+ rv = (VALUE)rb_thread_call_without_gvl(parg->func, parg->data, oci8_unblock_func, parg->svcctx);
407
+ #else
408
+ rv = rb_thread_blocking_region((VALUE(*)(void*))parg->func, parg->data, oci8_unblock_func, parg->svcctx);
409
+ #endif
410
+ if ((sword)rv == ACI_ERROR) {
411
+ if (oci8_get_error_code(oci8_errhp) == 1013) {
412
+ rb_raise(eOCIBreak, "Canceled by user request.");
413
+ }
414
+ }
415
+ return rv;
416
+ }
417
+
418
+ sword oci8_call_without_gvl(oci8_svcctx_t *svcctx, void *(*func)(void *), void *data)
419
+ {
420
+ ACIError *errhp = oci8_errhp;
421
+ protected_call_arg_t parg;
422
+ sword rv;
423
+ int state;
424
+
425
+ if (!NIL_P(svcctx->executing_thread)) {
426
+ rb_raise(rb_eRuntimeError, "executing in another thread");
427
+ }
428
+ if (!svcctx->suppress_free_temp_lobs) {
429
+ oci8_temp_lob_t *lob;
430
+ while ((lob = svcctx->temp_lobs) != NULL) {
431
+ svcctx->temp_lobs = lob->next;
432
+
433
+ if (svcctx->non_blocking) {
434
+ free_temp_lob_arg_t arg;
435
+
436
+ arg.svcctx = svcctx;
437
+ arg.svchp = svcctx->base.hp.svc;
438
+ arg.errhp = errhp;
439
+ arg.lob = lob->lob;
440
+
441
+ parg.svcctx = svcctx;
442
+ parg.func = free_temp_lob;
443
+ parg.data = &arg;
444
+
445
+ rb_protect(protected_call, (VALUE)&parg, &state);
446
+ if (state) {
447
+ lob->next = svcctx->temp_lobs;
448
+ svcctx->temp_lobs = lob;
449
+ rb_jump_tag(state);
450
+ }
451
+ } else {
452
+ ACILobFreeTemporary(svcctx->base.hp.svc, errhp, lob->lob);
453
+ }
454
+ ACIDescriptorFree(lob->lob, ACI_DTYPE_LOB);
455
+ xfree(lob);
456
+ }
457
+ }
458
+
459
+ if (svcctx->non_blocking) {
460
+ parg.svcctx = svcctx;
461
+ parg.func = func;
462
+ parg.data = data;
463
+ rv = (sword)rb_protect(protected_call, (VALUE)&parg, &state);
464
+ if (state) {
465
+ rb_jump_tag(state);
466
+ }
467
+ return rv;
468
+ } else {
469
+ return (sword)(VALUE)func(data);
470
+ }
471
+ }
472
+
473
+ typedef struct {
474
+ oci8_svcctx_t *svcctx;
475
+ const char *sql_text;
476
+ ub4 num_define_vars;
477
+ oci8_exec_sql_var_t *define_vars;
478
+ ub4 num_bind_vars;
479
+ oci8_exec_sql_var_t *bind_vars;
480
+ int raise_on_error;
481
+ ACIStmt *stmtp;
482
+ } cb_arg_t;
483
+
484
+ static VALUE exec_sql(VALUE varg);
485
+ static VALUE ensure_func(VALUE varg);
486
+
487
+ /*
488
+ * utility function to execute a single SQL statement
489
+ */
490
+ sword oci8_exec_sql(oci8_svcctx_t *svcctx, const char *sql_text, ub4 num_define_vars, oci8_exec_sql_var_t *define_vars, ub4 num_bind_vars, oci8_exec_sql_var_t *bind_vars, int raise_on_error)
491
+ {
492
+ cb_arg_t arg;
493
+
494
+ oci8_check_pid_consistency(svcctx);
495
+ arg.svcctx = svcctx;
496
+ arg.sql_text = sql_text;
497
+ arg.num_define_vars = num_define_vars;
498
+ arg.define_vars = define_vars;
499
+ arg.num_bind_vars = num_bind_vars;
500
+ arg.bind_vars = bind_vars;
501
+ arg.raise_on_error = raise_on_error;
502
+ arg.stmtp = NULL;
503
+ return (sword)rb_ensure(exec_sql, (VALUE)&arg, ensure_func, (VALUE)&arg);
504
+ }
505
+
506
+ static VALUE exec_sql(VALUE varg)
507
+ {
508
+ cb_arg_t *arg = (cb_arg_t *)varg;
509
+ ub4 pos;
510
+ sword rv;
511
+
512
+ chker2(ACIStmtPrepare2(arg->svcctx->base.hp.svc, &arg->stmtp, oci8_errhp,
513
+ (text*)arg->sql_text, strlen(arg->sql_text), NULL, 0,
514
+ ACI_NTV_SYNTAX, ACI_DEFAULT),
515
+ &arg->svcctx->base);
516
+ for (pos = 0; pos < arg->num_define_vars; pos++) {
517
+ arg->define_vars[pos].hp = NULL;
518
+ chker3(ACIDefineByPos(arg->stmtp, (ACIDefine**)&arg->define_vars[pos].hp,
519
+ oci8_errhp, pos + 1, arg->define_vars[pos].valuep,
520
+ arg->define_vars[pos].value_sz,
521
+ arg->define_vars[pos].dty, arg->define_vars[pos].indp,
522
+ arg->define_vars[pos].alenp, NULL, ACI_DEFAULT),
523
+ &arg->svcctx->base, arg->stmtp);
524
+ }
525
+ for (pos = 0; pos < arg->num_bind_vars; pos++) {
526
+ arg->bind_vars[pos].hp = NULL;
527
+ chker3(ACIBindByPos(arg->stmtp, (ACIBind**)&arg->bind_vars[pos].hp,
528
+ oci8_errhp, pos + 1, arg->bind_vars[pos].valuep,
529
+ arg->bind_vars[pos].value_sz, arg->bind_vars[pos].dty,
530
+ arg->bind_vars[pos].indp, arg->bind_vars[pos].alenp,
531
+ NULL, 0, NULL, ACI_DEFAULT),
532
+ &arg->svcctx->base, arg->stmtp);
533
+ }
534
+ rv = ACIStmtExecute_nb(arg->svcctx, arg->svcctx->base.hp.svc, arg->stmtp, oci8_errhp, 1, 0, NULL, NULL, ACI_DEFAULT);
535
+ if (rv == ACI_ERROR) {
536
+ if (oci8_get_error_code(oci8_errhp) == 1000) {
537
+ /* run GC to close unreferred cursors
538
+ * when ORA-01000 (maximum open cursors exceeded).
539
+ */
540
+ rb_gc();
541
+ rv = ACIStmtExecute_nb(arg->svcctx, arg->svcctx->base.hp.svc, arg->stmtp, oci8_errhp, 1, 0, NULL, NULL, ACI_DEFAULT);
542
+ }
543
+ }
544
+ if (arg->raise_on_error) {
545
+ chker3(rv, &arg->svcctx->base, arg->stmtp);
546
+ }
547
+ return (VALUE)rv;
548
+ }
549
+
550
+ static VALUE ensure_func(VALUE varg)
551
+ {
552
+ cb_arg_t *arg = (cb_arg_t *)varg;
553
+ if (arg->stmtp != NULL) {
554
+ ACIStmtRelease(arg->stmtp, oci8_errhp, NULL, 0, ACI_DEFAULT);
555
+ }
556
+ return Qnil;
557
+ }
558
+
559
+ #if defined RUNTIME_API_CHECK
560
+
561
+ #ifndef _WIN32
562
+ #include <dlfcn.h>
563
+ static void *load_file(const char *filename, int flags, VALUE errors)
564
+ {
565
+ void *handle = dlopen(filename, flags);
566
+
567
+ if (handle == NULL) {
568
+ char *err = dlerror();
569
+ VALUE msg;
570
+
571
+ if (strstr(err, filename) == NULL) {
572
+ msg = rb_sprintf("%s: %s", filename, err);
573
+ msg = rb_enc_associate_index(msg, rb_locale_encindex());
574
+ } else {
575
+ msg = rb_locale_str_new_cstr(err);
576
+ }
577
+ rb_ary_push(errors, msg);
578
+ }
579
+ return handle;
580
+ }
581
+ #endif
582
+
583
+ void *oci8_find_symbol(const char *symbol_name)
584
+ {
585
+ #if defined _WIN32
586
+ /* Windows */
587
+ static HMODULE hModule = NULL;
588
+
589
+ if (hModule == NULL) {
590
+ hModule = LoadLibrary("ACI.DLL");
591
+ if (hModule == NULL) {
592
+ char message[512];
593
+ int error = GetLastError();
594
+ char *p;
595
+
596
+ memset(message, 0, sizeof(message));
597
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), message, sizeof(message), NULL);
598
+ for (p = message; *p; p++) {
599
+ if (*p == '\n' || *p == '\r')
600
+ *p = ' ';
601
+ }
602
+ rb_raise(rb_eLoadError, "ACI.DLL: %d(%s)", error, message);
603
+ }
604
+ }
605
+ return GetProcAddress(hModule, symbol_name);
606
+ #else
607
+ /* UNIX */
608
+ static void *handle = NULL;
609
+
610
+ if (handle == NULL) {
611
+ static const char * const sonames[] = {
612
+ #if defined(__CYGWIN__)
613
+ /* Windows(Cygwin) */
614
+ "ACI.DLL",
615
+ #elif defined(_AIX)
616
+ /* AIX */
617
+ "libclntsh.a(shr.o)",
618
+ #elif defined(__hppa)
619
+ /* HP-UX(PA-RISC) */
620
+ "libclntsh.sl.12.1",
621
+ "libclntsh.sl.11.1",
622
+ "libclntsh.sl.10.1",
623
+ #elif defined(__APPLE__)
624
+ /* Mac OS X */
625
+ "libclntsh.dylib",
626
+ "libclntsh.dylib.12.1",
627
+ "libclntsh.dylib.11.1",
628
+ "libclntsh.dylib.10.1",
629
+ #else
630
+ /* Linux, Solaris and HP-UX(IA64) */
631
+ "libclntsh.so",
632
+ "libclntsh.so.12.1",
633
+ "libclntsh.so.11.1",
634
+ "libclntsh.so.10.1",
635
+ #endif
636
+ };
637
+ #define NUM_SONAMES (sizeof(sonames)/sizeof(sonames[0]))
638
+ #if defined(_AIX) /* AIX */
639
+ #define BASE_SONAME "libaci.a"
640
+ #elif defined(__hppa) /* HP-UX(PA-RISC) */
641
+ #define BASE_SONAME "libaci.so"
642
+ #elif !defined(__CYGWIN__) && !defined(__APPLE__)
643
+ #define BASE_SONAME "libaci.so"
644
+ #endif
645
+ size_t idx;
646
+ VALUE err = rb_ary_new();
647
+
648
+ #ifdef _AIX
649
+ #define DLOPEN_FLAG (RTLD_LAZY|RTLD_GLOBAL|RTLD_MEMBER)
650
+ #else
651
+ #define DLOPEN_FLAG (RTLD_LAZY|RTLD_GLOBAL)
652
+ #endif
653
+ #ifdef BASE_SONAME
654
+ char *oracle_home = getenv("SZ_OSCAR_HOME");
655
+
656
+ if (oracle_home != NULL) {
657
+ VALUE fname = rb_str_buf_cat2(rb_str_buf_new_cstr(oracle_home), "/bin/" BASE_SONAME);
658
+ handle = load_file(StringValueCStr(fname), DLOPEN_FLAG, err);
659
+ RB_GC_GUARD(fname);
660
+ }
661
+ #endif
662
+ for (idx = 0; handle == NULL && idx < NUM_SONAMES; idx++) {
663
+ handle = load_file(sonames[idx], DLOPEN_FLAG, err);
664
+ }
665
+ if (handle == NULL) {
666
+ VALUE msg = rb_ary_join(err, rb_usascii_str_new_cstr("; "));
667
+ rb_exc_raise(rb_exc_new3(rb_eLoadError, msg));
668
+ }
669
+ }
670
+ return dlsym(handle, symbol_name);
671
+ #endif /* defined _WIN32 */
672
+ }
673
+ #endif /* RUNTIME_API_CHECK */
674
+
675
+ void *oci8_check_typeddata(VALUE obj, const oci8_handle_data_type_t *data_type, int error_if_closed)
676
+ {
677
+ #ifdef HAVE_RB_DATA_TYPE_T_FUNCTION
678
+ oci8_base_t *hp = Check_TypedStruct(obj, &data_type->rb_data_type);
679
+ #else
680
+ oci8_base_t *hp;
681
+ const char *expected_type_name = data_type->rb_data_type.wrap_struct_name;
682
+ const rb_data_type_t *rb_data_type;
683
+ const rb_data_type_t *expected_rb_data_type = &data_type->rb_data_type;
684
+
685
+ if (TYPE(obj) != T_DATA || !rb_obj_is_kind_of(obj, oci8_cOCIHandle)) {
686
+ rb_raise(rb_eTypeError, "wrong argument type %s (expected %s)",
687
+ rb_obj_classname(obj), expected_type_name);
688
+ }
689
+ hp = DATA_PTR(obj);
690
+ rb_data_type = &hp->data_type->rb_data_type;
691
+ while (rb_data_type != expected_rb_data_type) {
692
+ if (rb_data_type == NULL) {
693
+ rb_raise(rb_eTypeError, "wrong argument type %s (expected %s)",
694
+ rb_obj_classname(obj), expected_type_name);
695
+ }
696
+ rb_data_type = rb_data_type->parent;
697
+ }
698
+ #endif
699
+ if (error_if_closed && hp->closed) {
700
+ rb_raise(eOCIException, "%s was already closed.",
701
+ rb_obj_classname(obj));
702
+ }
703
+ return hp;
704
+ }