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,624 +1,804 @@
1
+ /* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
1
2
  /*
2
- stmt.c - part of ruby-oci8
3
- implement the methods of OCIStmt.
3
+ * stmt.c - part of ruby-oci8
4
+ * implement the methods of OCIStmt.
5
+ *
6
+ * Copyright (C) 2002-2007 KUBO Takehiro <kubo@jiubao.org>
7
+ *
8
+ */
9
+ #include "oci8.h"
4
10
 
5
- Copyright (C) 2002-2006 KUBO Takehiro <kubo@jiubao.org>
11
+ static VALUE oci8_sym_select_stmt;
12
+ static VALUE oci8_sym_update_stmt;
13
+ static VALUE oci8_sym_delete_stmt;
14
+ static VALUE oci8_sym_insert_stmt;
15
+ static VALUE oci8_sym_create_stmt;
16
+ static VALUE oci8_sym_drop_stmt;
17
+ static VALUE oci8_sym_alter_stmt;
18
+ static VALUE oci8_sym_begin_stmt;
19
+ static VALUE oci8_sym_declare_stmt;
20
+ static ID id_at_column_metadata;
21
+ static ID id_at_actual_array_size;
22
+ static ID id_at_max_array_size;
23
+ static ID id_each_value;
24
+ static ID id_at_names;
25
+ static ID id_empty_p;
26
+ static ID id_at_con;
27
+ static ID id_clear;
28
+ static ID id_set;
29
+
30
+ VALUE cOCIStmt;
31
+
32
+ typedef struct {
33
+ oci8_base_t base;
34
+ VALUE svc;
35
+ VALUE binds;
36
+ VALUE defns;
37
+ } oci8_stmt_t;
38
+
39
+ static void oci8_stmt_mark(oci8_base_t *base)
40
+ {
41
+ oci8_stmt_t *stmt = (oci8_stmt_t *)base;
42
+ rb_gc_mark(stmt->svc);
43
+ rb_gc_mark(stmt->binds);
44
+ rb_gc_mark(stmt->defns);
45
+ }
6
46
 
7
- =begin
8
- == OCIStmt
9
- Statemet handle identify a SQL or PL/SQL statement and its associated attributes.
47
+ static void oci8_stmt_free(oci8_base_t *base)
48
+ {
49
+ oci8_stmt_t *stmt = (oci8_stmt_t *)base;
50
+ stmt->svc = Qnil;
51
+ stmt->binds = Qnil;
52
+ stmt->defns = Qnil;
53
+ }
10
54
 
11
- Information about SQL or PL/SQL's input/output variables is managed by the
12
- ((<bind handle|OCIBind>)). Fetched data of select statement is managed by the
13
- ((<define handle|OCIDefine>)).
55
+ static oci8_base_class_t oci8_stmt_class = {
56
+ oci8_stmt_mark,
57
+ oci8_stmt_free,
58
+ sizeof(oci8_stmt_t),
59
+ };
14
60
 
15
- super class: ((<OCIHandle>))
61
+ static VALUE oci8_stmt_initialize(int argc, VALUE *argv, VALUE self)
62
+ {
63
+ oci8_stmt_t *stmt = DATA_PTR(self);
64
+ VALUE svc;
65
+ VALUE sql;
66
+ sword rv;
67
+
68
+ rb_scan_args(argc, argv, "11", &svc, &sql);
69
+
70
+ oci8_check_pid_consistency(oci8_get_svcctx(svc));
71
+ if (argc > 1)
72
+ OCI8SafeStringValue(sql);
73
+
74
+ rv = OCIHandleAlloc(oci8_envhp, &stmt->base.hp.ptr, OCI_HTYPE_STMT, 0, NULL);
75
+ if (rv != OCI_SUCCESS)
76
+ oci8_env_raise(oci8_envhp, rv);
77
+ stmt->base.type = OCI_HTYPE_STMT;
78
+ stmt->svc = svc;
79
+ stmt->binds = rb_hash_new();
80
+ stmt->defns = rb_ary_new();
81
+ rb_ivar_set(stmt->base.self, id_at_column_metadata, rb_ary_new());
82
+ rb_ivar_set(stmt->base.self, id_at_names, Qnil);
83
+ rb_ivar_set(stmt->base.self, id_at_con, svc);
84
+ rb_ivar_set(stmt->base.self, id_at_max_array_size, Qnil);
85
+
86
+ if (argc > 1) {
87
+ rv = OCIStmtPrepare(stmt->base.hp.stmt, oci8_errhp, RSTRING_ORATEXT(sql), RSTRING_LEN(sql), OCI_NTV_SYNTAX, OCI_DEFAULT);
88
+ if (IS_OCI_ERROR(rv)) {
89
+ oci8_raise(oci8_errhp, rv, stmt->base.hp.stmt);
90
+ }
91
+ }
92
+ oci8_link_to_parent((oci8_base_t*)stmt, (oci8_base_t*)DATA_PTR(svc));
93
+ return Qnil;
94
+ }
16
95
 
17
- correspond native OCI datatype: ((|OCIStmt|))
18
- =end
19
- */
20
- #include "oci8.h"
96
+ static VALUE oci8_define_by_pos(VALUE self, VALUE vposition, VALUE vbindobj)
97
+ {
98
+ oci8_stmt_t *stmt = DATA_PTR(self);
99
+ ub4 position;
100
+ oci8_bind_t *obind;
101
+ const oci8_bind_class_t *bind_class;
102
+ sword status;
103
+ ub4 mode;
104
+
105
+ position = NUM2INT(vposition); /* 1 */
106
+ obind = oci8_get_bind(vbindobj); /* 2 */
107
+ if (obind->base.hp.dfn != NULL) {
108
+ oci8_base_free(&obind->base); /* TODO: OK? */
109
+ }
110
+ bind_class = (const oci8_bind_class_t *)obind->base.klass;
111
+ if (bind_class->out == NULL) {
112
+ mode = OCI_DEFAULT;
113
+ } else {
114
+ mode = OCI_DYNAMIC_FETCH;
115
+ }
116
+ status = OCIDefineByPos(stmt->base.hp.stmt, &obind->base.hp.dfn, oci8_errhp, position, obind->valuep, obind->value_sz, bind_class->dty, NIL_P(obind->tdo) ? obind->u.inds : NULL, NULL, 0, mode);
117
+ if (status != OCI_SUCCESS) {
118
+ oci8_raise(oci8_errhp, status, stmt->base.hp.ptr);
119
+ }
120
+ obind->base.type = OCI_HTYPE_DEFINE;
121
+ if (NIL_P(obind->tdo) && obind->maxar_sz > 0) {
122
+ oci_lc(OCIDefineArrayOfStruct(obind->base.hp.dfn, oci8_errhp, obind->alloc_sz, sizeof(sb2), 0, 0));
123
+ }
124
+ if (RTEST(obind->tdo)) {
125
+ oci8_base_t *tdo = DATA_PTR(obind->tdo);
126
+ oci_lc(OCIDefineObject(obind->base.hp.dfn, oci8_errhp, tdo->hp.tdo,
127
+ obind->valuep, 0, obind->u.null_structs, 0));
128
+ }
129
+ if (position - 1 < RARRAY_LEN(stmt->defns)) {
130
+ VALUE old_value = RARRAY_PTR(stmt->defns)[position - 1];
131
+ if (!NIL_P(old_value)) {
132
+ oci8_base_free((oci8_base_t*)oci8_get_bind(old_value));
133
+ }
134
+ }
135
+ if (bind_class->csfrm != 0) {
136
+ oci_lc(OCIAttrSet(obind->base.hp.ptr, OCI_HTYPE_DEFINE, (void*)&bind_class->csfrm, 0, OCI_ATTR_CHARSET_FORM, oci8_errhp));
137
+ }
138
+ rb_ary_store(stmt->defns, position - 1, obind->base.self);
139
+ oci8_unlink_from_parent((oci8_base_t*)obind);
140
+ oci8_link_to_parent((oci8_base_t*)obind, (oci8_base_t*)stmt);
141
+ return obind->base.self;
142
+ }
21
143
 
