ruby-staci 2.2.9
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.
- checksums.yaml +7 -0
- data/.yardopts +14 -0
- data/COPYING +30 -0
- data/COPYING_old +64 -0
- data/ChangeLog +3826 -0
- data/Makefile +92 -0
- data/NEWS +1194 -0
- data/README.md +66 -0
- data/dist-files +113 -0
- data/docs/bind-array-to-in_cond.md +38 -0
- data/docs/conflicts-local-connections-and-processes.md +98 -0
- data/docs/hanging-after-inactivity.md +63 -0
- data/docs/install-binary-package.md +44 -0
- data/docs/install-full-client.md +111 -0
- data/docs/install-instant-client.md +194 -0
- data/docs/install-on-osx.md +133 -0
- data/docs/ldap-auth-and-function-interposition.md +123 -0
- data/docs/number-type-mapping.md +79 -0
- data/docs/osx-install-dev-tools.png +0 -0
- data/docs/platform-specific-issues.md +164 -0
- data/docs/report-installation-issue.md +50 -0
- data/docs/timeout-parameters.md +94 -0
- data/ext/oci8/.document +18 -0
- data/ext/oci8/MANIFEST +18 -0
- data/ext/oci8/apiwrap.c.tmpl +178 -0
- data/ext/oci8/apiwrap.h.tmpl +61 -0
- data/ext/oci8/apiwrap.rb +96 -0
- data/ext/oci8/apiwrap.yml +1322 -0
- data/ext/oci8/attr.c +57 -0
- data/ext/oci8/bind.c +838 -0
- data/ext/oci8/connection_pool.c +216 -0
- data/ext/oci8/encoding.c +196 -0
- data/ext/oci8/env.c +139 -0
- data/ext/oci8/error.c +385 -0
- data/ext/oci8/extconf.rb +219 -0
- data/ext/oci8/hook_funcs.c +407 -0
- data/ext/oci8/lob.c +1278 -0
- data/ext/oci8/metadata.c +279 -0
- data/ext/oci8/object.c +919 -0
- data/ext/oci8/oci8.c +1058 -0
- data/ext/oci8/oci8.h +556 -0
- data/ext/oci8/oci8lib.c +704 -0
- data/ext/oci8/ocidatetime.c +506 -0
- data/ext/oci8/ocihandle.c +852 -0
- data/ext/oci8/ocinumber.c +1922 -0
- data/ext/oci8/oraconf.rb +1145 -0
- data/ext/oci8/oradate.c +670 -0
- data/ext/oci8/oranumber_util.c +352 -0
- data/ext/oci8/oranumber_util.h +24 -0
- data/ext/oci8/plthook.h +66 -0
- data/ext/oci8/plthook_elf.c +702 -0
- data/ext/oci8/plthook_osx.c +505 -0
- data/ext/oci8/plthook_win32.c +391 -0
- data/ext/oci8/post-config.rb +5 -0
- data/ext/oci8/stmt.c +448 -0
- data/ext/oci8/thread_util.c +81 -0
- data/ext/oci8/thread_util.h +18 -0
- data/ext/oci8/util.c +71 -0
- data/ext/oci8/win32.c +117 -0
- data/lib/.document +1 -0
- data/lib/dbd/STACI.rb +591 -0
- data/lib/oci8/.document +8 -0
- data/lib/oci8/bindtype.rb +333 -0
- data/lib/oci8/check_load_error.rb +146 -0
- data/lib/oci8/compat.rb +117 -0
- data/lib/oci8/connection_pool.rb +179 -0
- data/lib/oci8/cursor.rb +605 -0
- data/lib/oci8/datetime.rb +605 -0
- data/lib/oci8/encoding-init.rb +45 -0
- data/lib/oci8/encoding.yml +537 -0
- data/lib/oci8/metadata.rb +2148 -0
- data/lib/oci8/object.rb +641 -0
- data/lib/oci8/oci8.rb +756 -0
- data/lib/oci8/ocihandle.rb +591 -0
- data/lib/oci8/oracle_version.rb +153 -0
- data/lib/oci8/properties.rb +196 -0
- data/lib/oci8/version.rb +3 -0
- data/lib/ruby-staci.rb +1 -0
- data/lib/staci.rb +190 -0
- data/metaconfig +142 -0
- data/pre-distclean.rb +7 -0
- data/ruby-aci.gemspec +83 -0
- data/setup.rb +1342 -0
- data/test/README.md +37 -0
- data/test/config.rb +201 -0
- data/test/setup_test_object.sql +199 -0
- data/test/setup_test_package.sql +59 -0
- data/test/test_all.rb +56 -0
- data/test/test_appinfo.rb +62 -0
- data/test/test_array_dml.rb +333 -0
- data/test/test_bind_array.rb +70 -0
- data/test/test_bind_boolean.rb +99 -0
- data/test/test_bind_integer.rb +47 -0
- data/test/test_bind_raw.rb +45 -0
- data/test/test_bind_string.rb +105 -0
- data/test/test_bind_time.rb +177 -0
- data/test/test_break.rb +124 -0
- data/test/test_clob.rb +86 -0
- data/test/test_connection_pool.rb +124 -0
- data/test/test_connstr.rb +220 -0
- data/test/test_datetime.rb +585 -0
- data/test/test_dbi.rb +365 -0
- data/test/test_dbi_clob.rb +53 -0
- data/test/test_encoding.rb +103 -0
- data/test/test_error.rb +87 -0
- data/test/test_metadata.rb +2674 -0
- data/test/test_object.rb +546 -0
- data/test/test_oci8.rb +624 -0
- data/test/test_oracle_version.rb +68 -0
- data/test/test_oradate.rb +255 -0
- data/test/test_oranumber.rb +786 -0
- data/test/test_package_type.rb +981 -0
- data/test/test_properties.rb +17 -0
- data/test/test_rowid.rb +32 -0
- metadata +158 -0
data/ext/oci8/stmt.c
ADDED
@@ -0,0 +1,448 @@
|
|
1
|
+
/* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
|
2
|
+
/*
|
3
|
+
* stmt.c - part of ruby-oci8
|
4
|
+
* implement the methods of OCIStmt.
|
5
|
+
*
|
6
|
+
* Copyright (C) 2002-2015 Kubo Takehiro <kubo@jiubao.org>
|
7
|
+
*
|
8
|
+
*/
|
9
|
+
#include "oci8.h"
|
10
|
+
|
11
|
+
static VALUE cOCIStmt;
|
12
|
+
|
13
|
+
#define TO_STMT(obj) ((oci8_stmt_t *)oci8_check_typeddata((obj), &oci8_stmt_data_type, 1))
|
14
|
+
|
15
|
+
typedef struct {
|
16
|
+
oci8_base_t base;
|
17
|
+
VALUE svc;
|
18
|
+
char use_stmt_release;
|
19
|
+
char end_of_fetch;
|
20
|
+
} oci8_stmt_t;
|
21
|
+
|
22
|
+
static void oci8_stmt_mark(oci8_base_t *base)
|
23
|
+
{
|
24
|
+
oci8_stmt_t *stmt = (oci8_stmt_t *)base;
|
25
|
+
rb_gc_mark(stmt->svc);
|
26
|
+
}
|
27
|
+
|
28
|
+
static void oci8_stmt_free(oci8_base_t *base)
|
29
|
+
{
|
30
|
+
oci8_stmt_t *stmt = (oci8_stmt_t *)base;
|
31
|
+
stmt->svc = Qnil;
|
32
|
+
if (stmt->use_stmt_release) {
|
33
|
+
ACIStmtRelease(base->hp.stmt, oci8_errhp, NULL, 0, ACI_DEFAULT);
|
34
|
+
base->type = 0;
|
35
|
+
base->closed = 1;
|
36
|
+
stmt->use_stmt_release = 0;
|
37
|
+
}
|
38
|
+
}
|
39
|
+
|
40
|
+
static const oci8_handle_data_type_t oci8_stmt_data_type = {
|
41
|
+
{
|
42
|
+
"STACI::Cursor",
|
43
|
+
{
|
44
|
+
(RUBY_DATA_FUNC)oci8_stmt_mark,
|
45
|
+
oci8_handle_cleanup,
|
46
|
+
oci8_handle_size,
|
47
|
+
},
|
48
|
+
&oci8_handle_data_type.rb_data_type, NULL,
|
49
|
+
#ifdef RUBY_TYPED_WB_PROTECTED
|
50
|
+
RUBY_TYPED_WB_PROTECTED,
|
51
|
+
#endif
|
52
|
+
},
|
53
|
+
oci8_stmt_free,
|
54
|
+
sizeof(oci8_stmt_t),
|
55
|
+
};
|
56
|
+
|
57
|
+
static VALUE oci8_stmt_alloc(VALUE klass)
|
58
|
+
{
|
59
|
+
return oci8_allocate_typeddata(klass, &oci8_stmt_data_type);
|
60
|
+
}
|
61
|
+
|
62
|
+
/*
|
63
|
+
* @overload __initialize(connection, sql_statement)
|
64
|
+
*
|
65
|
+
* @param [OCI8] connection
|
66
|
+
* @param [String] sql_statement
|
67
|
+
*
|
68
|
+
* @private
|
69
|
+
*/
|
70
|
+
static VALUE oci8_stmt_initialize(VALUE self, VALUE svc, VALUE sql)
|
71
|
+
{
|
72
|
+
oci8_stmt_t *stmt = TO_STMT(self);
|
73
|
+
oci8_svcctx_t *svcctx;
|
74
|
+
sword rv;
|
75
|
+
|
76
|
+
svcctx = oci8_get_svcctx(svc);
|
77
|
+
oci8_check_pid_consistency(svcctx);
|
78
|
+
if (!NIL_P(sql)) {
|
79
|
+
OCI8SafeStringValue(sql);
|
80
|
+
|
81
|
+
rv = ACIStmtPrepare2(svcctx->base.hp.svc, &stmt->base.hp.stmt, oci8_errhp, RSTRING_ORATEXT(sql), RSTRING_LEN(sql), NULL, 0, ACI_NTV_SYNTAX, ACI_DEFAULT);
|
82
|
+
if (IS_OCI_ERROR(rv)) {
|
83
|
+
chker2(rv, &svcctx->base);
|
84
|
+
}
|
85
|
+
stmt->base.type = ACI_HTYPE_STMT;
|
86
|
+
stmt->use_stmt_release = 1;
|
87
|
+
} else {
|
88
|
+
rv = ACIHandleAlloc(oci8_envhp, &stmt->base.hp.ptr, ACI_HTYPE_STMT, 0, NULL);
|
89
|
+
if (rv != ACI_SUCCESS) {
|
90
|
+
oci8_env_raise(oci8_envhp, rv);
|
91
|
+
}
|
92
|
+
stmt->base.type = ACI_HTYPE_STMT;
|
93
|
+
}
|
94
|
+
RB_OBJ_WRITE(stmt->base.self, &stmt->svc, svc);
|
95
|
+
|
96
|
+
oci8_link_to_parent(&stmt->base, &svcctx->base);
|
97
|
+
return Qnil;
|
98
|
+
}
|
99
|
+
|
100
|
+
/*
|
101
|
+
* @overload __define(position, bindobj)
|
102
|
+
*
|
103
|
+
* @param [Integer] position
|
104
|
+
* @param [OCI8::BindType::Base] bindobj
|
105
|
+
*
|
106
|
+
* @private
|
107
|
+
*/
|
108
|
+
static VALUE oci8_define_by_pos(VALUE self, VALUE vposition, VALUE vbindobj)
|
109
|
+
{
|
110
|
+
oci8_stmt_t *stmt = TO_STMT(self);
|
111
|
+
ub4 position = NUM2INT(vposition);
|
112
|
+
oci8_bind_t *obind = TO_BIND(vbindobj);
|
113
|
+
const oci8_bind_data_type_t *data_type;
|
114
|
+
sword status;
|
115
|
+
void *valuep;
|
116
|
+
void *indp;
|
117
|
+
ub4 mode;
|
118
|
+
|
119
|
+
if (obind->base.hp.dfn != NULL) {
|
120
|
+
oci8_base_free(&obind->base); /* TODO: OK? */
|
121
|
+
}
|
122
|
+
data_type = (const oci8_bind_data_type_t *)obind->base.data_type;
|
123
|
+
if (obind->value_sz != SB4MAXVAL) {
|
124
|
+
valuep = obind->valuep;
|
125
|
+
indp = NIL_P(obind->tdo) ? obind->u.inds : NULL;
|
126
|
+
mode = ACI_DEFAULT;
|
127
|
+
} else {
|
128
|
+
valuep = NULL;
|
129
|
+
indp = NULL;
|
130
|
+
mode = ACI_DYNAMIC_FETCH;
|
131
|
+
}
|
132
|
+
status = ACIDefineByPos(stmt->base.hp.stmt, &obind->base.hp.dfn, oci8_errhp, position, valuep, obind->value_sz, data_type->dty, indp, NULL, 0, mode);
|
133
|
+
if (status != ACI_SUCCESS) {
|
134
|
+
chker3(status, &stmt->base, stmt->base.hp.ptr);
|
135
|
+
}
|
136
|
+
obind->base.type = ACI_HTYPE_DEFINE;
|
137
|
+
/* link to the parent as soon as possible to preserve deallocation order. */
|
138
|
+
oci8_unlink_from_parent((oci8_base_t*)obind);
|
139
|
+
oci8_link_to_parent((oci8_base_t*)obind, (oci8_base_t*)stmt);
|
140
|
+
|
141
|
+
if (NIL_P(obind->tdo) && obind->maxar_sz > 0) {
|
142
|
+
chker2(ACIDefineArrayOfStruct(obind->base.hp.dfn, oci8_errhp, obind->alloc_sz, sizeof(sb2), 0, 0), &stmt->base);
|
143
|
+
}
|
144
|
+
if (data_type->post_bind_hook != NULL) {
|
145
|
+
data_type->post_bind_hook(obind);
|
146
|
+
}
|
147
|
+
return obind->base.self;
|
148
|
+
}
|
149
|
+
|
150
|
+
/*
|
151
|
+
* @overload __bind(placeholder, bindobj)
|
152
|
+
*
|
153
|
+
* @param [Integer, String or Symbol] placeholder
|
154
|
+
* @param [STACI::BindType::Base] bindobj
|
155
|
+
*
|
156
|
+
* @private
|
157
|
+
*/
|
158
|
+
static VALUE oci8_bind(VALUE self, VALUE vplaceholder, VALUE vbindobj)
|
159
|
+
{
|
160
|
+
oci8_stmt_t *stmt = TO_STMT(self);
|
161
|
+
char *placeholder_ptr = (char*)-1; /* initialize as an invalid value */
|
162
|
+
ub4 placeholder_len = 0;
|
163
|
+
ub4 position = 0;
|
164
|
+
oci8_bind_t *obind;
|
165
|
+
const oci8_bind_data_type_t *data_type;
|
166
|
+
sword status;
|
167
|
+
void *valuep;
|
168
|
+
void *indp;
|
169
|
+
ub4 mode;
|
170
|
+
|
171
|
+
if (NIL_P(vplaceholder)) { /* 1 */
|
172
|
+
placeholder_ptr = NULL;
|
173
|
+
placeholder_len = 0;
|
174
|
+
} else if (SYMBOL_P(vplaceholder)) {
|
175
|
+
#ifdef HAVE_RB_SYM2STR
|
176
|
+
/* Don't use SYM2ID on ruby 2.2.0 or later.
|
177
|
+
* Symbols passed to SYM2ID are not GC'ed.
|
178
|
+
*/
|
179
|
+
VALUE symval = rb_sym2str(vplaceholder);
|
180
|
+
const char *symname = RSTRING_PTR(symval);
|
181
|
+
size_t len = RSTRING_LEN(symval);
|
182
|
+
#else
|
183
|
+
const char *symname = rb_id2name(SYM2ID(vplaceholder));
|
184
|
+
size_t len = strlen(symname);
|
185
|
+
#endif
|
186
|
+
placeholder_ptr = ALLOCA_N(char, len + 1);
|
187
|
+
placeholder_len = len + 1;
|
188
|
+
placeholder_ptr[0] = ':';
|
189
|
+
memcpy(placeholder_ptr + 1, symname, len);
|
190
|
+
} else if (FIXNUM_P(vplaceholder)) {
|
191
|
+
position = NUM2INT(vplaceholder);
|
192
|
+
} else {
|
193
|
+
OCI8StringValue(vplaceholder);
|
194
|
+
placeholder_ptr = RSTRING_PTR(vplaceholder);
|
195
|
+
placeholder_len = RSTRING_LEN(vplaceholder);
|
196
|
+
}
|
197
|
+
obind = TO_BIND(vbindobj); /* 2 */
|
198
|
+
if (obind->base.hp.bnd != NULL) {
|
199
|
+
oci8_base_free(&obind->base); /* TODO: OK? */
|
200
|
+
}
|
201
|
+
data_type = (const oci8_bind_data_type_t *)obind->base.data_type;
|
202
|
+
|
203
|
+
if (obind->value_sz != SB4MAXVAL) {
|
204
|
+
valuep = obind->valuep;
|
205
|
+
indp = NIL_P(obind->tdo) ? obind->u.inds : NULL;
|
206
|
+
mode = ACI_DEFAULT;
|
207
|
+
} else {
|
208
|
+
valuep = NULL;
|
209
|
+
indp = NULL;
|
210
|
+
mode = ACI_DATA_AT_EXEC;
|
211
|
+
}
|
212
|
+
if (placeholder_ptr == (char*)-1) {
|
213
|
+
status = OCIBindByPos(stmt->base.hp.stmt, &obind->base.hp.bnd, oci8_errhp, position, valuep, obind->value_sz, data_type->dty, indp, NULL, 0, 0, 0, mode);
|
214
|
+
} else {
|
215
|
+
status = ACIBindByName(stmt->base.hp.stmt, &obind->base.hp.bnd, oci8_errhp, TO_ORATEXT(placeholder_ptr), placeholder_len, valuep, obind->value_sz, data_type->dty, indp, NULL, 0, 0, 0, mode);
|
216
|
+
}
|
217
|
+
if (status != ACI_SUCCESS) {
|
218
|
+
chker3(status, &stmt->base, stmt->base.hp.stmt);
|
219
|
+
}
|
220
|
+
obind->base.type = ACI_HTYPE_BIND;
|
221
|
+
/* link to the parent as soon as possible to preserve deallocation order. */
|
222
|
+
oci8_unlink_from_parent((oci8_base_t*)obind);
|
223
|
+
oci8_link_to_parent((oci8_base_t*)obind, (oci8_base_t*)stmt);
|
224
|
+
|
225
|
+
if (NIL_P(obind->tdo) && obind->maxar_sz > 0) {
|
226
|
+
chker2(ACIBindArrayOfStruct(obind->base.hp.bnd, oci8_errhp, obind->alloc_sz, sizeof(sb2), 0, 0),
|
227
|
+
&stmt->base);
|
228
|
+
}
|
229
|
+
if (data_type->post_bind_hook != NULL) {
|
230
|
+
data_type->post_bind_hook(obind);
|
231
|
+
}
|
232
|
+
return obind->base.self;
|
233
|
+
}
|
234
|
+
|
235
|
+
static sword oci8_call_stmt_execute(oci8_svcctx_t *svcctx, oci8_stmt_t *stmt, ub4 iters, ub4 mode)
|
236
|
+
{
|
237
|
+
sword rv;
|
238
|
+
|
239
|
+
rv = ACIStmtExecute_nb(svcctx, svcctx->base.hp.svc, stmt->base.hp.stmt, oci8_errhp, iters, 0, NULL, NULL, mode);
|
240
|
+
if (rv == ACI_ERROR) {
|
241
|
+
if (oci8_get_error_code(oci8_errhp) == 1000) {
|
242
|
+
/* run GC to close unreferred cursors
|
243
|
+
* when ORA-01000 (maximum open cursors exceeded).
|
244
|
+
*/
|
245
|
+
rb_gc();
|
246
|
+
rv = ACIStmtExecute_nb(svcctx, svcctx->base.hp.svc, stmt->base.hp.stmt, oci8_errhp, iters, 0, NULL, NULL, mode);
|
247
|
+
}
|
248
|
+
}
|
249
|
+
return rv;
|
250
|
+
}
|
251
|
+
|
252
|
+
/*
|
253
|
+
* @overload __execute(iteration_count)
|
254
|
+
*
|
255
|
+
* @param [Integer] iteration_count
|
256
|
+
*
|
257
|
+
* @private
|
258
|
+
*/
|
259
|
+
static VALUE oci8_stmt_execute(VALUE self, VALUE iteration_count)
|
260
|
+
{
|
261
|
+
oci8_stmt_t *stmt = TO_STMT(self);
|
262
|
+
oci8_svcctx_t *svcctx = oci8_get_svcctx(stmt->svc);
|
263
|
+
|
264
|
+
stmt->end_of_fetch = 0;
|
265
|
+
chker3(oci8_call_stmt_execute(svcctx, stmt, NUM2UINT(iteration_count),
|
266
|
+
svcctx->is_autocommit ? ACI_COMMIT_ON_SUCCESS : ACI_DEFAULT),
|
267
|
+
&stmt->base, stmt->base.hp.stmt);
|
268
|
+
return self;
|
269
|
+
}
|
270
|
+
|
271
|
+
/*
|
272
|
+
* @overload __fetch(connection, max_rows)
|
273
|
+
*
|
274
|
+
* Fetches one row and set the result to <code>@define_handles</code>.
|
275
|
+
* This is called by private methods of STACI::Cursor.
|
276
|
+
*
|
277
|
+
* @param [STACI] connection
|
278
|
+
* @return [true or false] true on success and false when all rows are fetched.
|
279
|
+
*
|
280
|
+
* @private
|
281
|
+
*/
|
282
|
+
static VALUE oci8_stmt_fetch(VALUE self, VALUE svc, VALUE max_rows)
|
283
|
+
{
|
284
|
+
oci8_stmt_t *stmt = TO_STMT(self);
|
285
|
+
oci8_svcctx_t *svcctx = oci8_get_svcctx(svc);
|
286
|
+
sword rv;
|
287
|
+
oci8_bind_t *obind;
|
288
|
+
const oci8_bind_data_type_t *data_type;
|
289
|
+
ub4 nrows = NUM2UINT(max_rows);
|
290
|
+
|
291
|
+
if (stmt->end_of_fetch) {
|
292
|
+
return Qnil;
|
293
|
+
}
|
294
|
+
|
295
|
+
if (stmt->base.children != NULL) {
|
296
|
+
obind = (oci8_bind_t *)stmt->base.children;
|
297
|
+
do {
|
298
|
+
if (obind->base.type == ACI_HTYPE_DEFINE) {
|
299
|
+
data_type = (const oci8_bind_data_type_t *)obind->base.data_type;
|
300
|
+
if (data_type->pre_fetch_hook != NULL) {
|
301
|
+
data_type->pre_fetch_hook(obind, stmt->svc);
|
302
|
+
}
|
303
|
+
if (nrows > 1 && nrows != obind->maxar_sz) {
|
304
|
+
rb_raise(rb_eRuntimeError, "fetch size (%u) != define-handle size %u", nrows, obind->maxar_sz);
|
305
|
+
}
|
306
|
+
}
|
307
|
+
obind = (oci8_bind_t *)obind->base.next;
|
308
|
+
} while (obind != (oci8_bind_t*)stmt->base.children);
|
309
|
+
}
|
310
|
+
rv = ACIStmtFetch_nb(svcctx, stmt->base.hp.stmt, oci8_errhp, nrows, ACI_FETCH_NEXT, ACI_DEFAULT);
|
311
|
+
if (rv == ACI_NO_DATA) {
|
312
|
+
stmt->end_of_fetch = 1;
|
313
|
+
} else {
|
314
|
+
chker3(rv, &svcctx->base, stmt->base.hp.stmt);
|
315
|
+
}
|
316
|
+
chker2(ACIAttrGet(stmt->base.hp.stmt, ACI_HTYPE_STMT, &nrows, 0, ACI_ATTR_ROWS_FETCHED, oci8_errhp),
|
317
|
+
&svcctx->base);
|
318
|
+
return nrows ? UINT2NUM(nrows) : Qnil;
|
319
|
+
}
|
320
|
+
|
321
|
+
/*
|
322
|
+
* @overload __paramGet(pos)
|
323
|
+
*
|
324
|
+
* Returns the definition of column specified by <i>pos</i>
|
325
|
+
*
|
326
|
+
* @param [Integer] pos Column position which starts from one
|
327
|
+
* @return [STACI::Metadata::Base]
|
328
|
+
*
|
329
|
+
* @private
|
330
|
+
*/
|
331
|
+
static VALUE oci8_stmt_get_param(VALUE self, VALUE pos)
|
332
|
+
{
|
333
|
+
oci8_stmt_t *stmt = TO_STMT(self);
|
334
|
+
ACIParam *parmhp = NULL;
|
335
|
+
sword rv;
|
336
|
+
|
337
|
+
Check_Type(pos, T_FIXNUM); /* 1 */
|
338
|
+
rv = ACIParamGet(stmt->base.hp.stmt, ACI_HTYPE_STMT, oci8_errhp, (dvoid *)&parmhp, FIX2INT(pos));
|
339
|
+
if (rv != ACI_SUCCESS) {
|
340
|
+
chker3(rv, &stmt->base, stmt->base.hp.stmt);
|
341
|
+
}
|
342
|
+
return oci8_metadata_create(parmhp, stmt->svc, self);
|
343
|
+
}
|
344
|
+
|
345
|
+
/*
|
346
|
+
* Gets the rowid of the last inserted, updated or deleted row.
|
347
|
+
* This cannot be used for select statements.
|
348
|
+
*
|
349
|
+
* @example
|
350
|
+
* cursor = conn.parse('INSERT INTO foo_table values(:1, :2)', 1, 2)
|
351
|
+
* cursor.exec
|
352
|
+
* cursor.rowid # => "AAAFlLAAEAAAAG9AAA", the inserted row's rowid
|
353
|
+
*
|
354
|
+
* @return [String]
|
355
|
+
*/
|
356
|
+
static VALUE oci8_stmt_get_rowid(VALUE self)
|
357
|
+
{
|
358
|
+
oci8_base_t *base = oci8_check_typeddata(self, &oci8_stmt_data_type, 1);
|
359
|
+
return oci8_get_rowid_attr(base, ACI_ATTR_ROWID, base->hp.stmt);
|
360
|
+
}
|
361
|
+
|
362
|
+
/*
|
363
|
+
* bind_stmt
|
364
|
+
*/
|
365
|
+
VALUE oci8_stmt_get(oci8_bind_t *obind, void *data, void *null_struct)
|
366
|
+
{
|
367
|
+
oci8_hp_obj_t *oho = (oci8_hp_obj_t *)data;
|
368
|
+
rb_funcall(oho->obj, rb_intern("define_columns"), 0);
|
369
|
+
return oho->obj;
|
370
|
+
}
|
371
|
+
|
372
|
+
static void bind_stmt_set(oci8_bind_t *obind, void *data, void **null_structp, VALUE val)
|
373
|
+
{
|
374
|
+
oci8_hp_obj_t *oho = (oci8_hp_obj_t *)data;
|
375
|
+
oci8_stmt_t *stmt = TO_STMT(val);
|
376
|
+
oho->hp = stmt->base.hp.ptr;
|
377
|
+
RB_OBJ_WRITE(obind->base.self, &oho->obj, val);
|
378
|
+
}
|
379
|
+
|
380
|
+
static void bind_stmt_init(oci8_bind_t *obind, VALUE svc, VALUE val, VALUE length)
|
381
|
+
{
|
382
|
+
obind->value_sz = sizeof(void *);
|
383
|
+
obind->alloc_sz = sizeof(oci8_hp_obj_t);
|
384
|
+
}
|
385
|
+
|
386
|
+
static void bind_stmt_init_elem(oci8_bind_t *obind, VALUE svc)
|
387
|
+
{
|
388
|
+
oci8_hp_obj_t *oho = (oci8_hp_obj_t *)obind->valuep;
|
389
|
+
oci8_base_t *h;
|
390
|
+
ub4 idx = 0;
|
391
|
+
|
392
|
+
do {
|
393
|
+
oho[idx].obj = rb_class_new_instance(1, &svc, cOCIStmt);
|
394
|
+
RB_OBJ_WRITTEN(obind->base.self, Qundef, oho[idx].obj);
|
395
|
+
h = DATA_PTR(oho[idx].obj);
|
396
|
+
oho[idx].hp = h->hp.ptr;
|
397
|
+
} while (++idx < obind->maxar_sz);
|
398
|
+
}
|
399
|
+
|
400
|
+
static const oci8_bind_data_type_t bind_stmt_data_type = {
|
401
|
+
{
|
402
|
+
{
|
403
|
+
"STACI::BindType::Cursor",
|
404
|
+
{
|
405
|
+
(RUBY_DATA_FUNC)oci8_bind_hp_obj_mark,
|
406
|
+
oci8_handle_cleanup,
|
407
|
+
oci8_handle_size,
|
408
|
+
},
|
409
|
+
&oci8_bind_data_type.rb_data_type, NULL,
|
410
|
+
#ifdef RUBY_TYPED_WB_PROTECTED
|
411
|
+
RUBY_TYPED_WB_PROTECTED,
|
412
|
+
#endif
|
413
|
+
},
|
414
|
+
oci8_bind_free,
|
415
|
+
sizeof(oci8_bind_t)
|
416
|
+
},
|
417
|
+
oci8_stmt_get,
|
418
|
+
bind_stmt_set,
|
419
|
+
bind_stmt_init,
|
420
|
+
bind_stmt_init_elem,
|
421
|
+
bind_stmt_init_elem,
|
422
|
+
SQLT_RSET
|
423
|
+
};
|
424
|
+
|
425
|
+
static VALUE bind_stmt_alloc(VALUE klass)
|
426
|
+
{
|
427
|
+
return oci8_allocate_typeddata(klass, &bind_stmt_data_type.base);
|
428
|
+
}
|
429
|
+
|
430
|
+
void Init_oci8_stmt(VALUE cOCI8)
|
431
|
+
{
|
432
|
+
#if 0
|
433
|
+
cOCIHandle = rb_define_class("ACIHandle", rb_cObject);
|
434
|
+
cOCI8 = rb_define_class("OCI8", cOCIHandle);
|
435
|
+
cOCIStmt = rb_define_class_under(cOCI8, "Cursor", cOCIHandle);
|
436
|
+
#endif
|
437
|
+
cOCIStmt = oci8_define_class_under(cOCI8, "Cursor", &oci8_stmt_data_type, oci8_stmt_alloc);
|
438
|
+
|
439
|
+
rb_define_private_method(cOCIStmt, "__initialize", oci8_stmt_initialize, 2);
|
440
|
+
rb_define_private_method(cOCIStmt, "__define", oci8_define_by_pos, 2);
|
441
|
+
rb_define_private_method(cOCIStmt, "__bind", oci8_bind, 2);
|
442
|
+
rb_define_private_method(cOCIStmt, "__execute", oci8_stmt_execute, 1);
|
443
|
+
rb_define_private_method(cOCIStmt, "__fetch", oci8_stmt_fetch, 2);
|
444
|
+
rb_define_private_method(cOCIStmt, "__paramGet", oci8_stmt_get_param, 1);
|
445
|
+
rb_define_method(cOCIStmt, "rowid", oci8_stmt_get_rowid, 0);
|
446
|
+
|
447
|
+
oci8_define_bind_class("Cursor", &bind_stmt_data_type, bind_stmt_alloc);
|
448
|
+
}
|
@@ -0,0 +1,81 @@
|
|
1
|
+
/* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
|
2
|
+
/*
|
3
|
+
* thread_util.c - part of ruby-oci8
|
4
|
+
*
|
5
|
+
* Copyright (C) 2011 KUBO Takehiro <kubo@jiubao.org>
|
6
|
+
*/
|
7
|
+
#include "oci8.h"
|
8
|
+
#include <errno.h>
|
9
|
+
|
10
|
+
#ifndef WIN32
|
11
|
+
#include <pthread.h>
|
12
|
+
static pthread_attr_t detached_thread_attr;
|
13
|
+
#endif
|
14
|
+
|
15
|
+
typedef struct {
|
16
|
+
void *(*func)(void *);
|
17
|
+
void *arg;
|
18
|
+
} adapter_arg_t;
|
19
|
+
|
20
|
+
void Init_oci8_thread_util(void)
|
21
|
+
{
|
22
|
+
#ifndef WIN32
|
23
|
+
pthread_attr_init(&detached_thread_attr);
|
24
|
+
pthread_attr_setdetachstate(&detached_thread_attr, PTHREAD_CREATE_DETACHED);
|
25
|
+
#endif
|
26
|
+
}
|
27
|
+
|
28
|
+
#ifdef WIN32
|
29
|
+
|
30
|
+
static void __cdecl adapter(void *arg)
|
31
|
+
{
|
32
|
+
adapter_arg_t *aa = (adapter_arg_t *)arg;
|
33
|
+
aa->func(aa->arg);
|
34
|
+
free(aa);
|
35
|
+
}
|
36
|
+
|
37
|
+
int oci8_run_native_thread(void *(*func)(void*), void *arg)
|
38
|
+
{
|
39
|
+
adapter_arg_t *aa = malloc(sizeof(adapter_arg_t));
|
40
|
+
if (aa == NULL) {
|
41
|
+
return ENOMEM;
|
42
|
+
}
|
43
|
+
|
44
|
+
aa->func = func;
|
45
|
+
aa->arg = arg;
|
46
|
+
if (_beginthread(adapter, 0, aa) == (uintptr_t)-1L) {
|
47
|
+
int err = errno;
|
48
|
+
free(aa);
|
49
|
+
return err;
|
50
|
+
}
|
51
|
+
return 0;
|
52
|
+
}
|
53
|
+
|
54
|
+
#else /* WIN32 */
|
55
|
+
|
56
|
+
static void *adapter(void *arg)
|
57
|
+
{
|
58
|
+
adapter_arg_t *aa = (adapter_arg_t *)arg;
|
59
|
+
aa->func(aa->arg);
|
60
|
+
free(aa);
|
61
|
+
return NULL;
|
62
|
+
}
|
63
|
+
|
64
|
+
int oci8_run_native_thread(void *(*func)(void *), void *arg)
|
65
|
+
{
|
66
|
+
pthread_t thread;
|
67
|
+
adapter_arg_t *aa = malloc(sizeof(adapter_arg_t));
|
68
|
+
int rv;
|
69
|
+
if (aa == NULL) {
|
70
|
+
return ENOMEM;
|
71
|
+
}
|
72
|
+
|
73
|
+
aa->func = func;
|
74
|
+
aa->arg = arg;
|
75
|
+
rv = pthread_create(&thread, &detached_thread_attr, adapter, aa);
|
76
|
+
if (rv != 0) {
|
77
|
+
free(aa);
|
78
|
+
}
|
79
|
+
return rv;
|
80
|
+
}
|
81
|
+
#endif /* WIN32 */
|
@@ -0,0 +1,18 @@
|
|
1
|
+
/* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
|
2
|
+
/*
|
3
|
+
* thread_util.h - part of ruby-oci8
|
4
|
+
*
|
5
|
+
* Copyright (C) 2011 KUBO Takehiro <kubo@jiubao.org>
|
6
|
+
*/
|
7
|
+
|
8
|
+
/*
|
9
|
+
* Prepare to execute thread-related functions.
|
10
|
+
*/
|
11
|
+
void Init_oci8_thread_util(void);
|
12
|
+
|
13
|
+
/*
|
14
|
+
* Run the func in a new native thread.
|
15
|
+
* Don't call any ruby functions in the func.
|
16
|
+
* The return value is errno.
|
17
|
+
*/
|
18
|
+
int oci8_run_native_thread(void *(*func)(void *), void *arg);
|
data/ext/oci8/util.c
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
/* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
|
2
|
+
/*
|
3
|
+
util.c - part of ruby-oci8
|
4
|
+
|
5
|
+
Copyright (C) 2015 Kubo Takehiro <kubo@jiubao.org>
|
6
|
+
*/
|
7
|
+
#if defined __linux && !defined(_GNU_SOURCE)
|
8
|
+
#define _GNU_SOURCE 1
|
9
|
+
#endif
|
10
|
+
#include "oci8.h"
|
11
|
+
#ifdef HAVE_DLADDR
|
12
|
+
#include <dlfcn.h>
|
13
|
+
#endif
|
14
|
+
#ifdef __CYGWIN__
|
15
|
+
#undef boolean
|
16
|
+
#include <windows.h>
|
17
|
+
#endif
|
18
|
+
|
19
|
+
const char *oci8_dll_path(void)
|
20
|
+
{
|
21
|
+
#if defined _WIN32 || defined __CYGWIN__
|
22
|
+
HMODULE hMod = GetModuleHandleA("ACI.DLL");
|
23
|
+
static char buf[MAX_PATH];
|
24
|
+
if (hMod != NULL) {
|
25
|
+
if (GetModuleFileName(hMod, buf, sizeof(buf))) {
|
26
|
+
return buf;
|
27
|
+
}
|
28
|
+
}
|
29
|
+
#elif defined HAVE_DLADDR && defined RTLD_DEFAULT
|
30
|
+
void *addr = dlsym(RTLD_DEFAULT, "ACIEnvCreate");
|
31
|
+
Dl_info info;
|
32
|
+
if (addr != NULL && dladdr(addr, &info)) {
|
33
|
+
return info.dli_fname;
|
34
|
+
}
|
35
|
+
#elif defined HAVE_DLMODINFO && defined HAVE_DLGETNAME && defined RTLD_DEFAULT
|
36
|
+
void *addr = dlsym(RTLD_DEFAULT, "ACIEnvCreate");
|
37
|
+
if (addr != NULL) {
|
38
|
+
struct load_module_desc desc;
|
39
|
+
if (dlmodinfo((uint64_t)addr, &desc, sizeof(desc), NULL, 0, 0) != 0) {
|
40
|
+
return dlgetname(&desc, sizeof(desc), NULL, 0, 0);
|
41
|
+
}
|
42
|
+
}
|
43
|
+
#endif
|
44
|
+
return NULL;
|
45
|
+
}
|
46
|
+
|
47
|
+
/*
|
48
|
+
* Returns the full path of Oracle client library used by the current process.
|
49
|
+
*
|
50
|
+
* @return [String]
|
51
|
+
*/
|
52
|
+
static VALUE dll_path(VALUE module)
|
53
|
+
{
|
54
|
+
const char *path = oci8_dll_path();
|
55
|
+
if (path == NULL) {
|
56
|
+
return Qnil;
|
57
|
+
}
|
58
|
+
return rb_external_str_new_with_enc(path, strlen(path), rb_filesystem_encoding());
|
59
|
+
}
|
60
|
+
|
61
|
+
void Init_oci8_util(VALUE cOCI8)
|
62
|
+
{
|
63
|
+
#if 0
|
64
|
+
/* for yard */
|
65
|
+
cOCIHandle = rb_define_class("OCIHandle", rb_cObject);
|
66
|
+
cOCI8 = rb_define_class("STACI", cOCIHandle);
|
67
|
+
#endif
|
68
|
+
VALUE mUtil = rb_define_module_under(cOCI8, "Util");
|
69
|
+
|
70
|
+
rb_define_module_function(mUtil, "dll_path", dll_path, 0);
|
71
|
+
}
|