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.
Files changed (89) hide show
  1. data/ChangeLog +1254 -390
  2. data/Makefile +10 -13
  3. data/README +56 -385
  4. data/VERSION +1 -1
  5. data/dist-files +26 -27
  6. data/ext/oci8/.document +1 -0
  7. data/ext/oci8/MANIFEST +0 -4
  8. data/ext/oci8/apiwrap.c.tmpl +172 -0
  9. data/ext/oci8/apiwrap.h.tmpl +61 -0
  10. data/ext/oci8/apiwrap.rb +91 -0
  11. data/ext/oci8/apiwrap.yml +1243 -0
  12. data/ext/oci8/attr.c +124 -384
  13. data/ext/oci8/bind.c +472 -164
  14. data/ext/oci8/encoding.c +196 -0
  15. data/ext/oci8/env.c +84 -253
  16. data/ext/oci8/error.c +196 -127
  17. data/ext/oci8/extconf.rb +82 -59
  18. data/ext/oci8/lob.c +710 -370
  19. data/ext/oci8/metadata.c +359 -0
  20. data/ext/oci8/object.c +622 -0
  21. data/ext/oci8/oci8.c +577 -161
  22. data/ext/oci8/oci8.h +354 -258
  23. data/ext/oci8/oci8lib.c +493 -0
  24. data/ext/oci8/ocidatetime.c +473 -0
  25. data/ext/oci8/ocinumber.c +1123 -24
  26. data/ext/oci8/oraconf.rb +72 -106
  27. data/ext/oci8/oradate.c +511 -321
  28. data/ext/oci8/stmt.c +752 -572
  29. data/ext/oci8/win32.c +131 -0
  30. data/ext/oci8/xmldb.c +383 -0
  31. data/lib/.document +2 -0
  32. data/lib/dbd/OCI8.rb +2 -17
  33. data/lib/oci8.rb.in +41 -1622
  34. data/lib/oci8/.document +5 -0
  35. data/lib/oci8/compat.rb +108 -0
  36. data/lib/oci8/datetime.rb +489 -0
  37. data/lib/oci8/encoding-init.rb +40 -0
  38. data/lib/oci8/encoding.yml +537 -0
  39. data/lib/oci8/metadata.rb +2077 -0
  40. data/lib/oci8/object.rb +548 -0
  41. data/lib/oci8/oci8.rb +773 -0
  42. data/lib/oci8/oracle_version.rb +144 -0
  43. data/metaconfig +3 -3
  44. data/ruby-oci8.gemspec +5 -5
  45. data/setup.rb +4 -4
  46. data/test/config.rb +64 -84
  47. data/test/test_all.rb +14 -21
  48. data/test/test_array_dml.rb +317 -0
  49. data/test/test_bind_raw.rb +18 -25
  50. data/test/test_bind_time.rb +78 -91
  51. data/test/test_break.rb +37 -35
  52. data/test/test_clob.rb +33 -89
  53. data/test/test_connstr.rb +5 -4
  54. data/test/test_datetime.rb +469 -0
  55. data/test/test_dbi.rb +99 -60
  56. data/test/test_dbi_clob.rb +3 -8
  57. data/test/test_metadata.rb +65 -51
  58. data/test/test_oci8.rb +151 -55
  59. data/test/test_oracle_version.rb +70 -0
  60. data/test/test_oradate.rb +76 -83
  61. data/test/test_oranumber.rb +405 -71
  62. data/test/test_rowid.rb +6 -11
  63. metadata +31 -32
  64. data/NEWS +0 -420
  65. data/ext/oci8/const.c +0 -165
  66. data/ext/oci8/define.c +0 -53
  67. data/ext/oci8/describe.c +0 -81
  68. data/ext/oci8/descriptor.c +0 -39
  69. data/ext/oci8/handle.c +0 -273
  70. data/ext/oci8/oranumber.c +0 -445
  71. data/ext/oci8/param.c +0 -37
  72. data/ext/oci8/server.c +0 -182
  73. data/ext/oci8/session.c +0 -99
  74. data/ext/oci8/svcctx.c +0 -238
  75. data/ruby-oci8.spec +0 -62
  76. data/support/README +0 -4
  77. data/support/runit/assert.rb +0 -281
  78. data/support/runit/cui/testrunner.rb +0 -101
  79. data/support/runit/error.rb +0 -4
  80. data/support/runit/method_mappable.rb +0 -20
  81. data/support/runit/robserver.rb +0 -25
  82. data/support/runit/setuppable.rb +0 -15
  83. data/support/runit/teardownable.rb +0 -16
  84. data/support/runit/testcase.rb +0 -113
  85. data/support/runit/testfailure.rb +0 -25
  86. data/support/runit/testresult.rb +0 -121
  87. data/support/runit/testsuite.rb +0 -43
  88. data/support/runit/version.rb +0 -3
  89. data/test/test_describe.rb +0 -137