22
- static ID id_alloc;
144
+ static VALUE oci8_bind(VALUE self, VALUE vplaceholder, VALUE vbindobj)
145
+ {
146
+ oci8_stmt_t *stmt = DATA_PTR(self);
147
+ char *placeholder_ptr = (char*)-1; /* initialize as an invalid value */
148
+ ub4 placeholder_len = 0;
149
+ ub4 position = 0;
150
+ oci8_bind_t *obind;
151
+ const oci8_bind_class_t *bind_class;
152
+ sword status;
153
+ VALUE old_value;
154
+ void *indp;
155
+ ub4 *curelep;
156
+ ub4 mode;
157
+
158
+ if (NIL_P(vplaceholder)) { /* 1 */
159
+ placeholder_ptr = NULL;
160
+ placeholder_len = 0;
161
+ } else if (SYMBOL_P(vplaceholder)) {
162
+ const char *symname = rb_id2name(SYM2ID(vplaceholder));
163
+ size_t len = strlen(symname);
164
+ placeholder_ptr = ALLOCA_N(char, len + 1);
165
+ placeholder_len = len + 1;
166
+ placeholder_ptr[0] = ':';
167
+ memcpy(placeholder_ptr + 1, symname, len);
168
+ } else if (FIXNUM_P(vplaceholder)) {
169
+ position = NUM2INT(vplaceholder);
170
+ } else {
171
+ OCI8StringValue(vplaceholder);
172
+ placeholder_ptr = RSTRING_PTR(vplaceholder);
173
+ placeholder_len = RSTRING_LEN(vplaceholder);
174
+ }
175
+ obind = oci8_get_bind(vbindobj); /* 2 */
176
+ if (obind->base.hp.bnd != NULL) {
177
+ oci8_base_free(&obind->base); /* TODO: OK? */
178
+ }
179
+ bind_class = (const oci8_bind_class_t *)obind->base.klass;
180
+ if (bind_class->in != NULL || bind_class->out != NULL) {
181
+ mode = OCI_DATA_AT_EXEC;
182
+ } else {
183
+ mode = OCI_DEFAULT;
184
+ }
23
185
 
24
- static void check_bind_type(ub4 type, oci8_handle_t *stmth, VALUE vtype, VALUE vlength, oci8_bind_handle_t **bhp, ub2 *dty)
186
+ indp = NIL_P(obind->tdo) ? obind->u.inds : NULL;
187
+ if (obind->maxar_sz == 0) {
188
+ curelep = NULL;
189
+ } else {
190
+ curelep = &obind->curar_sz;
191
+ }
192
+ if (placeholder_ptr == (char*)-1) {
193
+ status = OCIBindByPos(stmt->base.hp.stmt, &obind->base.hp.bnd, oci8_errhp, position, obind->valuep, obind->value_sz, bind_class->dty, indp, NULL, 0, 0, 0, mode);
194
+ } else {
195
+ status = OCIBindByName(stmt->base.hp.stmt, &obind->base.hp.bnd, oci8_errhp, TO_ORATEXT(placeholder_ptr), placeholder_len, obind->valuep, obind->value_sz, bind_class->dty, indp, NULL, 0, 0, 0, mode);
196
+ }
197
+ if (status != OCI_SUCCESS) {
198
+ oci8_raise(oci8_errhp, status, stmt->base.hp.stmt);
199
+ }
200
+ obind->base.type = OCI_HTYPE_BIND;
201
+ if (NIL_P(obind->tdo) && obind->maxar_sz > 0) {
202
+ oci_lc(OCIBindArrayOfStruct(obind->base.hp.bnd, oci8_errhp, obind->alloc_sz, sizeof(sb2), 0, 0));
203
+ }
204
+ if (!NIL_P(obind->tdo)) {
205
+ oci8_base_t *tdo = DATA_PTR(obind->tdo);
206
+ oci_lc(OCIBindObject(obind->base.hp.bnd, oci8_errhp, tdo->hp.tdo,
207
+ obind->valuep, 0, obind->u.null_structs, 0));
208
+ }
209
+ if (bind_class->csfrm != 0) {
210
+ oci_lc(OCIAttrSet(obind->base.hp.ptr, OCI_HTYPE_BIND, (void*)&bind_class->csfrm, 0, OCI_ATTR_CHARSET_FORM, oci8_errhp));
211
+ }
212
+ old_value = rb_hash_aref(stmt->binds, vplaceholder);
213
+ if (!NIL_P(old_value)) {
214
+ oci8_base_free((oci8_base_t*)oci8_get_bind(old_value));
215
+ }
216
+ rb_hash_aset(stmt->binds, vplaceholder, obind->base.self);
217
+ oci8_unlink_from_parent((oci8_base_t*)obind);
218
+ oci8_link_to_parent((oci8_base_t*)obind, (oci8_base_t*)stmt);
219
+ return obind->base.self;
220
+ }
221
+
222
+ static sword oci8_call_stmt_execute(oci8_svcctx_t *svcctx, oci8_stmt_t *stmt, ub4 iters, ub4 mode)
25
223
  {
26
- enum oci8_bind_type bind_type;
27
- oci8_bind_handle_t *bh;
28
- sb4 value_sz;
29
- VALUE klass = Qnil;
30
-
31
- if (TYPE(vtype) == T_FIXNUM) {
32
- switch (FIX2INT(vtype)) {
33
- case SQLT_CHR: /* OCI_TYPECODE_VARCHAR */
34
- bind_type = BIND_STRING;
35
- *dty = SQLT_LVC;
36
- if (NIL_P(vlength))
37
- rb_raise(rb_eArgError, "the length of String is not specified.");
38
- value_sz = NUM2INT(vlength) + 4;
39
- if (value_sz < 5)
40
- value_sz = 5; /* at least 5 bytes */
41
- break;
42
- case SQLT_LVB: /* OCI_TYPECODE_RAW */
43
- case SQLT_BIN: /* OCI_TYPECODE_UNSIGNED8 */
44
- bind_type = BIND_STRING;
45
- *dty = SQLT_LVB;
46
- if (NIL_P(vlength))
47
- rb_raise(rb_eArgError, "the length of String is not specified.");
48
- value_sz = NUM2INT(vlength) + 4;
49
- if (value_sz < 5)
50
- value_sz = 5; /* at least 5 bytes */
51
- break;
52
- case SQLT_DAT:
53
- bind_type = BIND_ORA_DATE;
54
- *dty = SQLT_DAT;
55
- value_sz = sizeof(ora_date_t);
56
- break;
57
- case SQLT_CLOB: /* OCI_TYPECODE_CLOB */
58
- case SQLT_BLOB: /* OCI_TYPECODE_BLOB */
59
- bind_type = BIND_HANDLE;
60
- *dty = FIX2INT(vtype);
61
- value_sz = sizeof(bh->value.handle);
62
- klass = cOCILobLocator;
63
- break;
64
- case SQLT_BFILE:
65
- case SQLT_CFILE:
66
- bind_type = BIND_HANDLE;
67
- *dty = FIX2INT(vtype);
68
- value_sz = sizeof(bh->value.handle);
69
- klass = cOCIFileLocator;
70
- break;
71
- case SQLT_RDD:
72
- bind_type = BIND_HANDLE;
73
- *dty = SQLT_RDD;
74
- value_sz = sizeof(bh->value.handle);
75
- klass = cOCIRowid;
76
- break;
77
- case SQLT_RSET:
78
- bind_type = BIND_HANDLE;
79
- *dty = SQLT_RSET;
80
- value_sz = sizeof(bh->value.handle);
81
- klass = cOCIStmt;
82
- break;
83
- #ifdef SQLT_IBDOUBLE
84
- case SQLT_IBDOUBLE:
85
- bind_type = BIND_FLOAT;
86
- *dty = SQLT_BDOUBLE;
87
- value_sz = sizeof(double);
88
- break;
89
- #endif
90
- default:
91
- rb_raise(rb_eArgError, "Not supported type (%d)", FIX2INT(vtype));
92
- }
93
- } else if (vtype == rb_cFixnum) {
94
- bind_type = BIND_FIXNUM;
95
- *dty = SQLT_INT;
96
- value_sz = sizeof(long);
97
- } else if (vtype == rb_cInteger || vtype == rb_cBignum) {
98
- bind_type = BIND_INTEGER_VIA_ORA_NUMBER;
99
- *dty = SQLT_NUM;
100
- value_sz = sizeof(ora_number_t);
101
- } else if (vtype == rb_cTime) {
102
- bind_type = BIND_TIME_VIA_ORA_DATE;
103
- *dty = SQLT_DAT;
104
- value_sz = sizeof(ora_date_t);
105
- } else if (vtype == rb_cString) {
106
- bind_type = BIND_STRING;
107
- *dty = SQLT_LVC;
108
- if (NIL_P(vlength))
109
- rb_raise(rb_eArgError, "the length of String is not specified.");
110
- value_sz = NUM2INT(vlength) + 4;
111
- if (value_sz < 5)
112
- value_sz = 5; /* at least 5 bytes */
113
- } else if (vtype == rb_cFloat) {
114
- bind_type = BIND_FLOAT;
115
- *dty = SQLT_FLT;
116
- value_sz = sizeof(double);
117
- } else if (vtype == cOraDate) {
118
- bind_type = BIND_ORA_DATE;
119
- *dty = SQLT_DAT;
120
- value_sz = sizeof(ora_date_t);
121
- } else if (vtype == cOraNumber) {
122
- bind_type = BIND_ORA_NUMBER;
123
- *dty = SQLT_NUM;
124
- value_sz = sizeof(ora_number_t);
125
- } else {
126
- if (SYMBOL_P(vtype)) {
127
- rb_raise(rb_eArgError, "Not supported type (:%s)", rb_id2name(SYM2ID(vtype)));
224
+ sword rv;
225
+
226
+ rv = OCIStmtExecute_nb(svcctx, svcctx->base.hp.svc, stmt->base.hp.stmt, oci8_errhp, iters, 0, NULL, NULL, mode);
227
+ if (rv == OCI_ERROR) {
228
+ if (oci8_get_error_code(oci8_errhp) == 1000) {
229
+ /* run GC to close unreferred cursors
230
+ * when ORA-01000 (maximum open cursors exceeded).
231
+ */
232
+ rb_gc();
233
+ rv = OCIStmtExecute_nb(svcctx, svcctx->base.hp.svc, stmt->base.hp.stmt, oci8_errhp, iters, 0, NULL, NULL, mode);
234
+ }
235
+ }
236
+ return rv;
237
+ }
238
+
239
+ static VALUE oci8_stmt_execute(VALUE self, VALUE iteration_count)
240
+ {
241
+ oci8_stmt_t *stmt = DATA_PTR(self);
242
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(stmt->svc);
243
+ ub4 iters;
244
+ ub4 mode;
245
+ sword rv;
246
+
247
+ if (oci8_get_ub2_attr(&stmt->base, OCI_ATTR_STMT_TYPE) == INT2FIX(OCI_STMT_SELECT)) {
248
+ iters = 0;
249
+ mode = OCI_DEFAULT;
128
250
  } else {
129
- rb_raise(rb_eArgError, "Not supported type (%s)", rb_class2name(vtype));
130
- }
131
- }
132
- bh = (oci8_bind_handle_t *)oci8_make_handle(type, NULL, NULL, stmth, value_sz);
133
- bh->bind_type = bind_type;
134
- if (bind_type == BIND_HANDLE) {
135
- if (NIL_P(vlength)) {
136
- oci8_handle_t *envh;
137
- for (envh = stmth; envh->type != OCI_HTYPE_ENV; envh = envh->parent);
138
- vlength = rb_funcall(envh->self, id_alloc, 1, klass);
139
- }
140
- bh->value.handle.klass = klass;
141
- oci8_set_value(bh, vlength);
142
- }
143
- *bhp = bh;
251
+ if(!NIL_P(iteration_count))
252
+ iters = NUM2INT(iteration_count);
253
+ else
254
+ iters = 1;
255
+ mode = svcctx->is_autocommit ? OCI_COMMIT_ON_SUCCESS : OCI_DEFAULT;
256
+ }
257
+ rv = oci8_call_stmt_execute(svcctx, stmt, iters, mode);
258
+ #ifdef USE_DYNAMIC_FETCH
259
+ while (rv == OCI_NEED_DATA) {
260
+ oci8_bind_t *obind;
261
+ const oci8_bind_class_t *bind_class;
262
+ /* get piece info. */
263
+ dvoid *hp;
264
+ ub4 type;
265
+ ub1 in_out;
266
+ ub4 iter;
267
+ ub4 idx;
268
+ ub1 piece;
269
+ /* set piece info. */
270
+ void *valuep;
271
+ ub4 *alenp;
272
+ void *indp;
273
+
274
+ oci_lc(OCIStmtGetPieceInfo(stmt->base.hp.ptr, oci8_errhp, &hp, &type, &in_out, &iter, &idx, &piece));
275
+ obind = (oci8_bind_t*)stmt->base.children;
276
+ do {
277
+ if (obind->base.hp.ptr == hp) {
278
+ if (type != OCI_HTYPE_BIND)
279
+ rb_bug("ruby-oci8: expect OCI_HTYPE_BIND but %d", type);
280
+ bind_class = (const oci8_bind_class_t *)obind->base.klass;
281
+ switch (in_out) {
282
+ case OCI_PARAM_IN:
283
+ if (bind_class->in == NULL)
284
+ rb_bug("....");
285
+ piece = bind_class->in(obind, idx, piece, &valuep, &alenp, &indp);
286
+ break;
287
+ case OCI_PARAM_OUT:
288
+ if (bind_class->out == NULL)
289
+ rb_bug("....");
290
+ bind_class->out(obind, idx, piece, &valuep, &alenp, &indp);
291
+ break;
292
+ default:
293
+ rb_bug("ruby-oci8: expect OCI_PARAM_IN or OCI_PARAM_OUT but %d", in_out);
294
+ }
295
+ oci_lc(OCIStmtSetPieceInfo(obind->base.hp.ptr, OCI_HTYPE_BIND, oci8_errhp, valuep, alenp, 0, indp, NULL));
296
+ break;
297
+ }
298
+ obind = (oci8_bind_t*)obind->base.next;
299
+ } while (obind != (oci8_bind_t*)stmt->base.children);
300
+ if (obind == (oci8_bind_t*)stmt) {
301
+ rb_bug("ruby-oci8: No bind handle is found.");
302
+ }
303
+ rv = oci8_call_stmt_execute(svcctx, stmt, iters, mode);
304
+ }
305
+ #endif /* USE_DYNAMIC_FETCH */
306
+ if (IS_OCI_ERROR(rv)) {
307
+ oci8_raise(oci8_errhp, rv, stmt->base.hp.stmt);
308
+ }
309
+ return self;
310
+ }
311
+
312
+ static VALUE each_value(VALUE obj)
313
+ {
314
+ return rb_funcall(obj, id_each_value, 0);
315
+ }
316
+
317
+ static VALUE clear_binds_iterator_proc(VALUE val, VALUE arg)
318
+ {
319
+ if(!NIL_P(val)) {
320
+ oci8_base_free((oci8_base_t*)oci8_get_bind(val));
321
+ }
322
+ return Qnil;
144
323
  }
