ruby-oci8 1.0.7 → 2.0.0
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 +1254 -390
- data/Makefile +10 -13
- data/README +56 -385
- data/VERSION +1 -1
- data/dist-files +26 -27
- data/ext/oci8/.document +1 -0
- data/ext/oci8/MANIFEST +0 -4
- data/ext/oci8/apiwrap.c.tmpl +172 -0
- data/ext/oci8/apiwrap.h.tmpl +61 -0
- data/ext/oci8/apiwrap.rb +91 -0
- data/ext/oci8/apiwrap.yml +1243 -0
- data/ext/oci8/attr.c +124 -384
- data/ext/oci8/bind.c +472 -164
- data/ext/oci8/encoding.c +196 -0
- data/ext/oci8/env.c +84 -253
- data/ext/oci8/error.c +196 -127
- data/ext/oci8/extconf.rb +82 -59
- data/ext/oci8/lob.c +710 -370
- data/ext/oci8/metadata.c +359 -0
- data/ext/oci8/object.c +622 -0
- data/ext/oci8/oci8.c +577 -161
- data/ext/oci8/oci8.h +354 -258
- data/ext/oci8/oci8lib.c +493 -0
- data/ext/oci8/ocidatetime.c +473 -0
- data/ext/oci8/ocinumber.c +1123 -24
- data/ext/oci8/oraconf.rb +72 -106
- data/ext/oci8/oradate.c +511 -321
- data/ext/oci8/stmt.c +752 -572
- data/ext/oci8/win32.c +131 -0
- data/ext/oci8/xmldb.c +383 -0
- data/lib/.document +2 -0
- data/lib/dbd/OCI8.rb +2 -17
- data/lib/oci8.rb.in +41 -1622
- data/lib/oci8/.document +5 -0
- data/lib/oci8/compat.rb +108 -0
- data/lib/oci8/datetime.rb +489 -0
- data/lib/oci8/encoding-init.rb +40 -0
- data/lib/oci8/encoding.yml +537 -0
- data/lib/oci8/metadata.rb +2077 -0
- data/lib/oci8/object.rb +548 -0
- data/lib/oci8/oci8.rb +773 -0
- data/lib/oci8/oracle_version.rb +144 -0
- data/metaconfig +3 -3
- data/ruby-oci8.gemspec +5 -5
- data/setup.rb +4 -4
- data/test/config.rb +64 -84
- data/test/test_all.rb +14 -21
- data/test/test_array_dml.rb +317 -0
- data/test/test_bind_raw.rb +18 -25
- data/test/test_bind_time.rb +78 -91
- data/test/test_break.rb +37 -35
- data/test/test_clob.rb +33 -89
- data/test/test_connstr.rb +5 -4
- data/test/test_datetime.rb +469 -0
- data/test/test_dbi.rb +99 -60
- data/test/test_dbi_clob.rb +3 -8
- data/test/test_metadata.rb +65 -51
- data/test/test_oci8.rb +151 -55
- data/test/test_oracle_version.rb +70 -0
- data/test/test_oradate.rb +76 -83
- data/test/test_oranumber.rb +405 -71
- data/test/test_rowid.rb +6 -11
- metadata +31 -32
- data/NEWS +0 -420
- data/ext/oci8/const.c +0 -165
- data/ext/oci8/define.c +0 -53
- data/ext/oci8/describe.c +0 -81
- data/ext/oci8/descriptor.c +0 -39
- data/ext/oci8/handle.c +0 -273
- data/ext/oci8/oranumber.c +0 -445
- data/ext/oci8/param.c +0 -37
- data/ext/oci8/server.c +0 -182
- data/ext/oci8/session.c +0 -99
- data/ext/oci8/svcctx.c +0 -238
- data/ruby-oci8.spec +0 -62
- data/support/README +0 -4
- data/support/runit/assert.rb +0 -281
- data/support/runit/cui/testrunner.rb +0 -101
- data/support/runit/error.rb +0 -4
- data/support/runit/method_mappable.rb +0 -20
- data/support/runit/robserver.rb +0 -25
- data/support/runit/setuppable.rb +0 -15
- data/support/runit/teardownable.rb +0 -16
- data/support/runit/testcase.rb +0 -113
- data/support/runit/testfailure.rb +0 -25
- data/support/runit/testresult.rb +0 -121
- data/support/runit/testsuite.rb +0 -43
- data/support/runit/version.rb +0 -3
- data/test/test_describe.rb +0 -137
data/ext/oci8/oci8.c
CHANGED
@@ -1,178 +1,594 @@
|
|
1
|
+
/* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
|
1
2
|
/*
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
== class hierarchy
|
8
|
-
* ((<OCIHandle>))
|
9
|
-
* ((<OCIEnv>)) (OCI environment handle)
|
10
|
-
* ((<OCISvcCtx>)) (OCI service context handle)
|
11
|
-
* ((<OCIServer>)) (OCI server handle)
|
12
|
-
* ((<OCISession>)) (OCI user session handle)
|
13
|
-
* ((<OCIStmt>)) (OCI statement handle)
|
14
|
-
* ((<OCIDefine>)) (OCI define handle)
|
15
|
-
* ((<OCIBind>)) (OCI bind handle)
|
16
|
-
* ((<OCIDescribe>)) (OCI descibe handle)
|
17
|
-
|
18
|
-
* ((<OCIDescriptor>))
|
19
|
-
* ((<OCILobLocator>)) (OCI Lob Locator descriptor)
|
20
|
-
* ((<OCIParam>)) (read-only parameter descriptor)
|
21
|
-
* ((<OCIRowid>)) (OCI ROWID descriptor)
|
22
|
-
|
23
|
-
* OCIException
|
24
|
-
* ((<OCIError>))
|
25
|
-
* ((<OCISuccessWithInfo>))
|
26
|
-
* OCINoData
|
27
|
-
* OCIInvalidHandle
|
28
|
-
* OCINeedData
|
29
|
-
* OCIStillExecuting
|
30
|
-
|
31
|
-
* ((<OraDate>))
|
32
|
-
* ((<OraNumber>))
|
33
|
-
|
34
|
-
== object hierarchy
|
35
|
-
|
36
|
-
* ((<OCIEnv>)) (OCI environment handle)
|
37
|
-
* ((<OCISvcCtx>)) (OCI service context handle)
|
38
|
-
* ((<OCIServer>)) (OCI server handle)
|
39
|
-
* ((<OCISession>)) (OCI user session handle)
|
40
|
-
* ((<OCIStmt>)) (OCI statement handle)
|
41
|
-
* ((<OCIDefine>)) (OCI define handle)
|
42
|
-
* ((<OCIBind>)) (OCI bind handle)
|
43
|
-
=end
|
44
|
-
*/
|
3
|
+
* oci8.c - part of ruby-oci8
|
4
|
+
*
|
5
|
+
* Copyright (C) 2002-2009 KUBO Takehiro <kubo@jiubao.org>
|
6
|
+
*
|
7
|
+
*/
|
45
8
|
#include "oci8.h"
|
9
|
+
#ifdef HAVE_UNISTD_H
|
10
|
+
#include <unistd.h> /* getpid() */
|
11
|
+
#endif
|
46
12
|
|
47
|
-
|
48
|
-
#
|
49
|
-
|
13
|
+
#ifdef WIN32
|
14
|
+
#ifndef getpid
|
15
|
+
extern rb_pid_t rb_w32_getpid(void);
|
16
|
+
#define getpid() rb_w32_getpid()
|
17
|
+
#endif
|
50
18
|
#endif
|
51
19
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
VALUE
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
20
|
+
/*
|
21
|
+
* Document-class: OCI8
|
22
|
+
*
|
23
|
+
* The class to access Oracle database server.
|
24
|
+
*
|
25
|
+
* example:
|
26
|
+
* # output the emp table's content as CSV format.
|
27
|
+
* conn = OCI8.new(username, password)
|
28
|
+
* conn.exec('select * from emp') do |row|
|
29
|
+
* puts row.join(',')
|
30
|
+
* end
|
31
|
+
*
|
32
|
+
* # execute PL/SQL block with bind variables.
|
33
|
+
* conn = OCI8.new(username, password)
|
34
|
+
* conn.exec('BEGIN procedure_name(:1, :2); END;',
|
35
|
+
* value_for_the_first_parameter,
|
36
|
+
* value_for_the_second_parameter)
|
37
|
+
*/
|
38
|
+
static VALUE cOCI8;
|
39
|
+
|
40
|
+
static void oci8_svcctx_free(oci8_base_t *base)
|
41
|
+
{
|
42
|
+
oci8_svcctx_t *svcctx = (oci8_svcctx_t *)base;
|
43
|
+
|
44
|
+
if (svcctx->authhp) {
|
45
|
+
OCIHandleFree(svcctx->authhp, OCI_HTYPE_SESSION);
|
46
|
+
svcctx->authhp = NULL;
|
47
|
+
}
|
48
|
+
if (svcctx->srvhp) {
|
49
|
+
OCIHandleFree(svcctx->srvhp, OCI_HTYPE_SERVER);
|
50
|
+
svcctx->srvhp = NULL;
|
51
|
+
}
|
52
|
+
}
|
53
|
+
|
54
|
+
static oci8_base_class_t oci8_svcctx_class = {
|
55
|
+
NULL,
|
56
|
+
oci8_svcctx_free,
|
57
|
+
sizeof(oci8_svcctx_t)
|
58
|
+
};
|
59
|
+
|
60
|
+
static VALUE oracle_client_vernum; /* Oracle client version number */
|
61
|
+
static VALUE sym_SYSDBA;
|
62
|
+
static VALUE sym_SYSOPER;
|
63
|
+
static ID id_at_prefetch_rows;
|
64
|
+
static ID id_at_username;
|
65
|
+
static ID id_set_prefetch_rows;
|
66
|
+
|
67
|
+
static VALUE oci8_s_oracle_client_vernum(VALUE klass)
|
68
|
+
{
|
69
|
+
return oracle_client_vernum;
|
70
|
+
}
|
71
|
+
|
72
|
+
#define CONN_STR_REGEX "/^([^(\\s|\\@)]*)\\/([^(\\s|\\@)]*)(?:\\@(\\S+))?(?:\\s+as\\s+(\\S*)\\s*)?$/i"
|
73
|
+
static void oci8_do_parse_connect_string(VALUE conn_str, VALUE *user, VALUE *pass, VALUE *dbname, VALUE *mode)
|
74
|
+
{
|
75
|
+
static VALUE re = Qnil;
|
76
|
+
if (NIL_P(re)) {
|
77
|
+
re = rb_eval_string(CONN_STR_REGEX);
|
78
|
+
rb_global_variable(&re);
|
79
|
+
}
|
80
|
+
OCI8SafeStringValue(conn_str);
|
81
|
+
if (RTEST(rb_reg_match(re, conn_str))) {
|
82
|
+
*user = rb_reg_nth_match(1, rb_backref_get());
|
83
|
+
*pass = rb_reg_nth_match(2, rb_backref_get());
|
84
|
+
*dbname = rb_reg_nth_match(3, rb_backref_get());
|
85
|
+
*mode = rb_reg_nth_match(4, rb_backref_get());
|
86
|
+
if (RSTRING_LEN(*user) == 0 && RSTRING_LEN(*pass) == 0) {
|
87
|
+
/* external credential */
|
88
|
+
*user = Qnil;
|
89
|
+
*pass = Qnil;
|
90
|
+
}
|
91
|
+
if (!NIL_P(*mode)) {
|
92
|
+
char *ptr;
|
93
|
+
SafeStringValue(*mode);
|
94
|
+
ptr = RSTRING_PTR(*mode);
|
95
|
+
if (strcasecmp(ptr, "SYSDBA") == 0) {
|
96
|
+
*mode = sym_SYSDBA;
|
97
|
+
} else if (strcasecmp(ptr, "SYSOPER") == 0) {
|
98
|
+
*mode = sym_SYSOPER;
|
99
|
+
}
|
100
|
+
}
|
101
|
+
} else {
|
102
|
+
rb_raise(rb_eArgError, "invalid connect string \"%s\" (expect \"username/password[@(tns_name|//host[:port]/service_name)][ as (sysdba|sysoper)]\"", RSTRING_PTR(conn_str));
|
103
|
+
}
|
104
|
+
}
|
105
|
+
|
106
|
+
/*
|
107
|
+
* Add a private method to test oci8_do_parse_connect_string().
|
108
|
+
*/
|
109
|
+
static VALUE oci8_parse_connect_string(VALUE self, VALUE conn_str)
|
110
|
+
{
|
111
|
+
VALUE user;
|
112
|
+
VALUE pass;
|
113
|
+
VALUE dbname;
|
114
|
+
VALUE mode;
|
115
|
+
|
116
|
+
oci8_do_parse_connect_string(conn_str, &user, &pass, &dbname, &mode);
|
117
|
+
return rb_ary_new3(4, user, pass, dbname, mode);
|
118
|
+
}
|
119
|
+
|
120
|
+
/*
|
121
|
+
* call-seq:
|
122
|
+
* new(username, password, dbname = nil, privilege = nil)
|
123
|
+
*
|
124
|
+
* connect to Oracle by _username_ and _password_.
|
125
|
+
* set _dbname_ nil to connect the local database or TNS name to connect
|
126
|
+
* via network. You can use the following syntax for _dbname_ if the client
|
127
|
+
* library is Oracle 10g or upper.
|
128
|
+
*
|
129
|
+
* //HOST_NAME_OR_IP:TNS_LISTENER_PORT/ORACLE_SID
|
130
|
+
*
|
131
|
+
* If you need DBA privilege, use :SYSDBA or :SYSOPER to _privilege_.
|
132
|
+
*
|
133
|
+
* # connect to the local database.
|
134
|
+
* # sqlplus scott/tiger
|
135
|
+
* conn = OCI8.new("scott", "tiger")
|
136
|
+
*
|
137
|
+
* # connect via network with TNS name.
|
138
|
+
* # sqlplus scott/tiger@orcl.world
|
139
|
+
* conn = OCI8.new("scott", "tiger", "orcl.world")
|
140
|
+
*
|
141
|
+
* # connect via network with database's host, port and SID.
|
142
|
+
* # sqlplus scott/tiger@//localhost:1521/XE
|
143
|
+
* conn = OCI8.new("scott", "tiger", "//localhost:1521/XE")
|
144
|
+
*
|
145
|
+
* # connect as SYSDBA
|
146
|
+
* # sqlplus 'sys/change_on_install as sysdba'
|
147
|
+
* conn = OCI8.new("sys", "change_on_install", nil, :SYSDBA)
|
148
|
+
*
|
149
|
+
*/
|
150
|
+
static VALUE oci8_svcctx_initialize(int argc, VALUE *argv, VALUE self)
|
151
|
+
{
|
152
|
+
VALUE vusername;
|
153
|
+
VALUE vpassword;
|
154
|
+
VALUE vdbname;
|
155
|
+
VALUE vmode;
|
156
|
+
oci8_svcctx_t *svcctx = DATA_PTR(self);
|
157
|
+
sword rv;
|
158
|
+
enum logon_type_t logon_type = T_IMPLICIT;
|
159
|
+
ub4 cred = OCI_CRED_RDBMS;
|
160
|
+
ub4 mode = OCI_DEFAULT;
|
161
|
+
OCISvcCtx *svchp = NULL;
|
162
|
+
|
163
|
+
svcctx->executing_thread = Qnil;
|
164
|
+
if (argc == 1) {
|
165
|
+
oci8_do_parse_connect_string(argv[0], &vusername, &vpassword, &vdbname, &vmode);
|
166
|
+
} else {
|
167
|
+
rb_scan_args(argc, argv, "22", &vusername, &vpassword, &vdbname, &vmode);
|
168
|
+
}
|
169
|
+
|
170
|
+
rb_ivar_set(self, id_at_prefetch_rows, Qnil);
|
171
|
+
rb_ivar_set(self, id_at_username, Qnil);
|
172
|
+
if (NIL_P(vusername) && NIL_P(vpassword)) {
|
173
|
+
/* external credential */
|
174
|
+
logon_type = T_EXPLICIT;
|
175
|
+
cred = OCI_CRED_EXT;
|
176
|
+
} else {
|
177
|
+
/* RDBMS credential */
|
178
|
+
OCI8SafeStringValue(vusername); /* 1 */
|
179
|
+
OCI8SafeStringValue(vpassword); /* 2 */
|
180
|
+
}
|
181
|
+
if (!NIL_P(vdbname)) {
|
182
|
+
OCI8SafeStringValue(vdbname); /* 3 */
|
183
|
+
}
|
184
|
+
if (!NIL_P(vmode)) { /* 4 */
|
185
|
+
logon_type = T_EXPLICIT;
|
186
|
+
Check_Type(vmode, T_SYMBOL);
|
187
|
+
if (vmode == sym_SYSDBA) {
|
188
|
+
mode = OCI_SYSDBA;
|
189
|
+
} else if (vmode == sym_SYSOPER) {
|
190
|
+
mode = OCI_SYSOPER;
|
191
|
+
} else {
|
192
|
+
rb_raise(rb_eArgError, "invalid privilege name %s (expect :SYSDBA or :SYSOPER)", rb_id2name(SYM2ID(vmode)));
|
193
|
+
}
|
194
|
+
}
|
195
|
+
switch (logon_type) {
|
196
|
+
case T_IMPLICIT:
|
197
|
+
rv = OCILogon_nb(svcctx, oci8_envhp, oci8_errhp, &svchp,
|
198
|
+
RSTRING_ORATEXT(vusername), RSTRING_LEN(vusername),
|
199
|
+
RSTRING_ORATEXT(vpassword), RSTRING_LEN(vpassword),
|
200
|
+
NIL_P(vdbname) ? NULL : RSTRING_ORATEXT(vdbname),
|
201
|
+
NIL_P(vdbname) ? 0 : RSTRING_LEN(vdbname));
|
202
|
+
svcctx->base.hp.svc = svchp;
|
203
|
+
svcctx->base.type = OCI_HTYPE_SVCCTX;
|
204
|
+
svcctx->logon_type = T_IMPLICIT;
|
205
|
+
if (rv != OCI_SUCCESS) {
|
206
|
+
oci8_raise(oci8_errhp, rv, NULL);
|
207
|
+
}
|
208
|
+
break;
|
209
|
+
case T_EXPLICIT:
|
210
|
+
/* allocate OCI handles. */
|
211
|
+
rv = OCIHandleAlloc(oci8_envhp, &svcctx->base.hp.ptr, OCI_HTYPE_SVCCTX, 0, 0);
|
212
|
+
if (rv != OCI_SUCCESS)
|
213
|
+
oci8_env_raise(oci8_envhp, rv);
|
214
|
+
svcctx->base.type = OCI_HTYPE_SVCCTX;
|
215
|
+
rv = OCIHandleAlloc(oci8_envhp, (void*)&svcctx->authhp, OCI_HTYPE_SESSION, 0, 0);
|
216
|
+
if (rv != OCI_SUCCESS)
|
217
|
+
oci8_env_raise(oci8_envhp, rv);
|
218
|
+
rv = OCIHandleAlloc(oci8_envhp, (void*)&svcctx->srvhp, OCI_HTYPE_SERVER, 0, 0);
|
219
|
+
if (rv != OCI_SUCCESS)
|
220
|
+
oci8_env_raise(oci8_envhp, rv);
|
221
|
+
|
222
|
+
/* set username and password to OCISession. */
|
223
|
+
if (cred == OCI_CRED_RDBMS) {
|
224
|
+
oci_lc(OCIAttrSet(svcctx->authhp, OCI_HTYPE_SESSION,
|
225
|
+
RSTRING_PTR(vusername), RSTRING_LEN(vusername),
|
226
|
+
OCI_ATTR_USERNAME, oci8_errhp));
|
227
|
+
oci_lc(OCIAttrSet(svcctx->authhp, OCI_HTYPE_SESSION,
|
228
|
+
RSTRING_PTR(vpassword), RSTRING_LEN(vpassword),
|
229
|
+
OCI_ATTR_PASSWORD, oci8_errhp));
|
230
|
+
}
|
231
|
+
|
232
|
+
/* attach to server and set to OCISvcCtx. */
|
233
|
+
rv = OCIServerAttach_nb(svcctx, svcctx->srvhp, oci8_errhp,
|
234
|
+
NIL_P(vdbname) ? NULL : RSTRING_ORATEXT(vdbname),
|
235
|
+
NIL_P(vdbname) ? 0 : RSTRING_LEN(vdbname), OCI_DEFAULT);
|
236
|
+
if (rv != OCI_SUCCESS)
|
237
|
+
oci8_raise(oci8_errhp, rv, NULL);
|
238
|
+
oci_lc(OCIAttrSet(svcctx->base.hp.ptr, OCI_HTYPE_SVCCTX, svcctx->srvhp, 0, OCI_ATTR_SERVER, oci8_errhp));
|
239
|
+
|
240
|
+
/* begin session. */
|
241
|
+
rv = OCISessionBegin_nb(svcctx, svcctx->base.hp.ptr, oci8_errhp, svcctx->authhp, cred, mode);
|
242
|
+
if (rv != OCI_SUCCESS)
|
243
|
+
oci8_raise(oci8_errhp, rv, NULL);
|
244
|
+
oci_lc(OCIAttrSet(svcctx->base.hp.ptr, OCI_HTYPE_SVCCTX, svcctx->authhp, 0, OCI_ATTR_SESSION, oci8_errhp));
|
245
|
+
svcctx->logon_type = T_EXPLICIT;
|
246
|
+
break;
|
247
|
+
default:
|
248
|
+
break;
|
249
|
+
}
|
250
|
+
svcctx->pid = getpid();
|
251
|
+
svcctx->is_autocommit = 0;
|
252
|
+
#ifdef RUBY_VM
|
253
|
+
svcctx->non_blocking = 0;
|
140
254
|
#endif
|
255
|
+
svcctx->long_read_len = INT2FIX(65535);
|
256
|
+
return Qnil;
|
257
|
+
}
|
258
|
+
|
259
|
+
|
260
|
+
/*
|
261
|
+
* call-seq:
|
262
|
+
* logoff
|
263
|
+
*
|
264
|
+
* disconnect from Oracle. Uncommitted transaction will be
|
265
|
+
* rollbacked.
|
266
|
+
*
|
267
|
+
* example:
|
268
|
+
* conn = OCI8.new("scott", "tiger")
|
269
|
+
* ... do something ...
|
270
|
+
* conn.logoff
|
271
|
+
*/
|
272
|
+
static VALUE oci8_svcctx_logoff(VALUE self)
|
273
|
+
{
|
274
|
+
oci8_svcctx_t *svcctx = (oci8_svcctx_t *)DATA_PTR(self);
|
275
|
+
sword rv;
|
276
|
+
|
277
|
+
while (svcctx->base.children != NULL) {
|
278
|
+
oci8_base_free(svcctx->base.children);
|
279
|
+
}
|
280
|
+
switch (svcctx->logon_type) {
|
281
|
+
case T_IMPLICIT:
|
282
|
+
oci_lc(OCITransRollback_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, OCI_DEFAULT));
|
283
|
+
rv = OCILogoff_nb(svcctx, svcctx->base.hp.svc, oci8_errhp);
|
284
|
+
svcctx->base.type = 0;
|
285
|
+
svcctx->logon_type = T_NOT_LOGIN;
|
286
|
+
if (rv != OCI_SUCCESS)
|
287
|
+
oci8_raise(oci8_errhp, rv, NULL);
|
288
|
+
svcctx->authhp = NULL;
|
289
|
+
svcctx->srvhp = NULL;
|
290
|
+
break;
|
291
|
+
case T_EXPLICIT:
|
292
|
+
oci_lc(OCITransRollback_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, OCI_DEFAULT));
|
293
|
+
rv = OCISessionEnd_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, svcctx->authhp, OCI_DEFAULT);
|
294
|
+
if (rv == OCI_SUCCESS) {
|
295
|
+
rv = OCIServerDetach_nb(svcctx, svcctx->srvhp, oci8_errhp, OCI_DEFAULT);
|
296
|
+
}
|
297
|
+
svcctx->logon_type = T_NOT_LOGIN;
|
298
|
+
if (rv != OCI_SUCCESS)
|
299
|
+
oci8_raise(oci8_errhp, rv, NULL);
|
300
|
+
break;
|
301
|
+
case T_NOT_LOGIN:
|
302
|
+
break;
|
303
|
+
}
|
304
|
+
return Qtrue;
|
305
|
+
}
|
306
|
+
|
307
|
+
/*
|
308
|
+
* call-seq:
|
309
|
+
* parse(sql_text) -> an instance of OCI8::Cursor
|
310
|
+
*
|
311
|
+
* prepare the SQL statement and return an instance of OCI8::Cursor.
|
312
|
+
*/
|
313
|
+
static VALUE oci8_svcctx_parse(VALUE self, VALUE sql)
|
314
|
+
{
|
315
|
+
VALUE obj = rb_funcall(cOCIStmt, oci8_id_new, 2, self, sql);
|
316
|
+
VALUE prefetch_rows = rb_ivar_get(self, id_at_prefetch_rows);
|
317
|
+
if (!NIL_P(prefetch_rows)) {
|
318
|
+
rb_funcall(obj, id_set_prefetch_rows, 1, prefetch_rows);
|
319
|
+
}
|
320
|
+
return obj;
|
321
|
+
}
|
322
|
+
|
323
|
+
/*
|
324
|
+
* call-seq:
|
325
|
+
* commit
|
326
|
+
*
|
327
|
+
* commit the transaction.
|
328
|
+
*
|
329
|
+
* example:
|
330
|
+
* conn = OCI8.new("scott", "tiger")
|
331
|
+
* conn.exec("UPDATE emp SET sal = sal * 1.1") # yahoo
|
332
|
+
* conn.commit
|
333
|
+
* conn.logoff
|
334
|
+
*/
|
335
|
+
static VALUE oci8_commit(VALUE self)
|
336
|
+
{
|
337
|
+
oci8_svcctx_t *svcctx = DATA_PTR(self);
|
338
|
+
oci_lc(OCITransCommit_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, OCI_DEFAULT));
|
339
|
+
return self;
|
141
340
|
}
|
142
341
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
342
|
+
/*
|
343
|
+
* call-seq:
|
344
|
+
* rollback
|
345
|
+
*
|
346
|
+
* rollback the transaction.
|
347
|
+
*
|
348
|
+
* example:
|
349
|
+
* conn = OCI8.new("scott", "tiger")
|
350
|
+
* conn.exec("UPDATE emp SET sal = sal * 0.9") # boos
|
351
|
+
* conn.rollback
|
352
|
+
* conn.logoff
|
353
|
+
*/
|
354
|
+
static VALUE oci8_rollback(VALUE self)
|
355
|
+
{
|
356
|
+
oci8_svcctx_t *svcctx = DATA_PTR(self);
|
357
|
+
oci_lc(OCITransRollback_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, OCI_DEFAULT));
|
358
|
+
return self;
|
359
|
+
}
|
360
|
+
|
361
|
+
/*
|
362
|
+
* call-seq:
|
363
|
+
* non_blocking? -> true or false
|
364
|
+
*
|
365
|
+
* return the status of blocking/non-blocking mode.
|
366
|
+
* See non_blocking= also.
|
367
|
+
*/
|
368
|
+
static VALUE oci8_non_blocking_p(VALUE self)
|
369
|
+
{
|
370
|
+
oci8_svcctx_t *svcctx = DATA_PTR(self);
|
371
|
+
#ifdef RUBY_VM
|
372
|
+
return svcctx->non_blocking ? Qtrue : Qfalse;
|
373
|
+
#else
|
374
|
+
sb1 non_blocking;
|
375
|
+
|
376
|
+
if (svcctx->srvhp == NULL) {
|
377
|
+
oci_lc(OCIAttrGet(svcctx->base.hp.ptr, OCI_HTYPE_SVCCTX, &svcctx->srvhp, 0, OCI_ATTR_SERVER, oci8_errhp));
|
378
|
+
}
|
379
|
+
oci_lc(OCIAttrGet(svcctx->srvhp, OCI_HTYPE_SERVER, &non_blocking, 0, OCI_ATTR_NONBLOCKING_MODE, oci8_errhp));
|
380
|
+
return non_blocking ? Qtrue : Qfalse;
|
381
|
+
#endif
|
382
|
+
}
|
383
|
+
|
384
|
+
/*
|
385
|
+
* call-seq:
|
386
|
+
* non_blocking = true or false
|
387
|
+
*
|
388
|
+
* change the status of blocking/non-blocking mode. true for non-blocking
|
389
|
+
* mode. false for blocking mode. The default is blocking.
|
390
|
+
*
|
391
|
+
* When blocking mode, long-time SQL execution blocks the ruby process
|
392
|
+
* itself even though multithread application because ruby's thread is
|
393
|
+
* not native one.
|
394
|
+
*
|
395
|
+
* when non-blocking mode, long-time SQL execution doesn't block the ruby
|
396
|
+
* process. It only blocks the thread which executing the SQL statement.
|
397
|
+
* But each SQL will need a bit more time because it checks the status by
|
398
|
+
* polling.
|
399
|
+
*
|
400
|
+
* You can cancel an executing SQL by using OCI8#break from another thread.
|
401
|
+
* The canceled thread raises OCIBreak exception.
|
402
|
+
*/
|
403
|
+
static VALUE oci8_set_non_blocking(VALUE self, VALUE val)
|
404
|
+
{
|
405
|
+
oci8_svcctx_t *svcctx = DATA_PTR(self);
|
406
|
+
#ifdef RUBY_VM
|
407
|
+
svcctx->non_blocking = RTEST(val);
|
408
|
+
#else
|
409
|
+
sb1 non_blocking;
|
410
|
+
|
411
|
+
if (svcctx->srvhp == NULL) {
|
412
|
+
oci_lc(OCIAttrGet(svcctx->base.hp.ptr, OCI_HTYPE_SVCCTX, &svcctx->srvhp, 0, OCI_ATTR_SERVER, oci8_errhp));
|
413
|
+
}
|
414
|
+
oci_lc(OCIAttrGet(svcctx->srvhp, OCI_HTYPE_SERVER, &non_blocking, 0, OCI_ATTR_NONBLOCKING_MODE, oci8_errhp));
|
415
|
+
if ((RTEST(val) && !non_blocking) || (!RTEST(val) && non_blocking)) {
|
416
|
+
/* toggle blocking / non-blocking. */
|
417
|
+
oci_lc(OCIAttrSet(svcctx->srvhp, OCI_HTYPE_SERVER, 0, 0, OCI_ATTR_NONBLOCKING_MODE, oci8_errhp));
|
418
|
+
}
|
147
419
|
#endif
|
420
|
+
return val;
|
421
|
+
}
|
422
|
+
|
423
|
+
/*
|
424
|
+
* call-seq:
|
425
|
+
* autocommit? -> true or false
|
426
|
+
*
|
427
|
+
* return the state of the autocommit mode. The default value is
|
428
|
+
* false. If true, the transaction is committed on every SQL executions.
|
429
|
+
*/
|
430
|
+
static VALUE oci8_autocommit_p(VALUE self)
|
431
|
+
{
|
432
|
+
oci8_svcctx_t *svcctx = DATA_PTR(self);
|
433
|
+
return svcctx->is_autocommit ? Qtrue : Qfalse;
|
434
|
+
}
|
148
435
|
|
149
|
-
|
150
|
-
|
436
|
+
/*
|
437
|
+
* call-seq:
|
438
|
+
* autocommit = true or false
|
439
|
+
*
|
440
|
+
* change the status of the autocommit mode.
|
441
|
+
*
|
442
|
+
* example:
|
443
|
+
* conn = OCI8.new("scott", "tiger")
|
444
|
+
* conn.autocommit = true
|
445
|
+
* ... do something ...
|
446
|
+
* conn.logoff
|
447
|
+
*/
|
448
|
+
static VALUE oci8_set_autocommit(VALUE self, VALUE val)
|
449
|
+
{
|
450
|
+
oci8_svcctx_t *svcctx = DATA_PTR(self);
|
451
|
+
svcctx->is_autocommit = RTEST(val);
|
452
|
+
return val;
|
453
|
+
}
|
454
|
+
|
455
|
+
/*
|
456
|
+
* call-seq:
|
457
|
+
* long_read_len -> aFixnum (new in 0.1.16)
|
458
|
+
*
|
459
|
+
* get the maximum fetch size for a LONG and LONG RAW column.
|
460
|
+
*/
|
461
|
+
static VALUE oci8_long_read_len(VALUE self)
|
151
462
|
{
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
sword rv;
|
463
|
+
oci8_svcctx_t *svcctx = DATA_PTR(self);
|
464
|
+
return svcctx->long_read_len;
|
465
|
+
}
|
156
466
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
467
|
+
/*
|
468
|
+
* call-seq:
|
469
|
+
* long_read_len = aFixnum (new in 0.1.16)
|
470
|
+
*
|
471
|
+
* change the maximum fetch size for a LONG and LONG RAW column.
|
472
|
+
* The default value is 65535.
|
473
|
+
*
|
474
|
+
* example:
|
475
|
+
* conn = OCI8.new('scott', 'tiger'
|
476
|
+
* conn.long_read_len = 1000000
|
477
|
+
* cursor = con.exec('select content from articles where id = :1', 23478)
|
478
|
+
* row = cursor.fetch
|
479
|
+
*/
|
480
|
+
static VALUE oci8_set_long_read_len(VALUE self, VALUE val)
|
481
|
+
{
|
482
|
+
oci8_svcctx_t *svcctx = DATA_PTR(self);
|
483
|
+
Check_Type(val, T_FIXNUM);
|
484
|
+
svcctx->long_read_len = val;
|
485
|
+
return val;
|
162
486
|
}
|
487
|
+
|
488
|
+
/*
|
489
|
+
* call-seq:
|
490
|
+
* break
|
491
|
+
*
|
492
|
+
* cancel an executing SQL in an other thread.
|
493
|
+
* See non_blocking= also.
|
494
|
+
*/
|
495
|
+
static VALUE oci8_break(VALUE self)
|
496
|
+
{
|
497
|
+
oci8_svcctx_t *svcctx = DATA_PTR(self);
|
498
|
+
#ifndef RUBY_VM
|
499
|
+
sword rv;
|
163
500
|
#endif
|
164
501
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
if (OCIRowidToChar_func != NULL) {
|
173
|
-
rb_define_method(cOCIRowid, "to_s", oci8_rowid_to_s, 0);
|
174
|
-
}
|
175
|
-
#elif defined(HAVE_OCIROWIDTOCHAR)
|
176
|
-
rb_define_method(cOCIRowid, "to_s", oci8_rowid_to_s, 0);
|
502
|
+
if (NIL_P(svcctx->executing_thread)) {
|
503
|
+
return Qfalse;
|
504
|
+
}
|
505
|
+
#ifndef RUBY_VM
|
506
|
+
rv = OCIBreak(svcctx->base.hp.ptr, oci8_errhp);
|
507
|
+
if (rv != OCI_SUCCESS)
|
508
|
+
oci8_raise(oci8_errhp, rv, NULL);
|
177
509
|
#endif
|
510
|
+
rb_thread_wakeup(svcctx->executing_thread);
|
511
|
+
return Qtrue;
|
178
512
|
}
|
513
|
+
|
514
|
+
/*
|
515
|
+
* call-seq:
|
516
|
+
* prefetch_rows = aFixnum (new in 0.1.14)
|
517
|
+
*
|
518
|
+
* change the prefetch rows size. This reduces network round trips
|
519
|
+
* when fetching multiple rows.
|
520
|
+
*/
|
521
|
+
static VALUE oci8_set_prefetch_rows(VALUE self, VALUE val)
|
522
|
+
{
|
523
|
+
rb_ivar_set(self, id_at_prefetch_rows, val);
|
524
|
+
return val;
|
525
|
+
}
|
526
|
+
|
527
|
+
VALUE Init_oci8(void)
|
528
|
+
{
|
529
|
+
cOCI8 = oci8_define_class("OCI8", &oci8_svcctx_class);
|
530
|
+
|
531
|
+
oracle_client_vernum = oracle_client_version;
|
532
|
+
if (have_OCIClientVersion) {
|
533
|
+
sword major, minor, update, patch, port_update;
|
534
|
+
OCIClientVersion(&major, &minor, &update, &patch, &port_update);
|
535
|
+
oracle_client_vernum = INT2FIX(ORAVERNUM(major, minor, update, patch, port_update));
|
536
|
+
}
|
537
|
+
|
538
|
+
sym_SYSDBA = ID2SYM(rb_intern("SYSDBA"));
|
539
|
+
sym_SYSOPER = ID2SYM(rb_intern("SYSOPER"));
|
540
|
+
id_at_prefetch_rows = rb_intern("@prefetch_rows");
|
541
|
+
id_at_username = rb_intern("@username");
|
542
|
+
id_set_prefetch_rows = rb_intern("prefetch_rows=");
|
543
|
+
|
544
|
+
rb_define_singleton_method_nodoc(cOCI8, "oracle_client_vernum", oci8_s_oracle_client_vernum, 0);
|
545
|
+
rb_define_private_method(cOCI8, "parse_connect_string", oci8_parse_connect_string, 1);
|
546
|
+
rb_define_method(cOCI8, "initialize", oci8_svcctx_initialize, -1);
|
547
|
+
rb_define_method(cOCI8, "logoff", oci8_svcctx_logoff, 0);
|
548
|
+
rb_define_method(cOCI8, "parse", oci8_svcctx_parse, 1);
|
549
|
+
rb_define_method(cOCI8, "commit", oci8_commit, 0);
|
550
|
+
rb_define_method(cOCI8, "rollback", oci8_rollback, 0);
|
551
|
+
rb_define_method(cOCI8, "non_blocking?", oci8_non_blocking_p, 0);
|
552
|
+
rb_define_method(cOCI8, "non_blocking=", oci8_set_non_blocking, 1);
|
553
|
+
rb_define_method(cOCI8, "autocommit?", oci8_autocommit_p, 0);
|
554
|
+
rb_define_method(cOCI8, "autocommit=", oci8_set_autocommit, 1);
|
555
|
+
rb_define_method(cOCI8, "long_read_len", oci8_long_read_len, 0);
|
556
|
+
rb_define_method(cOCI8, "long_read_len=", oci8_set_long_read_len, 1);
|
557
|
+
rb_define_method(cOCI8, "break", oci8_break, 0);
|
558
|
+
rb_define_method(cOCI8, "prefetch_rows=", oci8_set_prefetch_rows, 1);
|
559
|
+
return cOCI8;
|
560
|
+
}
|
561
|
+
|
562
|
+
oci8_svcctx_t *oci8_get_svcctx(VALUE obj)
|
563
|
+
{
|
564
|
+
oci8_base_t *base;
|
565
|
+
Check_Handle(obj, cOCI8, base);
|
566
|
+
if (base->type == 0) {
|
567
|
+
rb_raise(eOCIException, "invalid argument %s was freed already.", rb_class2name(CLASS_OF(obj)));
|
568
|
+
}
|
569
|
+
return (oci8_svcctx_t *)base;
|
570
|
+
}
|
571
|
+
|
572
|
+
OCISvcCtx *oci8_get_oci_svcctx(VALUE obj)
|
573
|
+
{
|
574
|
+
oci8_svcctx_t *svcctx = oci8_get_svcctx(obj);
|
575
|
+
return svcctx->base.hp.svc;
|
576
|
+
}
|
577
|
+
|
578
|
+
OCISession *oci8_get_oci_session(VALUE obj)
|
579
|
+
{
|
580
|
+
oci8_svcctx_t *svcctx = oci8_get_svcctx(obj);
|
581
|
+
|
582
|
+
if (svcctx->authhp == NULL) {
|
583
|
+
oci_lc(OCIAttrGet(svcctx->base.hp.ptr, OCI_HTYPE_SVCCTX, &svcctx->authhp, 0, OCI_ATTR_SESSION, oci8_errhp));
|
584
|
+
}
|
585
|
+
return svcctx->authhp;
|
586
|
+
}
|
587
|
+
|
588
|
+
void oci8_check_pid_consistency(oci8_svcctx_t *svcctx)
|
589
|
+
{
|
590
|
+
if (svcctx->pid != getpid()) {
|
591
|
+
rb_raise(rb_eRuntimeError, "The connection cannot be reused in the forked process.");
|
592
|
+
}
|
593
|
+
}
|
594
|
+
|