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.
- checksums.yaml +7 -0
- data/.yardopts +14 -0
- data/COPYING +30 -0
- data/COPYING_old +64 -0
- data/ChangeLog +3826 -0
- data/Makefile +92 -0
- data/NEWS +1194 -0
- data/README.md +66 -0
- data/dist-files +113 -0
- data/docs/bind-array-to-in_cond.md +38 -0
- data/docs/conflicts-local-connections-and-processes.md +98 -0
- data/docs/hanging-after-inactivity.md +63 -0
- data/docs/install-binary-package.md +44 -0
- data/docs/install-full-client.md +111 -0
- data/docs/install-instant-client.md +194 -0
- data/docs/install-on-osx.md +133 -0
- data/docs/ldap-auth-and-function-interposition.md +123 -0
- data/docs/number-type-mapping.md +79 -0
- data/docs/osx-install-dev-tools.png +0 -0
- data/docs/platform-specific-issues.md +164 -0
- data/docs/report-installation-issue.md +50 -0
- data/docs/timeout-parameters.md +94 -0
- data/ext/oci8/.document +18 -0
- data/ext/oci8/MANIFEST +18 -0
- data/ext/oci8/apiwrap.c.tmpl +178 -0
- data/ext/oci8/apiwrap.h.tmpl +61 -0
- data/ext/oci8/apiwrap.rb +96 -0
- data/ext/oci8/apiwrap.yml +1322 -0
- data/ext/oci8/attr.c +57 -0
- data/ext/oci8/bind.c +838 -0
- data/ext/oci8/connection_pool.c +216 -0
- data/ext/oci8/encoding.c +196 -0
- data/ext/oci8/env.c +139 -0
- data/ext/oci8/error.c +385 -0
- data/ext/oci8/extconf.rb +219 -0
- data/ext/oci8/hook_funcs.c +407 -0
- data/ext/oci8/lob.c +1278 -0
- data/ext/oci8/metadata.c +279 -0
- data/ext/oci8/object.c +919 -0
- data/ext/oci8/oci8.c +1058 -0
- data/ext/oci8/oci8.h +556 -0
- data/ext/oci8/oci8lib.c +704 -0
- data/ext/oci8/ocidatetime.c +506 -0
- data/ext/oci8/ocihandle.c +852 -0
- data/ext/oci8/ocinumber.c +1922 -0
- data/ext/oci8/oraconf.rb +1145 -0
- data/ext/oci8/oradate.c +670 -0
- data/ext/oci8/oranumber_util.c +352 -0
- data/ext/oci8/oranumber_util.h +24 -0
- data/ext/oci8/plthook.h +66 -0
- data/ext/oci8/plthook_elf.c +702 -0
- data/ext/oci8/plthook_osx.c +505 -0
- data/ext/oci8/plthook_win32.c +391 -0
- data/ext/oci8/post-config.rb +5 -0
- data/ext/oci8/stmt.c +448 -0
- data/ext/oci8/thread_util.c +81 -0
- data/ext/oci8/thread_util.h +18 -0
- data/ext/oci8/util.c +71 -0
- data/ext/oci8/win32.c +117 -0
- data/lib/.document +1 -0
- data/lib/dbd/STACI.rb +591 -0
- data/lib/oci8/.document +8 -0
- data/lib/oci8/bindtype.rb +333 -0
- data/lib/oci8/check_load_error.rb +146 -0
- data/lib/oci8/compat.rb +117 -0
- data/lib/oci8/connection_pool.rb +179 -0
- data/lib/oci8/cursor.rb +605 -0
- data/lib/oci8/datetime.rb +605 -0
- data/lib/oci8/encoding-init.rb +45 -0
- data/lib/oci8/encoding.yml +537 -0
- data/lib/oci8/metadata.rb +2148 -0
- data/lib/oci8/object.rb +641 -0
- data/lib/oci8/oci8.rb +756 -0
- data/lib/oci8/ocihandle.rb +591 -0
- data/lib/oci8/oracle_version.rb +153 -0
- data/lib/oci8/properties.rb +196 -0
- data/lib/oci8/version.rb +3 -0
- data/lib/ruby-staci.rb +1 -0
- data/lib/staci.rb +190 -0
- data/metaconfig +142 -0
- data/pre-distclean.rb +7 -0
- data/ruby-aci.gemspec +83 -0
- data/setup.rb +1342 -0
- data/test/README.md +37 -0
- data/test/config.rb +201 -0
- data/test/setup_test_object.sql +199 -0
- data/test/setup_test_package.sql +59 -0
- data/test/test_all.rb +56 -0
- data/test/test_appinfo.rb +62 -0
- data/test/test_array_dml.rb +333 -0
- data/test/test_bind_array.rb +70 -0
- data/test/test_bind_boolean.rb +99 -0
- data/test/test_bind_integer.rb +47 -0
- data/test/test_bind_raw.rb +45 -0
- data/test/test_bind_string.rb +105 -0
- data/test/test_bind_time.rb +177 -0
- data/test/test_break.rb +124 -0
- data/test/test_clob.rb +86 -0
- data/test/test_connection_pool.rb +124 -0
- data/test/test_connstr.rb +220 -0
- data/test/test_datetime.rb +585 -0
- data/test/test_dbi.rb +365 -0
- data/test/test_dbi_clob.rb +53 -0
- data/test/test_encoding.rb +103 -0
- data/test/test_error.rb +87 -0
- data/test/test_metadata.rb +2674 -0
- data/test/test_object.rb +546 -0
- data/test/test_oci8.rb +624 -0
- data/test/test_oracle_version.rb +68 -0
- data/test/test_oradate.rb +255 -0
- data/test/test_oranumber.rb +786 -0
- data/test/test_package_type.rb +981 -0
- data/test/test_properties.rb +17 -0
- data/test/test_rowid.rb +32 -0
- metadata +158 -0
data/ext/oci8/oci8lib.c
ADDED
@@ -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
|
+
}
|