145
324
 
146
- static VALUE oci8_each_value(VALUE hash)
325
+ static VALUE oci8_stmt_clear_binds(VALUE self)
147
326
  {
148
- return rb_funcall(hash, rb_intern("each_value"), 0);
327
+ oci8_stmt_t *stmt = DATA_PTR(self);
328
+
329
+ if(!RTEST(rb_funcall(stmt->binds, id_empty_p, 0)))
330
+ {
331
+ rb_iterate(each_value, stmt->binds, clear_binds_iterator_proc, Qnil);
332
+ rb_funcall(stmt->binds,id_clear,0);
333
+ }
334
+
335
+ return self;
336
+ }
337
+
338
+ static VALUE oci8_stmt_do_fetch(oci8_stmt_t *stmt, oci8_svcctx_t *svcctx)
339
+ {
340
+ VALUE ary;
341
+ sword rv;
342
+ long idx;
343
+ oci8_bind_t *obind;
344
+ const oci8_bind_class_t *bind_class;
345
+
346
+ obind = (oci8_bind_t *)stmt->base.children;
347
+ do {
348
+ if (obind->base.type == OCI_HTYPE_DEFINE) {
349
+ bind_class = (const oci8_bind_class_t *)obind->base.klass;
350
+ if (bind_class->pre_fetch_hook != NULL) {
351
+ bind_class->pre_fetch_hook(obind, stmt->svc);
352
+ }
353
+ }
354
+ obind = (oci8_bind_t *)obind->base.next;
355
+ } while (obind != (oci8_bind_t*)stmt->base.children);
356
+ rv = OCIStmtFetch_nb(svcctx, stmt->base.hp.stmt, oci8_errhp, 1, OCI_FETCH_NEXT, OCI_DEFAULT);
357
+ #ifdef USE_DYNAMIC_FETCH
358
+ while (rv == OCI_NEED_DATA) {
359
+ /* get piece info. */
360
+ dvoid *hp;
361
+ ub4 type;
362
+ ub1 in_out;
363
+ ub4 iter;
364
+ ub4 idx;
365
+ ub1 piece;
366
+ /* set piece info. */
367
+ void *valuep;
368
+ ub4 *alenp;
369
+ void *indp;
370
+
371
+ oci_lc(OCIStmtGetPieceInfo(stmt->base.hp.ptr, oci8_errhp, &hp, &type, &in_out, &iter, &idx, &piece));
372
+ obind = (oci8_bind_t *)stmt->base.children;
373
+ do {
374
+ if (obind->base.hp.ptr == hp) {
375
+ if (type != OCI_HTYPE_DEFINE)
376
+ rb_bug("ruby-oci8: expect OCI_HTYPE_DEFINE but %d", type);
377
+ bind_class = (const oci8_bind_class_t *)obind->base.klass;
378
+ switch (in_out) {
379
+ case OCI_PARAM_OUT:
380
+ if (bind_class->out == NULL)
381
+ rb_bug("....");
382
+ bind_class->out(obind, idx, piece, &valuep, &alenp, &indp);
383
+ break;
384
+ default:
385
+ rb_bug("ruby-oci8: expect OCI_PARAM_OUT but %d", in_out);
386
+ }
387
+ oci_lc(OCIStmtSetPieceInfo(obind->base.hp.ptr, OCI_HTYPE_DEFINE, oci8_errhp, valuep, alenp, 0, indp, NULL));
388
+ break;
389
+ }
390
+ obind = (oci8_bind_t *)obind->base.next;
391
+ } while (obind != (oci8_bind_t*)stmt->base.children);
392
+ if (obind == (oci8_bind_t*)stmt) {
393
+ rb_bug("ruby-oci8: No define handle is found.");
394
+ }
395
+ rv = OCIStmtFetch_nb(svcctx, stmt->base.hp.stmt, oci8_errhp, 1, OCI_FETCH_NEXT, OCI_DEFAULT);
396
+ }
397
+ #endif /* USE_DYNAMIC_FETCH */
398
+ if (rv == OCI_NO_DATA) {
399
+ return Qnil;
400
+ }
401
+ if (IS_OCI_ERROR(rv)) {
402
+ oci8_raise(oci8_errhp, rv, stmt->base.hp.stmt);
403
+ }
404
+ #ifdef USE_DYNAMIC_FETCH
405
+ obind = (oci8_bind_t *)stmt->base.children;
406
+ do {
407
+ /* set piece info. */
408
+ void *valuep;
409
+ ub4 *alenp;
410
+ void *indp;
411
+ ub1 piece = OCI_LAST_PIECE;
412
+
413
+ if (obind->base.type == OCI_HTYPE_DEFINE) {
414
+ bind_class = (const oci8_bind_class_t *)obind->base.klass;
415
+ if (bind_class->out != NULL) {
416
+ if (obind->maxar_sz == 0) {
417
+ bind_class->out(obind, 0, piece, &valuep, &alenp, &indp);
418
+ } else {
419
+ ub4 idx;
420
+ for (idx = 0; idx < obind->curar_sz; idx++) {
421
+ bind_class->out(obind, idx, piece, &valuep, &alenp, &indp);
422
+ }
423
+ }
424
+ }
425
+ }
426
+ obind = (oci8_bind_t *)obind->base.next;
427
+ } while (obind != (oci8_bind_t*)stmt->base.children);
428
+ #endif /* USE_DYNAMIC_FETCH */
429
+ ary = rb_ary_new2(RARRAY_LEN(stmt->defns));
430
+ for (idx = 0; idx < RARRAY_LEN(stmt->defns); idx++) {
431
+ rb_ary_store(ary, idx, rb_funcall(RARRAY_PTR(stmt->defns)[idx], oci8_id_get, 0));
432
+ }
433
+ return ary;
149
434
  }
