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,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
  }