@@ -1,178 +1,594 @@
1
+ /* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
1
2
  /*
2
- oci8.c - part of ruby-oci8
3
-
4
- Copyright (C) 2002 KUBO Takehiro <kubo@jiubao.org>
5
-
6
- =begin
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
- /* #define DEBUG_CORE_FILE 1 */
48
- #ifdef DEBUG_CORE_FILE
49
- #include <signal.h>
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
- VALUE cOCIHandle;
53
- VALUE cOCIEnv;
54
- VALUE cOCIServer;
55
- VALUE cOCISession;
56
- VALUE cOCISvcCtx;
57
- VALUE cOCIStmt;
58
- VALUE cOCIDefine;
59
- VALUE cOCIBind;
60
- VALUE cOCIDescribe;
61
-
62
- VALUE cOCIDescriptor;
63
- VALUE cOCIParam;
64
- VALUE cOCILobLocator;
65
- VALUE cOCIFileLocator;
66
- VALUE cOCIRowid;
67
-
68
- VALUE eOCIException;
69
- VALUE eOCINoData;
70
- VALUE eOCIError;
71
- VALUE eOCIInvalidHandle;
72
- VALUE eOCINeedData;
73
- VALUE eOCIStillExecuting;
74
- VALUE eOCIContinue;
75
- VALUE eOCISuccessWithInfo;
76
-
77
- VALUE cOraDate;
78
- VALUE cOraNumber;
79
-
80
- static void Init_OCIRowid(void);
81
-
82
- void
83
- Init_oci8lib()
84
- {
85
- /* Handle */
86
- cOCIHandle = rb_define_class("OCIHandle", rb_cObject);
87
- cOCIEnv = rb_define_class("OCIEnv", cOCIHandle);
88
- cOCISvcCtx = rb_define_class("OCISvcCtx", cOCIHandle);
89
- cOCIServer = rb_define_class("OCIServer", cOCIHandle);
90
- cOCISession = rb_define_class("OCISession", cOCIHandle);
91
- cOCIStmt = rb_define_class("OCIStmt", cOCIHandle);
92
- cOCIDefine = rb_define_class("OCIDefine", cOCIHandle);
93
- cOCIBind = rb_define_class("OCIBind", cOCIHandle);
94
- cOCIDescribe = rb_define_class("OCIDescribe", cOCIHandle);
95
-
96
- /* Descriptor */
97
- cOCIDescriptor = rb_define_class("OCIDescriptor", rb_cObject);
98
- cOCILobLocator = rb_define_class("OCILobLocator", cOCIDescriptor);
99
- cOCIFileLocator = rb_define_class("OCIFileLocator", cOCILobLocator);
100
- cOCIParam = rb_define_class("OCIParam", cOCIDescriptor);
101
- cOCIRowid = rb_define_class("OCIRowid", cOCIDescriptor);
102
-
103
- /* Exception */
104
- eOCIException = rb_define_class("OCIException", rb_eStandardError);
105
- eOCINoData = rb_define_class("OCINoData", eOCIException);
106
- eOCIError = rb_define_class("OCIError", eOCIException);
107
- eOCIInvalidHandle = rb_define_class("OCIInvalidHandle", eOCIException);
108
- eOCINeedData = rb_define_class("OCINeedData", eOCIException);
109
- eOCIStillExecuting = rb_define_class("OCIStillExecuting", eOCIException);
110
- eOCIContinue = rb_define_class("OCIContinue", eOCIException);
111
- eOCISuccessWithInfo = rb_define_class("OCISuccessWithInfo", eOCIError);
112
-
113
- /* oracle specific type */
114
- cOraDate = rb_define_class("OraDate", rb_cObject);
115
- cOraNumber = rb_define_class("OraNumber", rb_cObject);
116
-
117
- Init_oci8_const();
118
- Init_oci8_handle();
119
- Init_oci8_env();
120
- Init_oci8_error();
121
- Init_oci8_svcctx();
122
- Init_oci8_server();
123
- Init_oci8_session();
124
- Init_oci8_stmt();
125
- Init_oci8_define();
126
- Init_oci8_bind();
127
- Init_oci8_describe();
128
-
129
- Init_oci8_descriptor();
130
- Init_oci8_param();
131
- Init_oci8_lob();
132
-
133
- Init_ora_date();
134
- Init_ora_number();
135
-
136
- Init_OCIRowid();
137
-
138
- #ifdef DEBUG_CORE_FILE
139
- signal(SIGSEGV, SIG_DFL);
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
- #if defined(WIN32)
144
- typedef sword (*OCIRowidToChar_func_t)(OCIRowid *rowidDesc, OraText *outbfp, ub2 *outbflp, OCIError *errhp);
145
- static OCIRowidToChar_func_t OCIRowidToChar_func;
146
- #define OCIRowidToChar OCIRowidToChar_func
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
- #if defined(WIN32) || defined(HAVE_OCIROWIDTOCHAR)
150
- static VALUE oci8_rowid_to_s(VALUE self)
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
- oci8_handle_t *h;
153
- char buf[64];
154
- ub2 buflen = sizeof(buf);
155
- sword rv;
463
+ oci8_svcctx_t *svcctx = DATA_PTR(self);
464
+ return svcctx->long_read_len;
465
+ }
156
466
 
157
- Get_Handle(self, h);
158
- rv = OCIRowidToChar(h->hp, (text*)buf, &buflen, h->errhp);
159
- if (rv != OCI_SUCCESS)
160
- oci8_raise(h->errhp, rv, NULL);
161
- return rb_str_new(buf, buflen);
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
- static void Init_OCIRowid(void)
166
- {
167
- #if defined(WIN32)
168
- HANDLE hModule = GetModuleHandle("OCI.DLL");
169
- if (hModule != NULL) {
170
- OCIRowidToChar_func = (OCIRowidToChar_func_t)GetProcAddress(hModule, "OCIRowidToChar");
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
+