150
435
 
151
436
  /*
152
- =begin
153
- --- OCIStmt#prepare(stmt [, language [, mode]])
154
- set and prepare SQL statement.
155
-
156
- :stmt
157
- SQL or PL/SQL statement
158
- :language
159
- ((|OCI_NTV_SYNTAX|)), ((|OCI_V7_SYNTAX|)), or ((|OCI_V8_SYNTAX|)).
160
- Default value is ((|OCI_NTV_SYNTAX|))
161
- :mode
162
- ((|OCI_DEFAULT|)) or ((|OCI_NO_SHARING|)). Default value is ((|OCI_DEFAULT|)).
163
-
164
- ((|OCI_NO_SHARING|)) disables ((<Shared Data Mode>)) for this statement.
165
-
166
- correspond native OCI function: ((|OCIStmtPrepare|))
167
- =end
437
+ * Gets fetched data as array. This is available for select
438
+ * statement only.
439
+ *
440
+ * example:
441
+ * conn = OCI8.new('scott', 'tiger')
442
+ * cursor = conn.exec('SELECT * FROM emp')
443
+ * while r = cursor.fetch()
444
+ * puts r.join(',')
445
+ * end
446
+ * cursor.close
447
+ * conn.logoff
168
448
  */
169
- static VALUE oci8_stmt_prepare(int argc, VALUE *argv, VALUE self)
449
+ static VALUE oci8_stmt_fetch(VALUE self)
450
+ {
451
+ oci8_stmt_t *stmt = DATA_PTR(self);
452
+ oci8_svcctx_t *svcctx = oci8_get_svcctx(stmt->svc);
453
+
454
+ if (rb_block_given_p()) {
455
+ for (;;) {
456
+ VALUE rs = oci8_stmt_do_fetch(stmt, svcctx);
457
+ if (NIL_P(rs))
458
+ return self; /* NEED TO CHECK 0.1 behavior. */
459
+ rb_yield(rs);
460
+ }
461
+ } else {
462
+ return oci8_stmt_do_fetch(stmt, svcctx);
463
+ }
464
+ }
465
+
466
+ static VALUE oci8_stmt_get_param(VALUE self, VALUE pos)
170
467
  {
171
- VALUE vsql, vlanguage, vmode;
172
- oci8_handle_t *h;
173
- oci8_string_t s;
174
- ub4 language;
175
- ub4 mode;
176
- sword rv;
177
- VALUE ary;
178
- VALUE hash;
179
- int i;
180
-
181
- rb_scan_args(argc, argv, "12", &vsql, &vlanguage, &vmode);
182
- Get_Handle(self, h); /* 0 */
183
- Get_String(vsql, s); /* 1 */
184
- Get_Int_With_Default(argc, 2, vlanguage, language, OCI_NTV_SYNTAX); /* 2 */
185
- Get_Int_With_Default(argc, 3, vmode, mode, OCI_DEFAULT); /* 3 */
186
-
187
- /* when a new statement is prepared, OCI implicitly free the previous
188
- * statement's define and bind handles.
189
- * But ruby's object don't know it. So free these handles in advance.
190
- */
191
- /* free define handles */
192
- ary = rb_ivar_get(self, oci8_id_define_array);
193
- if (ary != Qnil) {
194
- for (i = 0;i < RARRAY_LEN(ary);i++) {
195
- if (RARRAY_PTR(ary)[i] != Qnil)
196
- oci8_handle_free(RARRAY_PTR(ary)[i]);
197
- }
198
- rb_ivar_set(self, oci8_id_define_array, Qnil);
199
- }
200
- /* free bind handles */
201
- hash = rb_ivar_get(self, oci8_id_bind_hash);
202
- if (hash != Qnil) {
203
- rb_iterate(oci8_each_value, hash, oci8_handle_free, Qnil);
204
- rb_ivar_set(self, oci8_id_bind_hash, Qnil);
205
- }
206
-
207
- rv = OCIStmtPrepare(h->hp, h->errhp, s.ptr, s.len, language, mode);
208
- if (IS_OCI_ERROR(rv)) {
209
- oci8_raise(h->errhp, rv, h->hp);
210
- }
211
- return self;
468
+ oci8_stmt_t *stmt = DATA_PTR(self);
469
+ OCIParam *parmhp = NULL;
470
+ sword rv;
471
+
472
+ Check_Type(pos, T_FIXNUM); /* 1 */
473
+ rv = OCIParamGet(stmt->base.hp.stmt, OCI_HTYPE_STMT, oci8_errhp, (dvoid *)&parmhp, FIX2INT(pos));
474
+ if (rv != OCI_SUCCESS) {
475
+ oci8_raise(oci8_errhp, rv, NULL);
476
+ }
477
+ return oci8_metadata_create(parmhp, stmt->svc, self);
212
478
  }
213
479
 
