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.
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
+