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