214
480
  /*
215
- =begin
216
- --- OCIStmt#defineByPos(position, type [, length [, mode]])
217
- define the datatype of fetched column.
218
- You must define all column's datatype, before you fetch data.
219
-
220
- :position
221
- the position of the column. It starts from 1.
222
- :type
223
- the type of column.
224
- ((|String|)), ((|Fixnum|)), ((|Integer|)), ((|Float|)), ((|Time|)),
225
- ((<OraDate>)), ((<OraNumber>)), or ((|OCI_TYPECODE_RAW|))
226
- :length
227
- When the 2nd argument is
228
- * ((|String|)) or ((|OCI_TYPECODE_RAW|)),
229
- the max length of fetched data.
230
- * otherwise,
231
- its value is ignored.
232
- :mode
233
- ((|OCI_DEFAULT|)), or ((|OCI_DYNAMIC_FETCH|)). But now available value is
234
- ((|OCI_DEFAULT|)) only. Default value is ((|OCI_DEFAULT|))
235
- :return value
236
- newly created ((<define handle|OCIDefine>))
237
-
238
- correspond native OCI function: ((|OCIDefineByPos|))
239
- =end
481
+ * gets the type of SQL statement as follows.
482
+ * * OCI8::STMT_SELECT
483
+ * * OCI8::STMT_UPDATE
484
+ * * OCI8::STMT_DELETE
485
+ * * OCI8::STMT_INSERT
486
+ * * OCI8::STMT_CREATE
487
+ * * OCI8::STMT_DROP
488
+ * * OCI8::STMT_ALTER
489
+ * * OCI8::STMT_BEGIN (PL/SQL block which starts with a BEGIN keyword)
490
+ * * OCI8::STMT_DECLARE (PL/SQL block which starts with a DECLARE keyword)
491
+ * * Other Fixnum value undocumented in Oracle manuals.
492
+ *
493
+ * <em>Changes between ruby-oci8 1.0 and 2.0.</em>
494
+ *
495
+ * [ruby-oci8 2.0] OCI8::STMT_* are Symbols. (:select_stmt, :update_stmt, etc.)
496
+ * [ruby-oci8 1.0] OCI8::STMT_* are Fixnums. (1, 2, 3, etc.)
240
497
  */
241
- static VALUE oci8_define_by_pos(int argc, VALUE *argv, VALUE self)
498
+ static VALUE oci8_stmt_get_stmt_type(VALUE self)
242
499
  {
243
- VALUE vposition;
244
- VALUE vtype;
245
- VALUE vlength;
246
- VALUE vmode;
247
- oci8_handle_t *h;
248
- ub4 position;
249
- oci8_bind_handle_t *bh;
250
- ub2 dty;
251
- ub4 mode;
252
- dvoid *indp;
253
- ub2 *rlenp;
254
- dvoid *valuep;
255
- OCIDefine *dfnhp = NULL;
256
- sword status;
257
- VALUE ary;
258
- VALUE obj;
259
-
260
- rb_scan_args(argc, argv, "22", &vposition, &vtype, &vlength, &vmode);
261
- Get_Handle(self, h); /* 0 */
262
- position = NUM2INT(vposition); /* 1 */
263
- check_bind_type(OCI_HTYPE_DEFINE, h, vtype, vlength, &bh, &dty); /* 2, 3 */
264
- Get_Int_With_Default(argc, 4, vmode, mode, OCI_DEFAULT); /* 4 */
265
-
266
- if (mode & OCI_DYNAMIC_FETCH) {
267
- indp = NULL;
268
- rlenp = NULL;
269
- } else {
270
- indp = &(bh->ind);
271
- rlenp = (bh->bind_type == BIND_STRING) ? NULL : &bh->rlen;
272
- }
273
- valuep = &bh->value;
274
- status = OCIDefineByPos(h->hp, &dfnhp, h->errhp, position, valuep, bh->value_sz, dty, indp, rlenp, 0, mode);
275
- if (status != OCI_SUCCESS) {
276
- oci8_unlink((oci8_handle_t *)bh);
277
- bh->type = 0;
278
- oci8_raise(h->errhp, status, h->hp);
279
- }
280
- bh->type = OCI_HTYPE_DEFINE;
281
- bh->hp = dfnhp;
282
- bh->errhp = h->errhp;
283
- obj = bh->self;
284
- ary = rb_ivar_get(self, oci8_id_define_array);
285
- if (ary == Qnil) {
286
- ary = rb_ary_new();
287
- rb_ivar_set(self, oci8_id_define_array, ary);
288
- }
289
- rb_ary_store(ary, position - 1, obj);
290
- return obj;
500
+ VALUE stmt_type = oci8_get_ub2_attr(DATA_PTR(self), OCI_ATTR_STMT_TYPE);
501
+ switch (FIX2INT(stmt_type)) {
502
+ case OCI_STMT_SELECT:
503
+ return oci8_sym_select_stmt;
504
+ case OCI_STMT_UPDATE:
505
+ return oci8_sym_update_stmt;
506
+ case OCI_STMT_DELETE:
507
+ return oci8_sym_delete_stmt;
508
+ case OCI_STMT_INSERT:
509
+ return oci8_sym_insert_stmt;
510
+ case OCI_STMT_CREATE:
511
+ return oci8_sym_create_stmt;
512
+ case OCI_STMT_DROP:
513
+ return oci8_sym_drop_stmt;
514
+ case OCI_STMT_ALTER:
515
+ return oci8_sym_alter_stmt;
516
+ case OCI_STMT_BEGIN:
517
+ return oci8_sym_begin_stmt;
518
+ case OCI_STMT_DECLARE:
519
+ return oci8_sym_declare_stmt;
520
+ default:
521
+ return stmt_type;
522
+ }
291
523
  }
292
524
 
293
525
  /*
294
- =begin
295
- --- OCIStmt#bindByPos(position, type [, length [, mode]])
296
- define the datatype of the bind variable by posision.
297
-
298
- :position
299
- the position of the bind variable.
300
- :type
301
- the type of the bind variable.
302
- ((|String|)), ((|Fixnum|)), ((|Integer|)), ((|Float|)), ((|Time|)),
303
- ((<OraDate>)), ((<OraNumber>)), or ((|OCI_TYPECODE_RAW|))
304
- :length
305
- When the 2nd argument is
306
- * ((|String|)) or ((|OCI_TYPECODE_RAW|)),
307
- the max length of fetched data.
308
- * otherwise,
309
- its value is ignored.
310
- :mode
311
- ((|OCI_DEFAULT|)), or ((|OCI_DATA_AT_EXEC|)). But now available value is
312
- ((|OCI_DEFAULT|)) only. Default value is ((|OCI_DEFAULT|))
313
- :return value
314
- newly created ((<bind handle|OCIBind>))
315
-
316
- correspond native OCI function: ((|OCIBindByPos|))
317
- =end
526
+ * Returns the number of processed rows.
318
527
  */
319
- static VALUE oci8_bind_by_pos(int argc, VALUE *argv, VALUE self)
528
+ static VALUE oci8_stmt_get_row_count(VALUE self)
320
529
  {
321
- VALUE vposition;
322
- VALUE vtype;
323
- VALUE vlength;
324
- VALUE vmode;
325
- oci8_handle_t *h;
326
- ub4 position;
327
- oci8_bind_handle_t *bh;
328
- ub2 dty;
329
- ub4 mode;
330
- dvoid *indp;
331
- ub2 *rlenp;
332
- dvoid *valuep;
333
- OCIBind *bindhp = NULL;
334
- sword status;
335
- VALUE hash;
336
- VALUE obj;
337
-
338
- rb_scan_args(argc, argv, "22", &vposition, &vtype, &vlength, &vmode);
339
- Get_Handle(self, h); /* 0 */
340
- position = NUM2INT(vposition); /* 1 */
341
- check_bind_type(OCI_HTYPE_BIND, h, vtype, vlength, &bh, &dty); /* 2, 3 */
342
- Get_Int_With_Default(argc, 4, vmode, mode, OCI_DEFAULT); /* 4 */
343
-
344
- if (mode & OCI_DATA_AT_EXEC) {
345
- indp = NULL;
346
- rlenp = NULL;
347
- } else {
348
- indp = &(bh->ind);
349
- rlenp = (bh->bind_type == BIND_STRING) ? NULL : &bh->rlen;
350
- }
351
- valuep = &bh->value;
352
- status = OCIBindByPos(h->hp, &bindhp, h->errhp, position, valuep, bh->value_sz, dty, indp, rlenp, 0, 0, 0, mode);
353
- if (status != OCI_SUCCESS) {
354
- oci8_unlink((oci8_handle_t *)bh);
355
- bh->type = 0;
356
- oci8_raise(h->errhp, status, h->hp);
357
- }
358
- bh->type = OCI_HTYPE_BIND;
359
- bh->hp = bindhp;
360
- bh->errhp = h->errhp;
361
- obj = bh->self;
362
- hash = rb_ivar_get(self, oci8_id_bind_hash);
363
- if (hash == Qnil) {
364
- hash = rb_hash_new();
365
- rb_ivar_set(self, oci8_id_bind_hash, hash);
366
- }
367
- rb_hash_aset(hash, vposition, obj);
368
- return obj;
530
+ return oci8_get_ub4_attr(DATA_PTR(self), OCI_ATTR_ROW_COUNT);
369
531
  }
