ruby-oci8-master 2.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/ChangeLog +2321 -0
- data/Makefile +88 -0
- data/NEWS +303 -0
- data/README +76 -0
- data/VERSION +1 -0
- data/dist-files +83 -0
- data/doc/api.en.html +527 -0
- data/doc/api.en.rd +554 -0
- data/doc/api.ja.html +525 -0
- data/doc/api.ja.rd +557 -0
- data/doc/manual.css +35 -0
- data/ext/oci8/.document +18 -0
- data/ext/oci8/MANIFEST +18 -0
- data/ext/oci8/apiwrap.c.tmpl +182 -0
- data/ext/oci8/apiwrap.h.tmpl +61 -0
- data/ext/oci8/apiwrap.rb +91 -0
- data/ext/oci8/apiwrap.yml +1455 -0
- data/ext/oci8/attr.c +105 -0
- data/ext/oci8/bind.c +366 -0
- data/ext/oci8/connection_pool.c +199 -0
- data/ext/oci8/encoding.c +289 -0
- data/ext/oci8/env.c +178 -0
- data/ext/oci8/error.c +378 -0
- data/ext/oci8/extconf.rb +179 -0
- data/ext/oci8/lob.c +805 -0
- data/ext/oci8/metadata.c +232 -0
- data/ext/oci8/object.c +727 -0
- data/ext/oci8/oci8.c +1156 -0
- data/ext/oci8/oci8.h +574 -0
- data/ext/oci8/oci8lib.c +527 -0
- data/ext/oci8/ocidatetime.c +484 -0
- data/ext/oci8/ocihandle.c +751 -0
- data/ext/oci8/ocinumber.c +1612 -0
- data/ext/oci8/oraconf.rb +1119 -0
- data/ext/oci8/oradate.c +611 -0
- data/ext/oci8/oranumber_util.c +352 -0
- data/ext/oci8/oranumber_util.h +24 -0
- data/ext/oci8/post-config.rb +5 -0
- data/ext/oci8/stmt.c +673 -0
- data/ext/oci8/thread_util.c +85 -0
- data/ext/oci8/thread_util.h +30 -0
- data/ext/oci8/win32.c +137 -0
- data/lib/.document +1 -0
- data/lib/dbd/OCI8.rb +591 -0
- data/lib/oci8.rb.in +94 -0
- data/lib/oci8/.document +8 -0
- data/lib/oci8/bindtype.rb +349 -0
- data/lib/oci8/compat.rb +113 -0
- data/lib/oci8/connection_pool.rb +99 -0
- data/lib/oci8/datetime.rb +611 -0
- data/lib/oci8/encoding-init.rb +74 -0
- data/lib/oci8/encoding.yml +537 -0
- data/lib/oci8/metadata.rb +2132 -0
- data/lib/oci8/object.rb +581 -0
- data/lib/oci8/oci8.rb +721 -0
- data/lib/oci8/ocihandle.rb +425 -0
- data/lib/oci8/oracle_version.rb +144 -0
- data/lib/oci8/properties.rb +73 -0
- data/metaconfig +142 -0
- data/pre-distclean.rb +7 -0
- data/ruby-oci8.gemspec +63 -0
- data/setup.rb +1331 -0
- data/test/README +4 -0
- data/test/config.rb +122 -0
- data/test/test_all.rb +51 -0
- data/test/test_appinfo.rb +63 -0
- data/test/test_array_dml.rb +333 -0
- data/test/test_bind_raw.rb +46 -0
- data/test/test_bind_time.rb +178 -0
- data/test/test_break.rb +96 -0
- data/test/test_clob.rb +82 -0
- data/test/test_connstr.rb +81 -0
- data/test/test_datetime.rb +582 -0
- data/test/test_dbi.rb +366 -0
- data/test/test_dbi_clob.rb +53 -0
- data/test/test_encoding.rb +100 -0
- data/test/test_error.rb +88 -0
- data/test/test_metadata.rb +1399 -0
- data/test/test_oci8.rb +434 -0
- data/test/test_oracle_version.rb +70 -0
- data/test/test_oradate.rb +256 -0
- data/test/test_oranumber.rb +746 -0
- data/test/test_rowid.rb +33 -0
- metadata +137 -0
data/ext/oci8/oci8.c
ADDED
@@ -0,0 +1,1156 @@
|
|
1
|
+
/* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
|
2
|
+
/*
|
3
|
+
* oci8.c - part of ruby-oci8
|
4
|
+
*
|
5
|
+
* Copyright (C) 2002-2011 KUBO Takehiro <kubo@jiubao.org>
|
6
|
+
*
|
7
|
+
*/
|
8
|
+
#include "oci8.h"
|
9
|
+
#include <errno.h>
|
10
|
+
#ifdef HAVE_UNISTD_H
|
11
|
+
#include <unistd.h> /* getpid() */
|
12
|
+
#endif
|
13
|
+
|
14
|
+
#ifdef WIN32
|
15
|
+
#ifndef getpid
|
16
|
+
extern rb_pid_t rb_w32_getpid(void);
|
17
|
+
#define getpid() rb_w32_getpid()
|
18
|
+
#endif
|
19
|
+
#endif
|
20
|
+
|
21
|
+
#ifndef OCI_ATTR_CLIENT_IDENTIFIER
|
22
|
+
#define OCI_ATTR_CLIENT_IDENTIFIER 278
|
23
|
+
#endif
|
24
|
+
#ifndef OCI_ATTR_MODULE
|
25
|
+
#define OCI_ATTR_MODULE 366
|
26
|
+
#endif
|
27
|
+
#ifndef OCI_ATTR_ACTION
|
28
|
+
#define OCI_ATTR_ACTION 367
|
29
|
+
#endif
|
30
|
+
#ifndef OCI_ATTR_CLIENT_INFO
|
31
|
+
#define OCI_ATTR_CLIENT_INFO 368
|
32
|
+
#endif
|
33
|
+
|
34
|
+
#define OCI8_STATE_SESSION_BEGIN_WAS_CALLED 0x01
|
35
|
+
#define OCI8_STATE_SERVER_ATTACH_WAS_CALLED 0x02
|
36
|
+
|
37
|
+
static VALUE cOCI8;
|
38
|
+
static VALUE cSession;
|
39
|
+
static VALUE cServer;
|
40
|
+
static ID id_at_session_handle;
|
41
|
+
static ID id_at_server_handle;
|
42
|
+
|
43
|
+
typedef struct oci8_svcctx_associate {
|
44
|
+
oci8_base_t base;
|
45
|
+
oci8_svcctx_t *svcctx;
|
46
|
+
} oci8_svcctx_associate_t;
|
47
|
+
|
48
|
+
static void oci8_svcctx_associate_free(oci8_base_t *base)
|
49
|
+
{
|
50
|
+
base->type = 0;
|
51
|
+
base->hp.ptr = NULL;
|
52
|
+
}
|
53
|
+
|
54
|
+
static oci8_base_vtable_t oci8_svcctx_associate_vtable = {
|
55
|
+
NULL,
|
56
|
+
oci8_svcctx_associate_free,
|
57
|
+
sizeof(oci8_svcctx_associate_t),
|
58
|
+
};
|
59
|
+
|
60
|
+
static void copy_session_handle(oci8_svcctx_t *svcctx)
|
61
|
+
{
|
62
|
+
VALUE obj = rb_ivar_get(svcctx->base.self, id_at_session_handle);
|
63
|
+
oci8_base_t *base;
|
64
|
+
|
65
|
+
Check_Handle(obj, cSession, base);
|
66
|
+
base->type = OCI_HTYPE_SESSION;
|
67
|
+
base->hp.usrhp = svcctx->usrhp;
|
68
|
+
}
|
69
|
+
|
70
|
+
static void copy_server_handle(oci8_svcctx_t *svcctx)
|
71
|
+
{
|
72
|
+
VALUE obj = rb_ivar_get(svcctx->base.self, id_at_server_handle);
|
73
|
+
oci8_base_t *base;
|
74
|
+
|
75
|
+
Check_Handle(obj, cServer, base);
|
76
|
+
base->type = OCI_HTYPE_SERVER;
|
77
|
+
base->hp.srvhp = svcctx->srvhp;
|
78
|
+
}
|
79
|
+
|
80
|
+
static void oci8_svcctx_free(oci8_base_t *base)
|
81
|
+
{
|
82
|
+
oci8_svcctx_t *svcctx = (oci8_svcctx_t *)base;
|
83
|
+
if (svcctx->logoff_strategy != NULL) {
|
84
|
+
const oci8_logoff_strategy_t *strategy = svcctx->logoff_strategy;
|
85
|
+
void *data = strategy->prepare(svcctx);
|
86
|
+
int rv;
|
87
|
+
svcctx->base.type = 0;
|
88
|
+
svcctx->logoff_strategy = NULL;
|
89
|
+
rv = oci8_run_native_thread(strategy->execute, data);
|
90
|
+
if (rv != 0) {
|
91
|
+
errno = rv;
|
92
|
+
#ifdef WIN32
|
93
|
+
rb_sys_fail("_beginthread");
|
94
|
+
#else
|
95
|
+
rb_sys_fail("pthread_create");
|
96
|
+
#endif
|
97
|
+
}
|
98
|
+
}
|
99
|
+
svcctx->base.type = 0;
|
100
|
+
}
|
101
|
+
|
102
|
+
static void oci8_svcctx_init(oci8_base_t *base)
|
103
|
+
{
|
104
|
+
oci8_svcctx_t *svcctx = (oci8_svcctx_t *)base;
|
105
|
+
VALUE obj;
|
106
|
+
|
107
|
+
svcctx->executing_thread = Qnil;
|
108
|
+
/* set session handle */
|
109
|
+
obj = rb_obj_alloc(cSession);
|
110
|
+
rb_ivar_set(base->self, id_at_session_handle, obj);
|
111
|
+
oci8_link_to_parent(DATA_PTR(obj), base);
|
112
|
+
/* set server handle */
|
113
|
+
obj = rb_obj_alloc(cServer);
|
114
|
+
rb_ivar_set(base->self, id_at_server_handle, obj);
|
115
|
+
oci8_link_to_parent(DATA_PTR(obj), base);
|
116
|
+
|
117
|
+
svcctx->pid = getpid();
|
118
|
+
svcctx->is_autocommit = 0;
|
119
|
+
#ifdef HAVE_RB_THREAD_BLOCKING_REGION
|
120
|
+
svcctx->non_blocking = 1;
|
121
|
+
#endif
|
122
|
+
svcctx->long_read_len = INT2FIX(65535);
|
123
|
+
}
|
124
|
+
|
125
|
+
static oci8_base_vtable_t oci8_svcctx_vtable = {
|
126
|
+
NULL,
|
127
|
+
oci8_svcctx_free,
|
128
|
+
sizeof(oci8_svcctx_t),
|
129
|
+
oci8_svcctx_init,
|
130
|
+
};
|
131
|
+
|
132
|
+
static VALUE oracle_client_vernum; /* Oracle client version number */
|
133
|
+
static VALUE sym_SYSDBA;
|
134
|
+
static VALUE sym_SYSOPER;
|
135
|
+
static ID id_at_prefetch_rows;
|
136
|
+
static ID id_set_prefetch_rows;
|
137
|
+
|
138
|
+
static VALUE oci8_s_oracle_client_vernum(VALUE klass)
|
139
|
+
{
|
140
|
+
return oracle_client_vernum;
|
141
|
+
}
|
142
|
+
|
143
|
+
static VALUE oci8_s_set_property(VALUE klass, VALUE name, VALUE val)
|
144
|
+
{
|
145
|
+
const char *name_str;
|
146
|
+
|
147
|
+
Check_Type(name, T_SYMBOL);
|
148
|
+
name_str = rb_id2name(SYM2ID(name));
|
149
|
+
if (strcmp(name_str, "float_conversion_type") == 0) {
|
150
|
+
const char *val_str;
|
151
|
+
Check_Type(val, T_SYMBOL);
|
152
|
+
val_str = rb_id2name(SYM2ID(val));
|
153
|
+
if (strcmp(val_str, "ruby") == 0) {
|
154
|
+
oci8_float_conversion_type_is_ruby = 1;
|
155
|
+
} else if (strcmp(val_str, "oracle") == 0) {
|
156
|
+
oci8_float_conversion_type_is_ruby = 0;
|
157
|
+
} else {
|
158
|
+
rb_raise(rb_eArgError, "float_conversion_type's value should be either :ruby or :oracle.");
|
159
|
+
}
|
160
|
+
}
|
161
|
+
return Qnil;
|
162
|
+
}
|
163
|
+
|
164
|
+
/*
|
165
|
+
* call-seq:
|
166
|
+
* OCI8.error_message(message_no) -> string
|
167
|
+
*
|
168
|
+
* Get the Oracle error message specified by message_no.
|
169
|
+
* Its language depends on NLS_LANGUAGE.
|
170
|
+
*
|
171
|
+
* Note: This method is unavailable if the Oracle client version is 8.0.
|
172
|
+
*
|
173
|
+
* example:
|
174
|
+
* # When NLS_LANG is AMERICAN_AMERICA.AL32UTF8
|
175
|
+
* OCI8.error_message(1) # => "ORA-00001: unique constraint (%s.%s) violated"
|
176
|
+
*
|
177
|
+
* # When NLS_LANG is FRENCH_FRANCE.AL32UTF8
|
178
|
+
* OCI8.error_message(1) # => "ORA-00001: violation de contrainte unique (%s.%s)"
|
179
|
+
*
|
180
|
+
*/
|
181
|
+
static VALUE oci8_s_error_message(VALUE klass, VALUE msgid)
|
182
|
+
{
|
183
|
+
return oci8_get_error_message(NUM2UINT(msgid), NULL);
|
184
|
+
}
|
185
|
+
|
186
|
+
#define CONN_STR_REGEX "/^([^(\\s|\\@)]*)\\/([^(\\s|\\@)]*)(?:\\@(\\S+))?(?:\\s+as\\s+(\\S*)\\s*)?$/i"
|
187
|
+
void oci8_do_parse_connect_string(VALUE conn_str, VALUE *user, VALUE *pass, VALUE *dbname, VALUE *mode)
|
188
|
+
{
|
189
|
+
static VALUE re = Qnil;
|
190
|
+
if (NIL_P(re)) {
|
191
|
+
re = rb_eval_string(CONN_STR_REGEX);
|
192
|
+
rb_global_variable(&re);
|
193
|
+
}
|
194
|
+
OCI8SafeStringValue(conn_str);
|
195
|
+
if (RTEST(rb_reg_match(re, conn_str))) {
|
196
|
+
*user = rb_reg_nth_match(1, rb_backref_get());
|
197
|
+
*pass = rb_reg_nth_match(2, rb_backref_get());
|
198
|
+
*dbname = rb_reg_nth_match(3, rb_backref_get());
|
199
|
+
*mode = rb_reg_nth_match(4, rb_backref_get());
|
200
|
+
if (RSTRING_LEN(*user) == 0 && RSTRING_LEN(*pass) == 0) {
|
201
|
+
/* external credential */
|
202
|
+
*user = Qnil;
|
203
|
+
*pass = Qnil;
|
204
|
+
}
|
205
|
+
if (!NIL_P(*mode)) {
|
206
|
+
char *ptr;
|
207
|
+
SafeStringValue(*mode);
|
208
|
+
ptr = RSTRING_PTR(*mode);
|
209
|
+
if (strcasecmp(ptr, "SYSDBA") == 0) {
|
210
|
+
*mode = sym_SYSDBA;
|
211
|
+
} else if (strcasecmp(ptr, "SYSOPER") == 0) {
|
212
|
+
*mode = sym_SYSOPER;
|
213
|
+
}
|
214
|
+
}
|
215
|
+
} else {
|
216
|
+
rb_raise(rb_eArgError, "invalid connect string \"%s\" (expect \"username/password[@(tns_name|//host[:port]/service_name)][ as (sysdba|sysoper)]\"", RSTRING_PTR(conn_str));
|
217
|
+
}
|
218
|
+
}
|
219
|
+
|
220
|
+
/*
|
221
|
+
* call-seq:
|
222
|
+
* parse_connect_string(string) -> [username, password, dbname, privilege]
|
223
|
+
*
|
224
|
+
* Extracts +username+, +password+, +dbname+ and +privilege+ from the specified +string+.
|
225
|
+
*
|
226
|
+
* example:
|
227
|
+
* "scott/tiger" -> ["scott", "tiger", nil, nil],
|
228
|
+
* "scott/tiger@oradb.example.com" -> ["scott", "tiger", "oradb.example.com", nil]
|
229
|
+
* "sys/change_on_install as sysdba" -> ["sys", "change_on_install", nil, :SYSDBA]
|
230
|
+
*
|
231
|
+
*/
|
232
|
+
static VALUE oci8_parse_connect_string(VALUE self, VALUE conn_str)
|
233
|
+
{
|
234
|
+
VALUE user;
|
235
|
+
VALUE pass;
|
236
|
+
VALUE dbname;
|
237
|
+
VALUE mode;
|
238
|
+
|
239
|
+
oci8_do_parse_connect_string(conn_str, &user, &pass, &dbname, &mode);
|
240
|
+
return rb_ary_new3(4, user, pass, dbname, mode);
|
241
|
+
}
|
242
|
+
|
243
|
+
/*
|
244
|
+
* Logoff strategy for sessions connected by OCILogon.
|
245
|
+
*/
|
246
|
+
typedef struct {
|
247
|
+
OCISvcCtx *svchp;
|
248
|
+
OCISession *usrhp;
|
249
|
+
OCIServer *srvhp;
|
250
|
+
} simple_logoff_arg_t;
|
251
|
+
|
252
|
+
static void *simple_logoff_prepare(oci8_svcctx_t *svcctx)
|
253
|
+
{
|
254
|
+
simple_logoff_arg_t *sla = xmalloc(sizeof(simple_logoff_arg_t));
|
255
|
+
sla->svchp = svcctx->base.hp.svc;
|
256
|
+
sla->usrhp = svcctx->usrhp;
|
257
|
+
sla->srvhp = svcctx->srvhp;
|
258
|
+
svcctx->usrhp = NULL;
|
259
|
+
svcctx->srvhp = NULL;
|
260
|
+
return sla;
|
261
|
+
}
|
262
|
+
|
263
|
+
static VALUE simple_logoff_execute(void *arg)
|
264
|
+
{
|
265
|
+
simple_logoff_arg_t *sla = (simple_logoff_arg_t *)arg;
|
266
|
+
OCIError *errhp = oci8_errhp;
|
267
|
+
sword rv;
|
268
|
+
|
269
|
+
OCITransRollback(sla->svchp, errhp, OCI_DEFAULT);
|
270
|
+
rv = OCILogoff(sla->svchp, errhp);
|
271
|
+
xfree(sla);
|
272
|
+
return (VALUE)rv;
|
273
|
+
}
|
274
|
+
|
275
|
+
static const oci8_logoff_strategy_t simple_logoff = {
|
276
|
+
simple_logoff_prepare,
|
277
|
+
simple_logoff_execute,
|
278
|
+
};
|
279
|
+
|
280
|
+
/*
|
281
|
+
* Logoff strategy for sessions connected by OCIServerAttach and OCISessionBegin.
|
282
|
+
*/
|
283
|
+
|
284
|
+
typedef struct {
|
285
|
+
OCISvcCtx *svchp;
|
286
|
+
OCISession *usrhp;
|
287
|
+
OCIServer *srvhp;
|
288
|
+
unsigned char state;
|
289
|
+
} complex_logoff_arg_t;
|
290
|
+
|
291
|
+
static void *complex_logoff_prepare(oci8_svcctx_t *svcctx)
|
292
|
+
{
|
293
|
+
complex_logoff_arg_t *cla = xmalloc(sizeof(complex_logoff_arg_t));
|
294
|
+
cla->svchp = svcctx->base.hp.svc;
|
295
|
+
cla->usrhp = svcctx->usrhp;
|
296
|
+
cla->srvhp = svcctx->srvhp;
|
297
|
+
cla->state = svcctx->state;
|
298
|
+
svcctx->usrhp = NULL;
|
299
|
+
svcctx->srvhp = NULL;
|
300
|
+
svcctx->state = 0;
|
301
|
+
return cla;
|
302
|
+
}
|
303
|
+
|
304
|
+
static VALUE complex_logoff_execute(void *arg)
|
305
|
+
{
|
306
|
+
complex_logoff_arg_t *cla = (complex_logoff_arg_t *)arg;
|
307
|
+
OCIError *errhp = oci8_errhp;
|
308
|
+
sword rv = OCI_SUCCESS;
|
309
|
+
|
310
|
+
OCITransRollback(cla->svchp, errhp, OCI_DEFAULT);
|
311
|
+
|
312
|
+
if (cla->state & OCI8_STATE_SESSION_BEGIN_WAS_CALLED) {
|
313
|
+
rv = OCISessionEnd(cla->svchp, oci8_errhp, cla->usrhp, OCI_DEFAULT);
|
314
|
+
cla->state &= ~OCI8_STATE_SESSION_BEGIN_WAS_CALLED;
|
315
|
+
}
|
316
|
+
if (cla->state & OCI8_STATE_SERVER_ATTACH_WAS_CALLED) {
|
317
|
+
rv = OCIServerDetach(cla->srvhp, oci8_errhp, OCI_DEFAULT);
|
318
|
+
cla->state &= ~OCI8_STATE_SERVER_ATTACH_WAS_CALLED;
|
319
|
+
}
|
320
|
+
if (cla->usrhp != NULL) {
|
321
|
+
OCIHandleFree(cla->usrhp, OCI_HTYPE_SESSION);
|
322
|
+
}
|
323
|
+
if (cla->srvhp != NULL) {
|
324
|
+
OCIHandleFree(cla->srvhp, OCI_HTYPE_SERVER);
|
325
|
+
}
|
326
|
+
if (cla->svchp != NULL) {
|
327
|
+
OCIHandleFree(cla->svchp, OCI_HTYPE_SVCCTX);
|
328
|
+
}
|
329
|
+
xfree(cla);
|
330
|
+
return (VALUE)rv;
|
331
|
+
}
|
332
|
+
|
333
|
+
static const oci8_logoff_strategy_t complex_logoff = {
|
334
|
+
complex_logoff_prepare,
|
335
|
+
complex_logoff_execute,
|
336
|
+
};
|
337
|
+
|
338
|
+
/*
|
339
|
+
* call-seq:
|
340
|
+
* logon(username, password, dbname) -> connection
|
341
|
+
*
|
342
|
+
* <b>internal use only</b>
|
343
|
+
*
|
344
|
+
* Creates a simple logon session by the OCI function OCILogon().
|
345
|
+
*/
|
346
|
+
static VALUE oci8_logon(VALUE self, VALUE username, VALUE password, VALUE dbname)
|
347
|
+
{
|
348
|
+
oci8_svcctx_t *svcctx = DATA_PTR(self);
|
349
|
+
|
350
|
+
if (svcctx->logoff_strategy != NULL) {
|
351
|
+
rb_raise(rb_eRuntimeError, "Could not reuse the session.");
|
352
|
+
}
|
353
|
+
|
354
|
+
/* check arugmnets */
|
355
|
+
OCI8SafeStringValue(username);
|
356
|
+
OCI8SafeStringValue(password);
|
357
|
+
if (!NIL_P(dbname)) {
|
358
|
+
OCI8SafeStringValue(dbname);
|
359
|
+
}
|
360
|
+
|
361
|
+
/* logon */
|
362
|
+
svcctx->base.type = OCI_HTYPE_SVCCTX;
|
363
|
+
chker2(OCILogon_nb(svcctx, oci8_envhp, oci8_errhp, &svcctx->base.hp.svc,
|
364
|
+
RSTRING_ORATEXT(username), RSTRING_LEN(username),
|
365
|
+
RSTRING_ORATEXT(password), RSTRING_LEN(password),
|
366
|
+
NIL_P(dbname) ? NULL : RSTRING_ORATEXT(dbname),
|
367
|
+
NIL_P(dbname) ? 0 : RSTRING_LEN(dbname)),
|
368
|
+
&svcctx->base);
|
369
|
+
svcctx->logoff_strategy = &simple_logoff;
|
370
|
+
|
371
|
+
/* setup the session handle */
|
372
|
+
chker2(OCIAttrGet(svcctx->base.hp.ptr, OCI_HTYPE_SVCCTX, &svcctx->usrhp, 0, OCI_ATTR_SESSION, oci8_errhp),
|
373
|
+
&svcctx->base);
|
374
|
+
copy_session_handle(svcctx);
|
375
|
+
|
376
|
+
/* setup the server handle */
|
377
|
+
chker2(OCIAttrGet(svcctx->base.hp.ptr, OCI_HTYPE_SVCCTX, &svcctx->srvhp, 0, OCI_ATTR_SERVER, oci8_errhp),
|
378
|
+
&svcctx->base);
|
379
|
+
copy_server_handle(svcctx);
|
380
|
+
|
381
|
+
return Qnil;
|
382
|
+
}
|
383
|
+
|
384
|
+
/*
|
385
|
+
* call-seq:
|
386
|
+
* allocate_handles()
|
387
|
+
*
|
388
|
+
* <b>internal use only</b>
|
389
|
+
*
|
390
|
+
* Allocates a service context handle, a session handle and a
|
391
|
+
* server handle to use explicit attach and begin-session calls.
|
392
|
+
*/
|
393
|
+
static VALUE oci8_allocate_handles(VALUE self)
|
394
|
+
{
|
395
|
+
oci8_svcctx_t *svcctx = DATA_PTR(self);
|
396
|
+
sword rv;
|
397
|
+
|
398
|
+
if (svcctx->logoff_strategy != NULL) {
|
399
|
+
rb_raise(rb_eRuntimeError, "Could not reuse the session.");
|
400
|
+
}
|
401
|
+
svcctx->logoff_strategy = &complex_logoff;
|
402
|
+
svcctx->state = 0;
|
403
|
+
|
404
|
+
/* allocate a service context handle */
|
405
|
+
rv = OCIHandleAlloc(oci8_envhp, &svcctx->base.hp.ptr, OCI_HTYPE_SVCCTX, 0, 0);
|
406
|
+
if (rv != OCI_SUCCESS)
|
407
|
+
oci8_env_raise(oci8_envhp, rv);
|
408
|
+
svcctx->base.type = OCI_HTYPE_SVCCTX;
|
409
|
+
|
410
|
+
/* alocalte a session handle */
|
411
|
+
rv = OCIHandleAlloc(oci8_envhp, (void*)&svcctx->usrhp, OCI_HTYPE_SESSION, 0, 0);
|
412
|
+
if (rv != OCI_SUCCESS)
|
413
|
+
oci8_env_raise(oci8_envhp, rv);
|
414
|
+
copy_session_handle(svcctx);
|
415
|
+
|
416
|
+
/* alocalte a server handle */
|
417
|
+
rv = OCIHandleAlloc(oci8_envhp, (void*)&svcctx->srvhp, OCI_HTYPE_SERVER, 0, 0);
|
418
|
+
if (rv != OCI_SUCCESS)
|
419
|
+
oci8_env_raise(oci8_envhp, rv);
|
420
|
+
copy_server_handle(svcctx);
|
421
|
+
return self;
|
422
|
+
}
|
423
|
+
|
424
|
+
/*
|
425
|
+
* call-seq:
|
426
|
+
* session_handle -> a session handle
|
427
|
+
*
|
428
|
+
* <b>internal use only</b>
|
429
|
+
*
|
430
|
+
* Returns a session handle associated with the service context handle.
|
431
|
+
*/
|
432
|
+
static VALUE oci8_get_session_handle(VALUE self)
|
433
|
+
{
|
434
|
+
return rb_ivar_get(self, id_at_session_handle);
|
435
|
+
}
|
436
|
+
|
437
|
+
/*
|
438
|
+
* call-seq:
|
439
|
+
* server_handle -> a server handle
|
440
|
+
*
|
441
|
+
* <b>internal use only</b>
|
442
|
+
*
|
443
|
+
* Returns a server handle associated with the service context handle.
|
444
|
+
*/
|
445
|
+
static VALUE oci8_get_server_handle(VALUE self)
|
446
|
+
{
|
447
|
+
return rb_ivar_get(self, id_at_server_handle);
|
448
|
+
}
|
449
|
+
|
450
|
+
/*
|
451
|
+
* call-seq:
|
452
|
+
* server_attach(dbname, mode)
|
453
|
+
*
|
454
|
+
* <b>internal use only</b>
|
455
|
+
*
|
456
|
+
* Attachs to the server by the OCI function OCIServerAttach().
|
457
|
+
*/
|
458
|
+
static VALUE oci8_server_attach(VALUE self, VALUE dbname, VALUE mode)
|
459
|
+
{
|
460
|
+
oci8_svcctx_t *svcctx = oci8_get_svcctx(self);
|
461
|
+
|
462
|
+
if (svcctx->logoff_strategy != &complex_logoff) {
|
463
|
+
rb_raise(rb_eRuntimeError, "Use this method only for the service context handle created by OCI8#server_handle().");
|
464
|
+
}
|
465
|
+
if (svcctx->state & OCI8_STATE_SERVER_ATTACH_WAS_CALLED) {
|
466
|
+
rb_raise(rb_eRuntimeError, "Could not use this method twice.");
|
467
|
+
}
|
468
|
+
|
469
|
+
/* check arguments */
|
470
|
+
if (!NIL_P(dbname)) {
|
471
|
+
OCI8SafeStringValue(dbname);
|
472
|
+
}
|
473
|
+
Check_Type(mode, T_FIXNUM);
|
474
|
+
|
475
|
+
/* attach to the server */
|
476
|
+
chker2(OCIServerAttach_nb(svcctx, svcctx->srvhp, oci8_errhp,
|
477
|
+
NIL_P(dbname) ? NULL : RSTRING_ORATEXT(dbname),
|
478
|
+
NIL_P(dbname) ? 0 : RSTRING_LEN(dbname),
|
479
|
+
FIX2UINT(mode)),
|
480
|
+
&svcctx->base);
|
481
|
+
chker2(OCIAttrSet(svcctx->base.hp.ptr, OCI_HTYPE_SVCCTX,
|
482
|
+
svcctx->srvhp, 0, OCI_ATTR_SERVER,
|
483
|
+
oci8_errhp),
|
484
|
+
&svcctx->base);
|
485
|
+
svcctx->state |= OCI8_STATE_SERVER_ATTACH_WAS_CALLED;
|
486
|
+
return self;
|
487
|
+
}
|
488
|
+
|
489
|
+
/*
|
490
|
+
* call-seq:
|
491
|
+
* session_begin(cred, mode)
|
492
|
+
*
|
493
|
+
* <b>internal use only</b>
|
494
|
+
*
|
495
|
+
* Begins the session by the OCI function OCISessionBegin().
|
496
|
+
*/
|
497
|
+
static VALUE oci8_session_begin(VALUE self, VALUE cred, VALUE mode)
|
498
|
+
{
|
499
|
+
oci8_svcctx_t *svcctx = DATA_PTR(self);
|
500
|
+
|
501
|
+
if (svcctx->logoff_strategy != &complex_logoff) {
|
502
|
+
rb_raise(rb_eRuntimeError, "Use this method only for the service context handle created by OCI8#server_handle().");
|
503
|
+
}
|
504
|
+
if (svcctx->state & OCI8_STATE_SESSION_BEGIN_WAS_CALLED) {
|
505
|
+
rb_raise(rb_eRuntimeError, "Could not use this method twice.");
|
506
|
+
}
|
507
|
+
|
508
|
+
/* check arguments */
|
509
|
+
Check_Type(cred, T_FIXNUM);
|
510
|
+
Check_Type(mode, T_FIXNUM);
|
511
|
+
|
512
|
+
/* begin session */
|
513
|
+
chker2(OCISessionBegin_nb(svcctx, svcctx->base.hp.ptr, oci8_errhp,
|
514
|
+
svcctx->usrhp, FIX2UINT(cred),
|
515
|
+
FIX2UINT(mode)),
|
516
|
+
&svcctx->base);
|
517
|
+
chker2(OCIAttrSet(svcctx->base.hp.ptr, OCI_HTYPE_SVCCTX,
|
518
|
+
svcctx->usrhp, 0, OCI_ATTR_SESSION,
|
519
|
+
oci8_errhp),
|
520
|
+
&svcctx->base);
|
521
|
+
svcctx->state |= OCI8_STATE_SESSION_BEGIN_WAS_CALLED;
|
522
|
+
return Qnil;
|
523
|
+
}
|
524
|
+
|
525
|
+
/*
|
526
|
+
* call-seq:
|
527
|
+
* logoff
|
528
|
+
*
|
529
|
+
* Disconnects from the Oracle server. The uncommitted transaction is
|
530
|
+
* rollbacked.
|
531
|
+
*/
|
532
|
+
static VALUE oci8_svcctx_logoff(VALUE self)
|
533
|
+
{
|
534
|
+
oci8_svcctx_t *svcctx = (oci8_svcctx_t *)DATA_PTR(self);
|
535
|
+
|
536
|
+
while (svcctx->base.children != NULL) {
|
537
|
+
oci8_base_free(svcctx->base.children);
|
538
|
+
}
|
539
|
+
if (svcctx->logoff_strategy != NULL) {
|
540
|
+
const oci8_logoff_strategy_t *strategy = svcctx->logoff_strategy;
|
541
|
+
void *data = strategy->prepare(svcctx);
|
542
|
+
svcctx->base.type = 0;
|
543
|
+
svcctx->logoff_strategy = NULL;
|
544
|
+
chker2(oci8_blocking_region(svcctx, strategy->execute, data), &svcctx->base);
|
545
|
+
}
|
546
|
+
return Qtrue;
|
547
|
+
}
|
548
|
+
|
549
|
+
/*
|
550
|
+
* call-seq:
|
551
|
+
* commit
|
552
|
+
*
|
553
|
+
* Commits the transaction.
|
554
|
+
*/
|
555
|
+
static VALUE oci8_commit(VALUE self)
|
556
|
+
{
|
557
|
+
oci8_svcctx_t *svcctx = DATA_PTR(self);
|
558
|
+
chker2(OCITransCommit_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, OCI_DEFAULT), &svcctx->base);
|
559
|
+
return self;
|
560
|
+
}
|
561
|
+
|
562
|
+
/*
|
563
|
+
* call-seq:
|
564
|
+
* rollback
|
565
|
+
*
|
566
|
+
* Rollbacks the transaction.
|
567
|
+
*/
|
568
|
+
static VALUE oci8_rollback(VALUE self)
|
569
|
+
{
|
570
|
+
oci8_svcctx_t *svcctx = DATA_PTR(self);
|
571
|
+
chker2(OCITransRollback_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, OCI_DEFAULT), &svcctx->base);
|
572
|
+
return self;
|
573
|
+
}
|
574
|
+
|
575
|
+
/*
|
576
|
+
* call-seq:
|
577
|
+
* non_blocking? -> true or false
|
578
|
+
*
|
579
|
+
* Returns +true+ if the connection is in non-blocking mode, +false+
|
580
|
+
* otherwise.
|
581
|
+
*
|
582
|
+
* See also #non_blocking=.
|
583
|
+
*/
|
584
|
+
static VALUE oci8_non_blocking_p(VALUE self)
|
585
|
+
{
|
586
|
+
oci8_svcctx_t *svcctx = DATA_PTR(self);
|
587
|
+
#ifdef HAVE_RB_THREAD_BLOCKING_REGION
|
588
|
+
return svcctx->non_blocking ? Qtrue : Qfalse;
|
589
|
+
#else
|
590
|
+
sb1 non_blocking;
|
591
|
+
|
592
|
+
chker2(OCIAttrGet(svcctx->srvhp, OCI_HTYPE_SERVER, &non_blocking, 0, OCI_ATTR_NONBLOCKING_MODE, oci8_errhp), &svcctx->base);
|
593
|
+
return non_blocking ? Qtrue : Qfalse;
|
594
|
+
#endif
|
595
|
+
}
|
596
|
+
|
597
|
+
/*
|
598
|
+
* call-seq:
|
599
|
+
* non_blocking = true or false
|
600
|
+
*
|
601
|
+
* Sets +true+ to enable non-blocking mode, +false+ otherwise.
|
602
|
+
* The default setting depends on the ruby version and ruby-oci8
|
603
|
+
* version.
|
604
|
+
*
|
605
|
+
* When the connection is in blocking mode (non_blocking = false),
|
606
|
+
* SQL executions block not only the thread, but also the ruby
|
607
|
+
* process. It makes the whole application stop while a SQL execution
|
608
|
+
* needs long time.
|
609
|
+
*
|
610
|
+
* When in non-blocking mode (non_blocking = true), SQL executions
|
611
|
+
* block only the thread. It does't prevent other threads.
|
612
|
+
* A SQL execution which blocks a thread can be canceled by
|
613
|
+
* OCI8#break.
|
614
|
+
*
|
615
|
+
* === ruby 1.9
|
616
|
+
* The default setting is +true+ if the ruby-oci8 version is 2.0.3 or
|
617
|
+
* upper, +false+ otherwise.
|
618
|
+
*
|
619
|
+
* Ruby-oci8 makes the connection non-blocking by releasing ruby
|
620
|
+
* interpreter's GVL (Global VM Lock or Giant VM Lock) while OCI
|
621
|
+
* functions which may need more than one network round trips are in
|
622
|
+
* execution.
|
623
|
+
*
|
624
|
+
* === ruby 1.8
|
625
|
+
* The default setting is +false+.
|
626
|
+
*
|
627
|
+
* Ruby-oci8 makes the connection non-blocking by polling the return
|
628
|
+
* values of OCI functions. When an OCI function returns
|
629
|
+
* OCI_STILL_EXECUTING, the thread sleeps for 10 milli seconds to make
|
630
|
+
* a time for other threads to run. The sleep time is doubled up to
|
631
|
+
* 640 milli seconds as the function returns the same value.
|
632
|
+
*
|
633
|
+
*/
|
634
|
+
static VALUE oci8_set_non_blocking(VALUE self, VALUE val)
|
635
|
+
{
|
636
|
+
oci8_svcctx_t *svcctx = DATA_PTR(self);
|
637
|
+
#ifdef HAVE_RB_THREAD_BLOCKING_REGION
|
638
|
+
svcctx->non_blocking = RTEST(val);
|
639
|
+
#else
|
640
|
+
sb1 non_blocking;
|
641
|
+
|
642
|
+
chker2(OCIAttrGet(svcctx->srvhp, OCI_HTYPE_SERVER, &non_blocking, 0, OCI_ATTR_NONBLOCKING_MODE, oci8_errhp), &svcctx->base);
|
643
|
+
if ((RTEST(val) && !non_blocking) || (!RTEST(val) && non_blocking)) {
|
644
|
+
/* toggle blocking / non-blocking. */
|
645
|
+
chker2(OCIAttrSet(svcctx->srvhp, OCI_HTYPE_SERVER, 0, 0, OCI_ATTR_NONBLOCKING_MODE, oci8_errhp), &svcctx->base);
|
646
|
+
}
|
647
|
+
#endif
|
648
|
+
return val;
|
649
|
+
}
|
650
|
+
|
651
|
+
/*
|
652
|
+
* call-seq:
|
653
|
+
* autocommit? -> true or false
|
654
|
+
*
|
655
|
+
* Returns +true+ if the connection is in autocommit mode, +false+
|
656
|
+
* otherwise. The default value is +false+.
|
657
|
+
*/
|
658
|
+
static VALUE oci8_autocommit_p(VALUE self)
|
659
|
+
{
|
660
|
+
oci8_svcctx_t *svcctx = DATA_PTR(self);
|
661
|
+
return svcctx->is_autocommit ? Qtrue : Qfalse;
|
662
|
+
}
|
663
|
+
|
664
|
+
/*
|
665
|
+
* call-seq:
|
666
|
+
* autocommit = true or false
|
667
|
+
*
|
668
|
+
* Sets the autocommit mode. The default value is +false+.
|
669
|
+
*/
|
670
|
+
static VALUE oci8_set_autocommit(VALUE self, VALUE val)
|
671
|
+
{
|
672
|
+
oci8_svcctx_t *svcctx = DATA_PTR(self);
|
673
|
+
svcctx->is_autocommit = RTEST(val);
|
674
|
+
return val;
|
675
|
+
}
|
676
|
+
|
677
|
+
/*
|
678
|
+
* call-seq:
|
679
|
+
* long_read_len -> fixnum
|
680
|
+
*
|
681
|
+
* Gets the maximum length in bytes to fetch a LONG or LONG RAW
|
682
|
+
* column. The default value is 65535.
|
683
|
+
*
|
684
|
+
* If the actual data length is longer than long_read_len,
|
685
|
+
* "ORA-01406: fetched column value was truncated" is raised.
|
686
|
+
*
|
687
|
+
* Note: long_read_len is also used for XMLTYPE data type in 2.0.
|
688
|
+
*/
|
689
|
+
static VALUE oci8_long_read_len(VALUE self)
|
690
|
+
{
|
691
|
+
oci8_svcctx_t *svcctx = DATA_PTR(self);
|
692
|
+
return svcctx->long_read_len;
|
693
|
+
}
|
694
|
+
|
695
|
+
/*
|
696
|
+
* call-seq:
|
697
|
+
* long_read_len = fixnum
|
698
|
+
*
|
699
|
+
* Sets the maximum length in bytes to fetch a LONG or LONG RAW
|
700
|
+
* column.
|
701
|
+
*
|
702
|
+
* See also #long_read_len
|
703
|
+
*
|
704
|
+
*/
|
705
|
+
static VALUE oci8_set_long_read_len(VALUE self, VALUE val)
|
706
|
+
{
|
707
|
+
oci8_svcctx_t *svcctx = DATA_PTR(self);
|
708
|
+
Check_Type(val, T_FIXNUM);
|
709
|
+
svcctx->long_read_len = val;
|
710
|
+
return val;
|
711
|
+
}
|
712
|
+
|
713
|
+
/*
|
714
|
+
* call-seq:
|
715
|
+
* break
|
716
|
+
*
|
717
|
+
* Cancels the executing SQL.
|
718
|
+
*
|
719
|
+
* See also #non_blocking=.
|
720
|
+
*/
|
721
|
+
static VALUE oci8_break(VALUE self)
|
722
|
+
{
|
723
|
+
oci8_svcctx_t *svcctx = DATA_PTR(self);
|
724
|
+
|
725
|
+
if (NIL_P(svcctx->executing_thread)) {
|
726
|
+
return Qfalse;
|
727
|
+
}
|
728
|
+
#ifndef HAVE_RB_THREAD_BLOCKING_REGION
|
729
|
+
chker2(OCIBreak(svcctx->base.hp.ptr, oci8_errhp), &svcctx->base);
|
730
|
+
#endif
|
731
|
+
rb_thread_wakeup(svcctx->executing_thread);
|
732
|
+
return Qtrue;
|
733
|
+
}
|
734
|
+
|
735
|
+
/*
|
736
|
+
* call-seq:
|
737
|
+
* prefetch_rows = number
|
738
|
+
*
|
739
|
+
* Sets the prefetch rows size. The default value is one.
|
740
|
+
* When a select statement is executed, the OCI library allocate
|
741
|
+
* prefetch buffer to reduce the number of network round trips by
|
742
|
+
* retrieving specified number of rows in one round trip.
|
743
|
+
*
|
744
|
+
* Note: Active record adaptors set 100 by default.
|
745
|
+
*/
|
746
|
+
static VALUE oci8_set_prefetch_rows(VALUE self, VALUE val)
|
747
|
+
{
|
748
|
+
rb_ivar_set(self, id_at_prefetch_rows, val);
|
749
|
+
return val;
|
750
|
+
}
|
751
|
+
|
752
|
+
/*
|
753
|
+
* call-seq:
|
754
|
+
* oracle_server_vernum -> an integer
|
755
|
+
*
|
756
|
+
* <b>(new in 2.0.1)</b>
|
757
|
+
*
|
758
|
+
* Returns a numerical format of the Oracle server version.
|
759
|
+
*
|
760
|
+
* See also: #oracle_server_version
|
761
|
+
*/
|
762
|
+
static VALUE oci8_oracle_server_vernum(VALUE self)
|
763
|
+
{
|
764
|
+
oci8_svcctx_t *svcctx = DATA_PTR(self);
|
765
|
+
char buf[100];
|
766
|
+
ub4 version;
|
767
|
+
|
768
|
+
chker2(OCIServerRelease(svcctx->base.hp.ptr, oci8_errhp, (text*)buf, sizeof(buf), (ub1)svcctx->base.type, &version), &svcctx->base);
|
769
|
+
return UINT2NUM(version);
|
770
|
+
}
|
771
|
+
|
772
|
+
/*
|
773
|
+
* call-seq:
|
774
|
+
* ping -> true or false
|
775
|
+
*
|
776
|
+
* <b>(new in 2.0.2)</b>
|
777
|
+
*
|
778
|
+
* Makes a round trip call to the server to confirm that the connection and
|
779
|
+
* the server are active.
|
780
|
+
*
|
781
|
+
* OCI8#ping also can be used to flush all the pending OCI client-side calls
|
782
|
+
* to the server if any exist.
|
783
|
+
*
|
784
|
+
* === Oracle 10.2 client or upper
|
785
|
+
* A dummy round trip call is made by a newly added OCI function
|
786
|
+
* OCIPing[http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14250/oci16msc007.htm#sthref3540] in Oracle 10.2.
|
787
|
+
*
|
788
|
+
* === Oracle 10.1 client or lower
|
789
|
+
* A simple PL/SQL block "BEGIN NULL; END;" is executed to make a round trip call.
|
790
|
+
*/
|
791
|
+
static VALUE oci8_ping(VALUE self)
|
792
|
+
{
|
793
|
+
oci8_svcctx_t *svcctx = oci8_get_svcctx(self);
|
794
|
+
sword rv;
|
795
|
+
|
796
|
+
if (have_OCIPing_nb) {
|
797
|
+
/* Oracle 10.2 or upper */
|
798
|
+
rv = OCIPing_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, OCI_DEFAULT);
|
799
|
+
} else {
|
800
|
+
/* Oracle 10.1 or lower */
|
801
|
+
rv = oci8_exec_sql(svcctx, "BEGIN NULL; END;", 0U, NULL, 0U, NULL, 0);
|
802
|
+
}
|
803
|
+
return rv == OCI_SUCCESS ? Qtrue : FALSE;
|
804
|
+
}
|
805
|
+
|
806
|
+
/*
|
807
|
+
* call-seq:
|
808
|
+
* client_identifier = string or nil
|
809
|
+
*
|
810
|
+
* <b>(new in 2.0.3)</b>
|
811
|
+
*
|
812
|
+
* Sets the client ID. This information is stored in the V$SESSION
|
813
|
+
* view.
|
814
|
+
*
|
815
|
+
* === Oracle 9i client or upper
|
816
|
+
*
|
817
|
+
* This doesn't perform network round trips. The change is reflected
|
818
|
+
* to the server by the next round trip such as OCI8#exec, OCI8#ping,
|
819
|
+
* etc.
|
820
|
+
*
|
821
|
+
* === Oracle 8i client or lower
|
822
|
+
*
|
823
|
+
* This executes the following PL/SQL block internally.
|
824
|
+
* The change is reflected immediately by a network round trip.
|
825
|
+
*
|
826
|
+
* BEGIN
|
827
|
+
* DBMS_SESSION.SET_IDENTIFIER(:client_id);
|
828
|
+
* END;
|
829
|
+
*
|
830
|
+
* See {Oracle Manual: Oracle Database PL/SQL Packages and Types Reference}[http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14258/d_sessio.htm#i996935]
|
831
|
+
*
|
832
|
+
*/
|
833
|
+
static VALUE oci8_set_client_identifier(VALUE self, VALUE val)
|
834
|
+
{
|
835
|
+
char *ptr;
|
836
|
+
ub4 size;
|
837
|
+
|
838
|
+
if (!NIL_P(val)) {
|
839
|
+
OCI8SafeStringValue(val);
|
840
|
+
ptr = RSTRING_PTR(val);
|
841
|
+
size = RSTRING_LEN(val);
|
842
|
+
} else {
|
843
|
+
ptr = "";
|
844
|
+
size = 0;
|
845
|
+
}
|
846
|
+
|
847
|
+
if (oracle_client_version >= ORAVERNUM(9, 2, 0, 3, 0) || size > 0) {
|
848
|
+
if (size > 0 && ptr[0] == ':') {
|
849
|
+
rb_raise(rb_eArgError, "client identifier should not start with ':'.");
|
850
|
+
}
|
851
|
+
chker2(OCIAttrSet(oci8_get_oci_session(self), OCI_HTYPE_SESSION, ptr,
|
852
|
+
size, OCI_ATTR_CLIENT_IDENTIFIER, oci8_errhp),
|
853
|
+
DATA_PTR(self));
|
854
|
+
} else {
|
855
|
+
/* Workaround for Bug 2449486 */
|
856
|
+
oci8_exec_sql_var_t bind_vars[1];
|
857
|
+
|
858
|
+
/* :client_id */
|
859
|
+
bind_vars[0].valuep = ptr;
|
860
|
+
bind_vars[0].value_sz = size;
|
861
|
+
bind_vars[0].dty = SQLT_CHR;
|
862
|
+
bind_vars[0].indp = NULL;
|
863
|
+
bind_vars[0].alenp = NULL;
|
864
|
+
|
865
|
+
oci8_exec_sql(oci8_get_svcctx(self),
|
866
|
+
"BEGIN\n"
|
867
|
+
" DBMS_SESSION.SET_IDENTIFIER(:client_id);\n"
|
868
|
+
"END;\n", 0, NULL, 1, bind_vars, 1);
|
869
|
+
}
|
870
|
+
return val;
|
871
|
+
}
|
872
|
+
|
873
|
+
/*
|
874
|
+
* call-seq:
|
875
|
+
* module = string or nil
|
876
|
+
*
|
877
|
+
* <b>(new in 2.0.3)</b>
|
878
|
+
*
|
879
|
+
* Sets the name of the current module. This information is
|
880
|
+
* stored in the V$SESSION view and is also stored in the V$SQL view
|
881
|
+
* and the V$SQLAREA view when a SQL statement is executed and the SQL
|
882
|
+
* statement is first parsed in the Oracle server.
|
883
|
+
*
|
884
|
+
* === Oracle 10g client or upper
|
885
|
+
*
|
886
|
+
* This doesn't perform network round trips. The change is reflected
|
887
|
+
* to the server by the next round trip such as OCI8#exec, OCI8#ping,
|
888
|
+
* etc.
|
889
|
+
*
|
890
|
+
* === Oracle 9i client or lower
|
891
|
+
*
|
892
|
+
* This executes the following PL/SQL block internally.
|
893
|
+
* The change is reflected immediately by a network round trip.
|
894
|
+
*
|
895
|
+
* DECLARE
|
896
|
+
* action VARCHAR2(32);
|
897
|
+
* BEGIN
|
898
|
+
* -- retrieve action name.
|
899
|
+
* SELECT SYS_CONTEXT('USERENV','ACTION') INTO action FROM DUAL;
|
900
|
+
* -- change module name without modifying the action name.
|
901
|
+
* DBMS_APPLICATION_INFO.SET_MODULE(:module, action);
|
902
|
+
* END;
|
903
|
+
*
|
904
|
+
* See {Oracle Manual: Oracle Database PL/SQL Packages and Types Reference}[http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14258/d_appinf.htm#i999254]
|
905
|
+
*
|
906
|
+
*/
|
907
|
+
static VALUE oci8_set_module(VALUE self, VALUE val)
|
908
|
+
{
|
909
|
+
char *ptr;
|
910
|
+
ub4 size;
|
911
|
+
|
912
|
+
if (!NIL_P(val)) {
|
913
|
+
OCI8SafeStringValue(val);
|
914
|
+
ptr = RSTRING_PTR(val);
|
915
|
+
size = RSTRING_LEN(val);
|
916
|
+
} else {
|
917
|
+
ptr = "";
|
918
|
+
size = 0;
|
919
|
+
}
|
920
|
+
if (oracle_client_version >= ORAVER_10_1) {
|
921
|
+
/* Oracle 10g or upper */
|
922
|
+
chker2(OCIAttrSet(oci8_get_oci_session(self), OCI_HTYPE_SESSION, ptr,
|
923
|
+
size, OCI_ATTR_MODULE, oci8_errhp),
|
924
|
+
DATA_PTR(self));
|
925
|
+
} else {
|
926
|
+
/* Oracle 9i or lower */
|
927
|
+
oci8_exec_sql_var_t bind_vars[1];
|
928
|
+
|
929
|
+
/* :module */
|
930
|
+
bind_vars[0].valuep = ptr;
|
931
|
+
bind_vars[0].value_sz = size;
|
932
|
+
bind_vars[0].dty = SQLT_CHR;
|
933
|
+
bind_vars[0].indp = NULL;
|
934
|
+
bind_vars[0].alenp = NULL;
|
935
|
+
|
936
|
+
oci8_exec_sql(oci8_get_svcctx(self),
|
937
|
+
"DECLARE\n"
|
938
|
+
" action VARCHAR2(32);\n"
|
939
|
+
"BEGIN\n"
|
940
|
+
" SELECT SYS_CONTEXT('USERENV','ACTION') INTO action FROM DUAL;\n"
|
941
|
+
" DBMS_APPLICATION_INFO.SET_MODULE(:module, action);\n"
|
942
|
+
"END;\n", 0, NULL, 1, bind_vars, 1);
|
943
|
+
}
|
944
|
+
return self;
|
945
|
+
}
|
946
|
+
|
947
|
+
/*
|
948
|
+
* call-seq:
|
949
|
+
* action = string or nil
|
950
|
+
*
|
951
|
+
* <b>(new in 2.0.3)</b>
|
952
|
+
*
|
953
|
+
* Sets the name of the current action within the current module.
|
954
|
+
* This information is stored in the V$SESSION view and is also
|
955
|
+
* stored in the V$SQL view and the V$SQLAREA view when a SQL
|
956
|
+
* statement is executed and the SQL statement is first parsed
|
957
|
+
* in the Oracle server.
|
958
|
+
*
|
959
|
+
* === Oracle 10g client or upper
|
960
|
+
*
|
961
|
+
* This doesn't perform network round trips. The change is reflected
|
962
|
+
* to the server by the next round trip such as OCI8#exec, OCI8#ping,
|
963
|
+
* etc.
|
964
|
+
*
|
965
|
+
* === Oracle 9i client or lower
|
966
|
+
*
|
967
|
+
* This executes the following PL/SQL block internally.
|
968
|
+
* The change is reflected immediately by a network round trip.
|
969
|
+
*
|
970
|
+
* BEGIN
|
971
|
+
* DBMS_APPLICATION_INFO.SET_ACTION(:action);
|
972
|
+
* END;
|
973
|
+
*
|
974
|
+
* See {Oracle Manual: Oracle Database PL/SQL Packages and Types Reference}[http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14258/d_appinf.htm#i999254]
|
975
|
+
*
|
976
|
+
*/
|
977
|
+
static VALUE oci8_set_action(VALUE self, VALUE val)
|
978
|
+
{
|
979
|
+
char *ptr;
|
980
|
+
ub4 size;
|
981
|
+
|
982
|
+
if (!NIL_P(val)) {
|
983
|
+
OCI8SafeStringValue(val);
|
984
|
+
ptr = RSTRING_PTR(val);
|
985
|
+
size = RSTRING_LEN(val);
|
986
|
+
} else {
|
987
|
+
ptr = "";
|
988
|
+
size = 0;
|
989
|
+
}
|
990
|
+
if (oracle_client_version >= ORAVER_10_1) {
|
991
|
+
/* Oracle 10g or upper */
|
992
|
+
chker2(OCIAttrSet(oci8_get_oci_session(self), OCI_HTYPE_SESSION, ptr,
|
993
|
+
size, OCI_ATTR_ACTION, oci8_errhp),
|
994
|
+
DATA_PTR(self));
|
995
|
+
} else {
|
996
|
+
/* Oracle 9i or lower */
|
997
|
+
oci8_exec_sql_var_t bind_vars[1];
|
998
|
+
|
999
|
+
/* :action */
|
1000
|
+
bind_vars[0].valuep = ptr;
|
1001
|
+
bind_vars[0].value_sz = size;
|
1002
|
+
bind_vars[0].dty = SQLT_CHR;
|
1003
|
+
bind_vars[0].indp = NULL;
|
1004
|
+
bind_vars[0].alenp = NULL;
|
1005
|
+
|
1006
|
+
oci8_exec_sql(oci8_get_svcctx(self),
|
1007
|
+
"BEGIN\n"
|
1008
|
+
" DBMS_APPLICATION_INFO.SET_ACTION(:action);\n"
|
1009
|
+
"END;\n", 0, NULL, 1, bind_vars, 1);
|
1010
|
+
}
|
1011
|
+
return val;
|
1012
|
+
}
|
1013
|
+
|
1014
|
+
/*
|
1015
|
+
* call-seq:
|
1016
|
+
* client_info = string or nil
|
1017
|
+
*
|
1018
|
+
* <b>(new in 2.0.3)</b>
|
1019
|
+
*
|
1020
|
+
* Sets additional information about the client application.
|
1021
|
+
* This information is stored in the V$SESSION view.
|
1022
|
+
*
|
1023
|
+
* === Oracle 10g client or upper
|
1024
|
+
*
|
1025
|
+
* This doesn't perform network round trips. The change is reflected
|
1026
|
+
* to the server by the next round trip such as OCI8#exec, OCI8#ping,
|
1027
|
+
* etc.
|
1028
|
+
*
|
1029
|
+
* === Oracle 9i client or lower
|
1030
|
+
*
|
1031
|
+
* This executes the following PL/SQL block internally.
|
1032
|
+
* The change is reflected immediately by a network round trip.
|
1033
|
+
*
|
1034
|
+
* BEGIN
|
1035
|
+
* DBMS_APPLICATION_INFO.SET_CLIENT_INFO(:client_info);
|
1036
|
+
* END;
|
1037
|
+
*
|
1038
|
+
* See {Oracle Manual: Oracle Database PL/SQL Packages and Types Reference}[http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14258/d_appinf.htm#CHEJCFGG]
|
1039
|
+
*/
|
1040
|
+
static VALUE oci8_set_client_info(VALUE self, VALUE val)
|
1041
|
+
{
|
1042
|
+
char *ptr;
|
1043
|
+
ub4 size;
|
1044
|
+
|
1045
|
+
if (!NIL_P(val)) {
|
1046
|
+
OCI8SafeStringValue(val);
|
1047
|
+
ptr = RSTRING_PTR(val);
|
1048
|
+
size = RSTRING_LEN(val);
|
1049
|
+
} else {
|
1050
|
+
ptr = "";
|
1051
|
+
size = 0;
|
1052
|
+
}
|
1053
|
+
if (oracle_client_version >= ORAVER_10_1) {
|
1054
|
+
/* Oracle 10g or upper */
|
1055
|
+
chker2(OCIAttrSet(oci8_get_oci_session(self), OCI_HTYPE_SESSION, ptr,
|
1056
|
+
size, OCI_ATTR_CLIENT_INFO, oci8_errhp),
|
1057
|
+
DATA_PTR(self));
|
1058
|
+
} else {
|
1059
|
+
/* Oracle 9i or lower */
|
1060
|
+
oci8_exec_sql_var_t bind_vars[1];
|
1061
|
+
|
1062
|
+
/* :client_info */
|
1063
|
+
bind_vars[0].valuep = ptr;
|
1064
|
+
bind_vars[0].value_sz = size;
|
1065
|
+
bind_vars[0].dty = SQLT_CHR;
|
1066
|
+
bind_vars[0].indp = NULL;
|
1067
|
+
bind_vars[0].alenp = NULL;
|
1068
|
+
|
1069
|
+
oci8_exec_sql(oci8_get_svcctx(self),
|
1070
|
+
"BEGIN\n"
|
1071
|
+
" DBMS_APPLICATION_INFO.SET_CLIENT_INFO(:client_info);\n"
|
1072
|
+
"END;\n", 0, NULL, 1, bind_vars, 1);
|
1073
|
+
}
|
1074
|
+
return val;
|
1075
|
+
}
|
1076
|
+
|
1077
|
+
VALUE Init_oci8(void)
|
1078
|
+
{
|
1079
|
+
#if 0
|
1080
|
+
oci8_cOCIHandle = rb_define_class("OCIHandle", rb_cObject);
|
1081
|
+
cOCI8 = rb_define_class("OCI8", oci8_cOCIHandle);
|
1082
|
+
#endif
|
1083
|
+
cOCI8 = oci8_define_class("OCI8", &oci8_svcctx_vtable);
|
1084
|
+
cSession = oci8_define_class_under(cOCI8, "Session", &oci8_svcctx_associate_vtable);
|
1085
|
+
cServer = oci8_define_class_under(cOCI8, "Server", &oci8_svcctx_associate_vtable);
|
1086
|
+
id_at_session_handle = rb_intern("@session_handle");
|
1087
|
+
id_at_server_handle = rb_intern("@server_handle");
|
1088
|
+
|
1089
|
+
oracle_client_vernum = INT2FIX(oracle_client_version);
|
1090
|
+
if (have_OCIClientVersion) {
|
1091
|
+
sword major, minor, update, patch, port_update;
|
1092
|
+
OCIClientVersion(&major, &minor, &update, &patch, &port_update);
|
1093
|
+
oracle_client_vernum = INT2FIX(ORAVERNUM(major, minor, update, patch, port_update));
|
1094
|
+
}
|
1095
|
+
|
1096
|
+
sym_SYSDBA = ID2SYM(rb_intern("SYSDBA"));
|
1097
|
+
sym_SYSOPER = ID2SYM(rb_intern("SYSOPER"));
|
1098
|
+
id_at_prefetch_rows = rb_intern("@prefetch_rows");
|
1099
|
+
id_set_prefetch_rows = rb_intern("prefetch_rows=");
|
1100
|
+
|
1101
|
+
rb_define_const(cOCI8, "VERSION", rb_obj_freeze(rb_usascii_str_new_cstr(OCI8LIB_VERSION)));
|
1102
|
+
rb_define_singleton_method_nodoc(cOCI8, "oracle_client_vernum", oci8_s_oracle_client_vernum, 0);
|
1103
|
+
rb_define_singleton_method_nodoc(cOCI8, "__set_property", oci8_s_set_property, 2);
|
1104
|
+
rb_define_singleton_method(cOCI8, "error_message", oci8_s_error_message, 1);
|
1105
|
+
rb_define_private_method(cOCI8, "parse_connect_string", oci8_parse_connect_string, 1);
|
1106
|
+
rb_define_private_method(cOCI8, "logon", oci8_logon, 3);
|
1107
|
+
rb_define_private_method(cOCI8, "allocate_handles", oci8_allocate_handles, 0);
|
1108
|
+
rb_define_private_method(cOCI8, "session_handle", oci8_get_session_handle, 0);
|
1109
|
+
rb_define_private_method(cOCI8, "server_handle", oci8_get_server_handle, 0);
|
1110
|
+
rb_define_private_method(cOCI8, "server_attach", oci8_server_attach, 2);
|
1111
|
+
rb_define_private_method(cOCI8, "session_begin", oci8_session_begin, 2);
|
1112
|
+
rb_define_method(cOCI8, "logoff", oci8_svcctx_logoff, 0);
|
1113
|
+
rb_define_method(cOCI8, "commit", oci8_commit, 0);
|
1114
|
+
rb_define_method(cOCI8, "rollback", oci8_rollback, 0);
|
1115
|
+
rb_define_method(cOCI8, "non_blocking?", oci8_non_blocking_p, 0);
|
1116
|
+
rb_define_method(cOCI8, "non_blocking=", oci8_set_non_blocking, 1);
|
1117
|
+
rb_define_method(cOCI8, "autocommit?", oci8_autocommit_p, 0);
|
1118
|
+
rb_define_method(cOCI8, "autocommit=", oci8_set_autocommit, 1);
|
1119
|
+
rb_define_method(cOCI8, "long_read_len", oci8_long_read_len, 0);
|
1120
|
+
rb_define_method(cOCI8, "long_read_len=", oci8_set_long_read_len, 1);
|
1121
|
+
rb_define_method(cOCI8, "break", oci8_break, 0);
|
1122
|
+
rb_define_method(cOCI8, "prefetch_rows=", oci8_set_prefetch_rows, 1);
|
1123
|
+
rb_define_private_method(cOCI8, "oracle_server_vernum", oci8_oracle_server_vernum, 0);
|
1124
|
+
rb_define_method(cOCI8, "ping", oci8_ping, 0);
|
1125
|
+
rb_define_method(cOCI8, "client_identifier=", oci8_set_client_identifier, 1);
|
1126
|
+
rb_define_method(cOCI8, "module=", oci8_set_module, 1);
|
1127
|
+
rb_define_method(cOCI8, "action=", oci8_set_action, 1);
|
1128
|
+
rb_define_method(cOCI8, "client_info=", oci8_set_client_info, 1);
|
1129
|
+
rb_define_attr(cOCI8, "last_error", 1, 1);
|
1130
|
+
return cOCI8;
|
1131
|
+
}
|
1132
|
+
|
1133
|
+
oci8_svcctx_t *oci8_get_svcctx(VALUE obj)
|
1134
|
+
{
|
1135
|
+
return (oci8_svcctx_t *)oci8_get_handle(obj, cOCI8);
|
1136
|
+
}
|
1137
|
+
|
1138
|
+
OCISvcCtx *oci8_get_oci_svcctx(VALUE obj)
|
1139
|
+
{
|
1140
|
+
oci8_svcctx_t *svcctx = oci8_get_svcctx(obj);
|
1141
|
+
return svcctx->base.hp.svc;
|
1142
|
+
}
|
1143
|
+
|
1144
|
+
OCISession *oci8_get_oci_session(VALUE obj)
|
1145
|
+
{
|
1146
|
+
oci8_svcctx_t *svcctx = oci8_get_svcctx(obj);
|
1147
|
+
return svcctx->usrhp;
|
1148
|
+
}
|
1149
|
+
|
1150
|
+
void oci8_check_pid_consistency(oci8_svcctx_t *svcctx)
|
1151
|
+
{
|
1152
|
+
if (svcctx->pid != getpid()) {
|
1153
|
+
rb_raise(rb_eRuntimeError, "The connection cannot be reused in the forked process.");
|
1154
|
+
}
|
1155
|
+
}
|
1156
|
+
|