ruby-oci8 1.0.7 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|