370
532
 
371
533
  /*
372
- =begin
373
- --- OCIStmt#bindByName(name, type [, length [, mode]])
374
- define the datatype of the bind variable by name.
375
-
376
- :name
377
- the name of the bind variable including colon.
378
- :type
379
- the type of the bind variable.
380
- ((|String|)), ((|Fixnum|)), ((|Integer|)), ((|Float|)), ((|Time|)),
381
- ((<OraDate>)), ((<OraNumber>)), or ((|OCI_TYPECODE_RAW|))
382
- :length
383
- When the 2nd argument is
384
- * ((|String|)) or ((|OCI_TYPECODE_RAW|)),
385
- the max length of fetched data.
386
- * otherwise,
387
- its value is ignored.
388
- :mode
389
- ((|OCI_DEFAULT|)), or ((|OCI_DATA_AT_EXEC|)). But now available value is
390
- ((|OCI_DEFAULT|)) only. Default value is ((|OCI_DEFAULT|))
391
- :return value
392
- newly created ((<bind handle|OCIBind>))
393
-
394
- for example
395
- stmt = env.alloc(OCIStmt)
396
- stmt.prepare("SELECT * FROM EMP
397
- WHERE ename = :ENAME
398
- AND sal > :SAL
399
- AND hiredate >= :HIREDATE")
400
- b_ename = stmt.bindByName(":ENAME", String, 10)
401
- b_sal = stmt.bindByName(":SAL", Fixnum)
402
- b_hiredate = stmt.bindByName(":HIREDATE", OraDate)
403
-
404
- correspond native OCI function: ((|OCIBindByName|))
405
- =end
534
+ * Get the rowid of the last inserted/updated/deleted row.
535
+ * This cannot be used for select statements.
536
+ *
537
+ * example:
538
+ * cursor = conn.parse('INSERT INTO foo_table values(:1, :2)', 1, 2)
539
+ * cursor.exec
540
+ * cursor.rowid # => the inserted row's rowid
541
+ *
542
+ * <em>Changes between ruby-oci8 1.0.3 and 1.0.4.</em>
543
+ *
544
+ * [ruby-oci8 1.0.4 or upper] The return value is a String.
545
+ * [ruby-oci8 1.0.3 or lower] It returns an OCIRowid object.
406
546
  */
407
- static VALUE oci8_bind_by_name(int argc, VALUE *argv, VALUE self)
547
+ static VALUE oci8_stmt_get_rowid(VALUE self)
548
+ {
549
+ return oci8_get_rowid_attr(DATA_PTR(self), OCI_ATTR_ROWID);
550
+ }
551
+
552
+ static VALUE oci8_stmt_get_param_count(VALUE self)
408
553
  {
409
- VALUE vplaceholder;
410
- VALUE vtype;
411
- VALUE vlength;
412
- VALUE vmode;
413
- oci8_handle_t *h;
414
- oci8_string_t placeholder;
415
- oci8_bind_handle_t *bh;
416
- ub2 dty;
417
- ub4 mode;
418
- dvoid *indp;
419
- ub2 *rlenp;
420
- dvoid *valuep;
421
- OCIBind *bindhp = NULL;
422
- sword status;
423
- VALUE hash;
424
- VALUE obj;
425
-
426
- rb_scan_args(argc, argv, "22", &vplaceholder, &vtype, &vlength, &vmode);
427
- Get_Handle(self, h); /* 0 */
428
- Get_String(vplaceholder, placeholder); /* 1 */
429
- check_bind_type(OCI_HTYPE_BIND, h, vtype, vlength, &bh, &dty); /* 2, 3 */
430
- Get_Int_With_Default(argc, 4, vmode, mode, OCI_DEFAULT); /* 4 */
431
-
432
- if (mode & OCI_DATA_AT_EXEC) {
433
- indp = NULL;
434
- rlenp = NULL;
435
- } else {
436
- indp = &(bh->ind);
437
- rlenp = (bh->bind_type == BIND_STRING) ? NULL : &bh->rlen;
438
- }
439
- valuep = &bh->value;
440
- status = OCIBindByName(h->hp, &bindhp, h->errhp, placeholder.ptr, placeholder.len, valuep, bh->value_sz, dty, indp, rlenp, 0, 0, 0, mode);
441
- if (status != OCI_SUCCESS) {
442
- oci8_unlink((oci8_handle_t *)bh);
443
- bh->type = 0;
444
- oci8_raise(h->errhp, status, h->hp);
445
- }
446
- bh->type = OCI_HTYPE_BIND;
447
- bh->hp = bindhp;
448
- bh->errhp = h->errhp;
449
- obj = bh->self;
450
- hash = rb_ivar_get(self, oci8_id_bind_hash);
451
- if (hash == Qnil) {
452
- hash = rb_hash_new();
453
- rb_ivar_set(self, oci8_id_bind_hash, hash);
454
- }
455
- rb_hash_aset(hash, vplaceholder, obj);
456
- return obj;
554
+ return oci8_get_ub4_attr(DATA_PTR(self), OCI_ATTR_PARAM_COUNT);
457
555
  }
458
556
 
459
557
  /*
460
- =begin
461
- --- OCIStmt#execute(svc [, iters [, mode]])
462
- execute statement at the ((<service context handle|OCISvcCtx>)).
463
-
464
- :svc
465
- ((<service context handle|OCISvcCtx>))
466
- :iters
467
- the number of iterations to execute.
468
-
469
- For select statement, if there are columns which is not defined
470
- by ((<OCIStmt#defineByPos>)) and this value is positive, it
471
- raises exception. If zero, no exception. In any case you must define
472
- all columns before you call ((<OCIStmt#fetch>)).
473
-
474
- For non-select statement, use positive value.
475
-
476
- Default value is 0 for select statement, 1 for non-select statement.
477
-
478
- note: Current implemantation doesn't support array fetch and batch mode, so
479
- valid value is 0 or 1.
480
- :mode
481
- ((|OCI_DEFAULT|)), ((|OCI_BATCH_ERRORS|)), ((|OCI_COMMIT_ON_SUCCESS|)),
482
- ((|OCI_DESCRIBE_ONLY|)), ((|OCI_EXACT_FETCH|)), ((|OCI_PARSE_ONLY|)),
483
- any combinations of previous values, or ((|OCI_STMT_SCROLLABLE_READONLY|)).
484
- Default value is ((|OCI_DEFAULT|)).
485
-
486
- ((|OCI_BATCH_ERRORS|)) and ((|OCI_STMT_SCROLLABLE_READONLY|)) are not
487
- supported by current implementation.
488
-
489
- correspond native OCI function: ((|OCIStmtExecute|))
490
- =end
491
- */
492
- static VALUE oci8_stmt_execute(int argc, VALUE *argv, VALUE self)
558
+ * call-seq:
559
+ * [key]
560
+ *
561
+ * Gets the value of the bind variable.
562
+ *
563
+ * In case of binding explicitly, use same key with that of
564
+ * OCI8::Cursor#bind_param. A placeholder can be bound by
565
+ * name or position. If you bind by name, use that name. If you bind
566
+ * by position, use the position.
567
+ *
568
+ * example:
569
+ * cursor = conn.parse("BEGIN :out := 'BAR'; END;")
570
+ * cursor.bind_param(':out', 'FOO') # bind by name
571
+ * p cursor[':out'] # => 'FOO'
572
+ * p cursor[1] # => nil
573
+ * cursor.exec()
574
+ * p cursor[':out'] # => 'BAR'
575
+ * p cursor[1] # => nil
576
+ *
577
+ * example:
578
+ * cursor = conn.parse("BEGIN :out := 'BAR'; END;")
579
+ * cursor.bind_param(1, 'FOO') # bind by position
580
+ * p cursor[':out'] # => nil
581
+ * p cursor[1] # => 'FOO'
582
+ * cursor.exec()
583
+ * p cursor[':out'] # => nil
584
+ * p cursor[1] # => 'BAR'
585
+ *
586
+ * In case of binding by OCI8#exec or OCI8::Cursor#exec,
587
+ * get the value by position, which starts from 1.
588
+ *
589
+ * example:
590
+ * cursor = conn.exec("BEGIN :out := 'BAR'; END;", 'FOO')
591
+ * # 1st bind variable is bound as String with width 3. Its initial value is 'FOO'
592
+ * # After execute, the value become 'BAR'.
593
+ * p cursor[1] # => 'BAR'
594
+ */
595
+ static VALUE oci8_stmt_aref(VALUE self, VALUE key)
493
596
  {
494
- VALUE vsvc;
495
- VALUE viters;
496
- VALUE vmode;
497
- oci8_handle_t *h;
498
- oci8_handle_t *svch;
499
- ub4 mode;
500
- ub4 iters;
501
- ub2 stmt_type;
502
- sword rv;
503
-
504
- rb_scan_args(argc, argv, "12", &vsvc, &viters, &vmode);
505
- Get_Handle(self, h); /* 0 */
506
- Check_Handle(vsvc, OCISvcCtx, svch); /* 1 */
507
- if (argc >= 2) {
508
- iters = NUM2UINT(viters); /* 2 */
509
- } else {
510
- rv = OCIAttrGet(h->hp, OCI_HTYPE_STMT, &stmt_type, 0, OCI_ATTR_STMT_TYPE, h->errhp);
511
- if (rv != OCI_SUCCESS) {
512
- oci8_raise(h->errhp, rv, h->hp);
597
+ oci8_stmt_t *stmt = DATA_PTR(self);
598
+ VALUE obj = rb_hash_aref(stmt->binds, key);
599
+ if (NIL_P(obj)) {
600
+ return Qnil;
513
601
  }
514
- if (stmt_type == OCI_STMT_SELECT) {
515
- /* for select statement, default value 0. */
516
- iters = 0;
517
- } else {
518
- /* for non-select statement, default value 0. */
519
- iters = 1;
520
- }
521
- }
522
- Get_Int_With_Default(argc, 3, vmode, mode, OCI_DEFAULT); /* 3 */
523
-
524
- if (iters > 1) {
525
- rb_raise(rb_eArgError, "current implementation doesn't support array fatch or batch mode");
526
- }
527
-
528
- rv = OCIStmtExecute(svch->hp, h->hp, h->errhp, iters, 0, NULL, NULL, mode);
529
- if (rv == OCI_ERROR) {
530
- sb4 errcode;
531
- OCIErrorGet(h->errhp, 1, NULL, &errcode, NULL, 0, OCI_HTYPE_ERROR);
532
- if (errcode == 1000) {
533
- /* run GC to close unreferred cursors when ORA-01000 (maximum open cursors exceeded). */
534
- rb_gc();
535
- rv = OCIStmtExecute(svch->hp, h->hp, h->errhp, iters, 0, NULL, NULL, mode);
536
- }
537
- }
538
- if (IS_OCI_ERROR(rv)) {
539
- oci8_raise(h->errhp, rv, h->hp);
540
- }
541
- return self;
602
+ return rb_funcall(obj, oci8_id_get, 0);
542
603
  }
543
604
 
544
605
  /*
545
- =begin
546
- --- OCIStmt#fetch([nrows [, orientation [, mode]]])
547
- fetch data from select statement.
548
- fetched data are stored to previously defined ((<define handle|OCIDefine>)).
606
+ * call-seq:
607
+ * [key] = val
608
+ *
609
+ * Sets the value to the bind variable. The way to specify the
610
+ * +key+ is same with OCI8::Cursor#[]. This is available
611
+ * to replace the value and execute many times.
612
+ *
613
+ * example1:
614
+ * cursor = conn.parse("INSERT INTO test(col1) VALUES(:1)")
615
+ * cursor.bind_params(1, nil, String, 3)
616
+ * ['FOO', 'BAR', 'BAZ'].each do |key|
617
+ * cursor[1] = key
618
+ * cursor.exec
619
+ * end
620
+ * cursor.close()
621
+ *
622
+ * example2:
623
+ * ['FOO', 'BAR', 'BAZ'].each do |key|
624
+ * conn.exec("INSERT INTO test(col1) VALUES(:1)", key)
625
+ * end
626
+ *
627
+ * Both example's results are same. But the former will use less resources.
628
+ */
629
+ static VALUE oci8_stmt_aset(VALUE self, VALUE key, VALUE val)
630
+ {
631
+ long max_array_size;
632
+ long actual_array_size;
633
+ long bind_array_size;
634
+
635
+ oci8_stmt_t *stmt = DATA_PTR(self);
636
+ VALUE obj = rb_hash_aref(stmt->binds, key);
637
+ if (NIL_P(obj)) {
638
+ return Qnil; /* ?? MUST BE ERROR? */
639
+ }
549
640
 
550
- :nrows
551
- number of rows to fetch. If zero, cancel the cursor.
552
- The default value is 1.
641
+ if(TYPE(val) == T_ARRAY) {
642
+ max_array_size = NUM2INT(rb_ivar_get(self, id_at_max_array_size));
643
+ actual_array_size = NUM2INT(rb_ivar_get(self, id_at_actual_array_size));
644
+ bind_array_size = RARRAY_LEN(val);
553
645
 
554
- Because array fetch is not supported, valid value is 0 or 1.
646
+ if(actual_array_size > 0 && bind_array_size != actual_array_size) {
647
+ rb_raise(rb_eRuntimeError, "all binding arrays hould be the same size");
648
+ }
649
+ if(bind_array_size <= max_array_size && actual_array_size == 0) {
650
+ rb_ivar_set(self, id_at_actual_array_size, INT2NUM(bind_array_size));
651
+ }
652
+ }
555
653
 
556
- :orientation
557
- orientation to fetch. ((|OCI_FETCH_NEXT|)) only valid.
558
- The default value is ((|OCI_FETCH_NEXT|)).
654
+ return rb_funcall(obj, oci8_id_set, 1, val);
655
+ }
559
656
 
560
- :mode
561
- ((|OCI_DEFULT|)) only valid.
562
- The default value is ((|OCI_DEFAULT|)).
657
+ /*
658
+ * call-seq:
659
+ * keys -> an Array
660
+ *
661
+ * Returns the keys of bind variables as array.
662
+ */
663
+ static VALUE oci8_stmt_keys(VALUE self)
664
+ {
665
+ oci8_stmt_t *stmt = DATA_PTR(self);
666
+ return rb_funcall(stmt->binds, oci8_id_keys, 0);
667
+ }
563
668
 
564
- :return value
565
- array of define handles, which are defined previously,
566
- or nil when end of data.
669
+ static VALUE oci8_stmt_defined_p(VALUE self, VALUE pos)
670
+ {
671
+ oci8_stmt_t *stmt = DATA_PTR(self);
672
+ long position = NUM2INT(pos);
673
+
674
+ if (position - 1 < RARRAY_LEN(stmt->defns)) {
675
+ VALUE value = RARRAY_PTR(stmt->defns)[position - 1];
676
+ if (!NIL_P(value)) {
677
+ return Qtrue;
678
+ }
679
+ }
680
+ return Qfalse;
681
+ }
567
682
 
568
- correspond native OCI function: ((|OCIStmtFetch|))
569
- =end
570
- */
571
- static VALUE oci8_stmt_fetch(int argc, VALUE *argv, VALUE self)
683
+ /*
684
+ * call-seq:
685
+ * prefetch_rows = aFixnum
686
+ *
687
+ * Set number of rows to be prefetched.
688
+ * This can reduce the number of network round trips when fetching
689
+ * many rows. The default value is one.
690
+ *
691
+ * FYI: Rails oracle adaptor uses 100 by default.
692
+ */
693
+ static VALUE oci8_stmt_set_prefetch_rows(VALUE self, VALUE rows)
572
694
  {
573
- VALUE vnrows;
574
- VALUE vorientation;
575
- VALUE vmode;
576
- oci8_handle_t *h;
577
- ub4 nrows;
578
- ub2 orientation;
579
- ub4 mode;
580
- sword rv;
581
-
582
- rb_scan_args(argc, argv, "03", &vnrows, &vorientation, &vmode);
583
- Get_Handle(self, h); /* 0 */
584
- Get_Int_With_Default(argc, 1, vnrows, nrows, 1); /* 1 */
585
- Get_Int_With_Default(argc, 2, vorientation, orientation, OCI_FETCH_NEXT); /* 2 */
586
- Get_Int_With_Default(argc, 3, vmode, mode, OCI_DEFAULT); /* 3 */
587
-
588
- rv = OCIStmtFetch(h->hp, h->errhp, nrows, orientation, mode);
589
- if (rv == OCI_NO_DATA) {
590
- return Qnil;
591
- }
592
- if (IS_OCI_ERROR(rv)) {
593
- oci8_raise(h->errhp, rv, h->hp);
594
- }
595
- return rb_ivar_get(self, oci8_id_define_array);
596
- }
695
+ oci8_stmt_t *stmt = DATA_PTR(self);
696
+ ub4 num = NUM2UINT(rows);
697
+
698
+ oci_lc(OCIAttrSet(stmt->base.hp.ptr, OCI_HTYPE_STMT, &num, 0, OCI_ATTR_PREFETCH_ROWS, oci8_errhp));
699
+ return Qfalse;
700
+ }
597
701
 
598
702
  /*
599
- implemented in param.c
600
- =begin
601
- --- OCIStmt#paramGet(position)
602
- get column information of executed select statement.
603
- See ((<Select a table whose column types are unknown.>))
604
-
605
- :posision
606
- the position of the column to get parameter. It starts from 1.
607
- :return value
608
- newly created ((<read-only parameter descriptor|OCIParam>))
609
-
610
- correspond native OCI function: ((|OCIParamGet|))
611
- =end
612
- */
613
-
614
- void Init_oci8_stmt(void)
703
+ * bind_stmt
704
+ */
705
+ VALUE oci8_stmt_get(oci8_bind_t *obind, void *data, void *null_struct)
615
706
  {
616
- id_alloc = rb_intern("alloc");
617
- rb_define_method(cOCIStmt, "prepare", oci8_stmt_prepare, -1);
618
- rb_define_method(cOCIStmt, "defineByPos", oci8_define_by_pos, -1);
619
- rb_define_method(cOCIStmt, "bindByPos", oci8_bind_by_pos, -1);
620
- rb_define_method(cOCIStmt, "bindByName", oci8_bind_by_name, -1);
621
- rb_define_method(cOCIStmt, "execute", oci8_stmt_execute, -1);
622
- rb_define_method(cOCIStmt, "fetch", oci8_stmt_fetch, -1);
623
- rb_define_method(cOCIStmt, "paramGet", oci8_param_get, 1);
707
+ oci8_hp_obj_t *oho = (oci8_hp_obj_t *)data;
708
+ rb_funcall(oho->obj, rb_intern("define_columns"), 0);
709
+ return oho->obj;
710
+ }
711
+
712
+ static void bind_stmt_set(oci8_bind_t *obind, void *data, void **null_structp, VALUE val)
713
+ {
714
+ oci8_hp_obj_t *oho = (oci8_hp_obj_t *)data;
715
+ oci8_base_t *h;
716
+ if (!rb_obj_is_instance_of(val, cOCIStmt))
717
+ rb_raise(rb_eArgError, "Invalid argument: %s (expect OCIStmt)", rb_class2name(CLASS_OF(val)));
718
+ h = DATA_PTR(val);
719
+ oho->hp = h->hp.ptr;
720
+ oho->obj = val;
721
+ }
722
+
723
+ static void bind_stmt_init(oci8_bind_t *obind, VALUE svc, VALUE val, VALUE length)
724
+ {
725
+ obind->value_sz = sizeof(void *);
726
+ obind->alloc_sz = sizeof(oci8_hp_obj_t);
727
+ }
728
+
729
+ static void bind_stmt_init_elem(oci8_bind_t *obind, VALUE svc)
730
+ {
731
+ oci8_hp_obj_t *oho = (oci8_hp_obj_t *)obind->valuep;
732
+ oci8_base_t *h;
733
+ ub4 idx = 0;
734
+
735
+ do {
736
+ oho[idx].obj = rb_funcall(cOCIStmt, oci8_id_new, 1, svc);
737
+ h = DATA_PTR(oho[idx].obj);
738
+ oho[idx].hp = h->hp.ptr;
739
+ } while (++idx < obind->maxar_sz);
740
+ }
741
+
742
+ static const oci8_bind_class_t bind_stmt_class = {
743
+ {
744
+ oci8_bind_hp_obj_mark,
745
+ oci8_bind_free,
746
+ sizeof(oci8_bind_t)
747
+ },
748
+ oci8_stmt_get,
749
+ bind_stmt_set,
750
+ bind_stmt_init,
751
+ bind_stmt_init_elem,
752
+ NULL,
753
+ NULL,
754
+ bind_stmt_init_elem,
755
+ SQLT_RSET
756
+ };
757
+
758
+ void Init_oci8_stmt(VALUE cOCI8)
759
+ {
760
+ #if 0
761
+ cOCIHandle = rb_define_class("OCIHandle", rb_cObject);
762
+ cOCI8 = rb_define_class("OCI8", cOCIHandle);
763
+ cOCIStmt = rb_define_class_under(cOCI8, "Cursor", cOCIHandle);
764
+ #endif
765
+ cOCIStmt = oci8_define_class_under(cOCI8, "Cursor", &oci8_stmt_class);
766
+
767
+ oci8_sym_select_stmt = ID2SYM(rb_intern("select_stmt"));
768
+ oci8_sym_update_stmt = ID2SYM(rb_intern("update_stmt"));
769
+ oci8_sym_delete_stmt = ID2SYM(rb_intern("delete_stmt"));
770
+ oci8_sym_insert_stmt = ID2SYM(rb_intern("insert_stmt"));
771
+ oci8_sym_create_stmt = ID2SYM(rb_intern("create_stmt"));
772
+ oci8_sym_drop_stmt = ID2SYM(rb_intern("drop_stmt"));
773
+ oci8_sym_alter_stmt = ID2SYM(rb_intern("alter_stmt"));
774
+ oci8_sym_begin_stmt = ID2SYM(rb_intern("begin_stmt"));
775
+ oci8_sym_declare_stmt = ID2SYM(rb_intern("declare_stmt"));
776
+ id_at_column_metadata = rb_intern("@column_metadata");
777
+ id_at_actual_array_size = rb_intern("@actual_array_size");
778
+ id_at_max_array_size = rb_intern("@max_array_size");
779
+ id_each_value = rb_intern("each_value");
780
+ id_at_names = rb_intern("@names");
781
+ id_at_con = rb_intern("@con");
782
+ id_empty_p = rb_intern("empty?");
783
+ id_clear = rb_intern("clear");
784
+ id_set = rb_intern("set");
785
+
786
+ rb_define_private_method(cOCIStmt, "initialize", oci8_stmt_initialize, -1);
787
+ rb_define_private_method(cOCIStmt, "__define", oci8_define_by_pos, 2);
788
+ rb_define_private_method(cOCIStmt, "__bind", oci8_bind, 2);
789
+ rb_define_private_method(cOCIStmt, "__execute", oci8_stmt_execute, 1);
790
+ rb_define_private_method(cOCIStmt, "__clearBinds", oci8_stmt_clear_binds, 0);
791
+ rb_define_method(cOCIStmt, "fetch", oci8_stmt_fetch, 0);
792
+ rb_define_private_method(cOCIStmt, "__paramGet", oci8_stmt_get_param, 1);
793
+ rb_define_method(cOCIStmt, "type", oci8_stmt_get_stmt_type, 0);
794
+ rb_define_method(cOCIStmt, "row_count", oci8_stmt_get_row_count, 0);
795
+ rb_define_method(cOCIStmt, "rowid", oci8_stmt_get_rowid, 0);
796
+ rb_define_private_method(cOCIStmt, "__param_count", oci8_stmt_get_param_count, 0);
797
+ rb_define_method(cOCIStmt, "[]", oci8_stmt_aref, 1);
798
+ rb_define_method(cOCIStmt, "[]=", oci8_stmt_aset, 2);
799
+ rb_define_method(cOCIStmt, "keys", oci8_stmt_keys, 0);
800
+ rb_define_private_method(cOCIStmt, "__defined?", oci8_stmt_defined_p, 1);
801
+ rb_define_method(cOCIStmt, "prefetch_rows=", oci8_stmt_set_prefetch_rows, 1);
802
+
803
+ oci8_define_bind_class("Cursor", &bind_stmt_class);
624
804
  }