ruby-oci8 2.2.3 → 2.2.12
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/ChangeLog +427 -0
- data/NEWS +335 -42
- data/README.md +20 -9
- data/dist-files +9 -3
- data/docs/bind-array-to-in_cond.md +2 -2
- data/docs/conflicts-local-connections-and-processes.md +7 -4
- data/docs/hanging-after-inactivity.md +63 -0
- data/docs/install-binary-package.md +15 -11
- data/docs/install-full-client.md +18 -21
- data/docs/install-instant-client.md +45 -27
- data/docs/install-on-osx.md +31 -120
- data/docs/ldap-auth-and-function-interposition.md +123 -0
- data/docs/number-type-mapping.md +79 -0
- data/docs/platform-specific-issues.md +17 -50
- data/docs/report-installation-issue.md +3 -0
- data/docs/timeout-parameters.md +3 -0
- data/ext/oci8/apiwrap.c.tmpl +2 -5
- data/ext/oci8/apiwrap.rb +6 -1
- data/ext/oci8/apiwrap.yml +34 -22
- data/ext/oci8/attr.c +4 -2
- data/ext/oci8/bind.c +366 -6
- data/ext/oci8/connection_pool.c +3 -3
- data/ext/oci8/encoding.c +5 -5
- data/ext/oci8/env.c +8 -2
- data/ext/oci8/error.c +24 -16
- data/ext/oci8/extconf.rb +8 -4
- data/ext/oci8/hook_funcs.c +274 -61
- data/ext/oci8/lob.c +31 -75
- data/ext/oci8/metadata.c +2 -2
- data/ext/oci8/object.c +72 -27
- data/ext/oci8/oci8.c +45 -132
- data/ext/oci8/oci8.h +32 -88
- data/ext/oci8/oci8lib.c +178 -38
- data/ext/oci8/ocihandle.c +37 -37
- data/ext/oci8/ocinumber.c +23 -18
- data/ext/oci8/oraconf.rb +158 -339
- data/ext/oci8/oradate.c +19 -19
- data/ext/oci8/plthook.h +10 -0
- data/ext/oci8/plthook_elf.c +433 -268
- data/ext/oci8/plthook_osx.c +40 -9
- data/ext/oci8/plthook_win32.c +9 -0
- data/ext/oci8/stmt.c +52 -17
- data/ext/oci8/win32.c +4 -22
- data/lib/oci8/bindtype.rb +1 -15
- data/lib/oci8/check_load_error.rb +57 -10
- data/lib/oci8/cursor.rb +57 -25
- data/lib/oci8/metadata.rb +9 -1
- data/lib/oci8/object.rb +10 -0
- data/lib/oci8/oci8.rb +33 -28
- data/lib/oci8/oracle_version.rb +11 -1
- data/lib/oci8/properties.rb +22 -0
- data/lib/oci8/version.rb +1 -1
- data/lib/oci8.rb +48 -4
- data/lib/ruby-oci8.rb +0 -3
- data/pre-distclean.rb +1 -3
- data/ruby-oci8.gemspec +3 -8
- data/setup.rb +11 -2
- data/test/README.md +37 -0
- data/test/config.rb +1 -1
- data/test/setup_test_object.sql +21 -13
- data/test/setup_test_package.sql +59 -0
- data/test/test_all.rb +2 -0
- data/test/test_bind_boolean.rb +99 -0
- data/test/test_bind_integer.rb +47 -0
- data/test/test_break.rb +11 -9
- data/test/test_clob.rb +4 -16
- data/test/test_connstr.rb +29 -13
- data/test/test_datetime.rb +8 -3
- data/test/test_object.rb +27 -9
- data/test/test_oci8.rb +170 -46
- data/test/test_oranumber.rb +12 -6
- data/test/test_package_type.rb +15 -3
- data/test/test_properties.rb +17 -0
- metadata +40 -54
- data/docs/osx-install-dev-tools.png +0 -0
- data/test/README +0 -42
data/ext/oci8/plthook_osx.c
CHANGED
@@ -73,10 +73,10 @@ struct plthook {
|
|
73
73
|
};
|
74
74
|
|
75
75
|
static int plthook_open_real(plthook_t **plthook_out, const struct mach_header *mh);
|
76
|
-
static unsigned int get_bind_addr(plthook_t *plthook, const uint8_t *base, uint32_t lazy_bind_off, uint32_t lazy_bind_size, struct segment_command_ **segments,
|
76
|
+
static unsigned int get_bind_addr(plthook_t *plthook, const uint8_t *base, uint32_t lazy_bind_off, uint32_t lazy_bind_size, struct segment_command_ **segments, ptrdiff_t addrdiff);
|
77
77
|
|
78
78
|
static void set_errmsg(const char *fmt, ...) __attribute__((__format__ (__printf__, 1, 2)));
|
79
|
-
static void set_bind_addr(unsigned int *idx, plthook_t *plthook, const uint8_t *base, const char *sym_name, int seg_index,
|
79
|
+
static void set_bind_addr(unsigned int *idx, plthook_t *plthook, const uint8_t *base, const char *sym_name, int seg_index, uint64_t seg_offset, struct segment_command_ **segments);
|
80
80
|
|
81
81
|
static uint64_t uleb128(const uint8_t **p)
|
82
82
|
{
|
@@ -142,6 +142,37 @@ int plthook_open(plthook_t **plthook_out, const char *filename)
|
|
142
142
|
return plthook_open_real(plthook_out, _dyld_get_image_header(idx));
|
143
143
|
}
|
144
144
|
|
145
|
+
int plthook_open_by_handle(plthook_t **plthook_out, void *hndl)
|
146
|
+
{
|
147
|
+
int flags[] = {
|
148
|
+
RTLD_LAZY | RTLD_NOLOAD,
|
149
|
+
RTLD_LAZY | RTLD_NOLOAD | RTLD_FIRST,
|
150
|
+
};
|
151
|
+
size_t flag_idx;
|
152
|
+
#define NUM_FLAGS (sizeof(flags) / sizeof(flags[0]))
|
153
|
+
|
154
|
+
if (hndl == NULL) {
|
155
|
+
set_errmsg("NULL handle");
|
156
|
+
return PLTHOOK_FILE_NOT_FOUND;
|
157
|
+
}
|
158
|
+
for (flag_idx = 0; flag_idx < NUM_FLAGS; flag_idx++) {
|
159
|
+
const char *image_name = NULL;
|
160
|
+
uint32_t idx = 0;
|
161
|
+
|
162
|
+
do {
|
163
|
+
void *handle = dlopen(image_name, flags[flag_idx]);
|
164
|
+
if (handle != NULL) {
|
165
|
+
dlclose(handle);
|
166
|
+
if (handle == hndl) {
|
167
|
+
return plthook_open_real(plthook_out, _dyld_get_image_header(idx));
|
168
|
+
}
|
169
|
+
}
|
170
|
+
} while ((image_name = _dyld_get_image_name(++idx)) != NULL);
|
171
|
+
}
|
172
|
+
set_errmsg("Cannot find the image correspond to handle %p", hndl);
|
173
|
+
return PLTHOOK_FILE_NOT_FOUND;
|
174
|
+
}
|
175
|
+
|
145
176
|
int plthook_open_by_address(plthook_t **plthook_out, void *address)
|
146
177
|
{
|
147
178
|
Dl_info dlinfo;
|
@@ -165,8 +196,8 @@ static int plthook_open_real(plthook_t **plthook_out, const struct mach_header *
|
|
165
196
|
struct segment_command_ *segments[NUM_SEGMENTS];
|
166
197
|
int segment_idx = 0;
|
167
198
|
unsigned int nbind;
|
168
|
-
|
169
|
-
|
199
|
+
ptrdiff_t addrdiff = 0;
|
200
|
+
uint32_t i;
|
170
201
|
|
171
202
|
memset(segments, 0, sizeof(segments));
|
172
203
|
#ifdef __LP64__
|
@@ -289,14 +320,14 @@ static int plthook_open_real(plthook_t **plthook_out, const struct mach_header *
|
|
289
320
|
return 0;
|
290
321
|
}
|
291
322
|
|
292
|
-
static unsigned int get_bind_addr(plthook_t *plthook, const uint8_t *base, uint32_t lazy_bind_off, uint32_t lazy_bind_size, struct segment_command_ **segments,
|
323
|
+
static unsigned int get_bind_addr(plthook_t *plthook, const uint8_t *base, uint32_t lazy_bind_off, uint32_t lazy_bind_size, struct segment_command_ **segments, ptrdiff_t addrdiff)
|
293
324
|
{
|
294
325
|
const uint8_t *ptr = base + lazy_bind_off + addrdiff;
|
295
326
|
const uint8_t *end = ptr + lazy_bind_size;
|
296
327
|
const char *sym_name;
|
297
328
|
int seg_index = 0;
|
298
329
|
uint64_t seg_offset = 0;
|
299
|
-
|
330
|
+
uint64_t count, skip;
|
300
331
|
unsigned int idx;
|
301
332
|
DEBUG_BIND("get_bind_addr(%p, 0x%x, 0x%x", base, lazy_bind_off, lazy_bind_size);
|
302
333
|
for (idx = 0; segments[idx] != NULL; idx++) {
|
@@ -310,7 +341,7 @@ static unsigned int get_bind_addr(plthook_t *plthook, const uint8_t *base, uint3
|
|
310
341
|
uint8_t imm = *ptr & BIND_IMMEDIATE_MASK;
|
311
342
|
uint64_t ulebval;
|
312
343
|
int64_t slebval;
|
313
|
-
|
344
|
+
uint64_t i;
|
314
345
|
|
315
346
|
DEBUG_BIND("0x%02x: ", *ptr);
|
316
347
|
ptr++;
|
@@ -379,10 +410,10 @@ static unsigned int get_bind_addr(plthook_t *plthook, const uint8_t *base, uint3
|
|
379
410
|
return idx;
|
380
411
|
}
|
381
412
|
|
382
|
-
static void set_bind_addr(unsigned int *idx, plthook_t *plthook, const uint8_t *base, const char *sym_name, int seg_index,
|
413
|
+
static void set_bind_addr(unsigned int *idx, plthook_t *plthook, const uint8_t *base, const char *sym_name, int seg_index, uint64_t seg_offset, struct segment_command_ **segments)
|
383
414
|
{
|
384
415
|
if (plthook != NULL) {
|
385
|
-
|
416
|
+
uint64_t vmaddr = segments[seg_index]->vmaddr;
|
386
417
|
plthook->entries[*idx].name = sym_name;
|
387
418
|
plthook->entries[*idx].addr = (void**)(base + vmaddr + seg_offset);
|
388
419
|
}
|
data/ext/oci8/plthook_win32.c
CHANGED
@@ -93,6 +93,15 @@ int plthook_open(plthook_t **plthook_out, const char *filename)
|
|
93
93
|
return plthook_open_real(plthook_out, hMod);
|
94
94
|
}
|
95
95
|
|
96
|
+
int plthook_open_by_handle(plthook_t **plthook_out, void *hndl)
|
97
|
+
{
|
98
|
+
if (hndl == NULL) {
|
99
|
+
set_errmsg("NULL handle");
|
100
|
+
return PLTHOOK_FILE_NOT_FOUND;
|
101
|
+
}
|
102
|
+
return plthook_open_real(plthook_out, (HMODULE)hndl);
|
103
|
+
}
|
104
|
+
|
96
105
|
int plthook_open_by_address(plthook_t **plthook_out, void *address)
|
97
106
|
{
|
98
107
|
HMODULE hMod;
|
data/ext/oci8/stmt.c
CHANGED
@@ -15,7 +15,8 @@ static VALUE cOCIStmt;
|
|
15
15
|
typedef struct {
|
16
16
|
oci8_base_t base;
|
17
17
|
VALUE svc;
|
18
|
-
|
18
|
+
char use_stmt_release;
|
19
|
+
char end_of_fetch;
|
19
20
|
} oci8_stmt_t;
|
20
21
|
|
21
22
|
static void oci8_stmt_mark(oci8_base_t *base)
|
@@ -77,7 +78,7 @@ static VALUE oci8_stmt_initialize(VALUE self, VALUE svc, VALUE sql)
|
|
77
78
|
if (!NIL_P(sql)) {
|
78
79
|
OCI8SafeStringValue(sql);
|
79
80
|
|
80
|
-
rv = OCIStmtPrepare2(svcctx->base.hp.svc, &stmt->base.hp.stmt, oci8_errhp, RSTRING_ORATEXT(sql),
|
81
|
+
rv = OCIStmtPrepare2(svcctx->base.hp.svc, &stmt->base.hp.stmt, oci8_errhp, RSTRING_ORATEXT(sql), RSTRING_LENINT(sql), NULL, 0, OCI_NTV_SYNTAX, OCI_DEFAULT);
|
81
82
|
if (IS_OCI_ERROR(rv)) {
|
82
83
|
chker2(rv, &svcctx->base);
|
83
84
|
}
|
@@ -111,12 +112,24 @@ static VALUE oci8_define_by_pos(VALUE self, VALUE vposition, VALUE vbindobj)
|
|
111
112
|
oci8_bind_t *obind = TO_BIND(vbindobj);
|
112
113
|
const oci8_bind_data_type_t *data_type;
|
113
114
|
sword status;
|
115
|
+
void *valuep;
|
116
|
+
void *indp;
|
117
|
+
ub4 mode;
|
114
118
|
|
115
119
|
if (obind->base.hp.dfn != NULL) {
|
116
120
|
oci8_base_free(&obind->base); /* TODO: OK? */
|
117
121
|
}
|
118
122
|
data_type = (const oci8_bind_data_type_t *)obind->base.data_type;
|
119
|
-
|
123
|
+
if (obind->value_sz != SB4MAXVAL) {
|
124
|
+
valuep = obind->valuep;
|
125
|
+
indp = NIL_P(obind->tdo) ? obind->u.inds : NULL;
|
126
|
+
mode = OCI_DEFAULT;
|
127
|
+
} else {
|
128
|
+
valuep = NULL;
|
129
|
+
indp = NULL;
|
130
|
+
mode = OCI_DYNAMIC_FETCH;
|
131
|
+
}
|
132
|
+
status = OCIDefineByPos(stmt->base.hp.stmt, &obind->base.hp.dfn, oci8_errhp, position, valuep, obind->value_sz, data_type->dty, indp, NULL, 0, mode);
|
120
133
|
if (status != OCI_SUCCESS) {
|
121
134
|
chker3(status, &stmt->base, stmt->base.hp.ptr);
|
122
135
|
}
|
@@ -151,7 +164,9 @@ static VALUE oci8_bind(VALUE self, VALUE vplaceholder, VALUE vbindobj)
|
|
151
164
|
oci8_bind_t *obind;
|
152
165
|
const oci8_bind_data_type_t *data_type;
|
153
166
|
sword status;
|
167
|
+
void *valuep;
|
154
168
|
void *indp;
|
169
|
+
ub4 mode;
|
155
170
|
|
156
171
|
if (NIL_P(vplaceholder)) { /* 1 */
|
157
172
|
placeholder_ptr = NULL;
|
@@ -163,10 +178,10 @@ static VALUE oci8_bind(VALUE self, VALUE vplaceholder, VALUE vbindobj)
|
|
163
178
|
*/
|
164
179
|
VALUE symval = rb_sym2str(vplaceholder);
|
165
180
|
const char *symname = RSTRING_PTR(symval);
|
166
|
-
|
181
|
+
ub4 len = RSTRING_LENINT(symval);
|
167
182
|
#else
|
168
183
|
const char *symname = rb_id2name(SYM2ID(vplaceholder));
|
169
|
-
|
184
|
+
ub4 len = (ub4)strlen(symname);
|
170
185
|
#endif
|
171
186
|
placeholder_ptr = ALLOCA_N(char, len + 1);
|
172
187
|
placeholder_len = len + 1;
|
@@ -177,7 +192,7 @@ static VALUE oci8_bind(VALUE self, VALUE vplaceholder, VALUE vbindobj)
|
|
177
192
|
} else {
|
178
193
|
OCI8StringValue(vplaceholder);
|
179
194
|
placeholder_ptr = RSTRING_PTR(vplaceholder);
|
180
|
-
placeholder_len =
|
195
|
+
placeholder_len = RSTRING_LENINT(vplaceholder);
|
181
196
|
}
|
182
197
|
obind = TO_BIND(vbindobj); /* 2 */
|
183
198
|
if (obind->base.hp.bnd != NULL) {
|
@@ -185,11 +200,19 @@ static VALUE oci8_bind(VALUE self, VALUE vplaceholder, VALUE vbindobj)
|
|
185
200
|
}
|
186
201
|
data_type = (const oci8_bind_data_type_t *)obind->base.data_type;
|
187
202
|
|
188
|
-
|
203
|
+
if (obind->value_sz != SB4MAXVAL) {
|
204
|
+
valuep = obind->valuep;
|
205
|
+
indp = NIL_P(obind->tdo) ? obind->u.inds : NULL;
|
206
|
+
mode = OCI_DEFAULT;
|
207
|
+
} else {
|
208
|
+
valuep = NULL;
|
209
|
+
indp = NULL;
|
210
|
+
mode = OCI_DATA_AT_EXEC;
|
211
|
+
}
|
189
212
|
if (placeholder_ptr == (char*)-1) {
|
190
|
-
status = OCIBindByPos(stmt->base.hp.stmt, &obind->base.hp.bnd, oci8_errhp, position,
|
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);
|
191
214
|
} else {
|
192
|
-
status = OCIBindByName(stmt->base.hp.stmt, &obind->base.hp.bnd, oci8_errhp, TO_ORATEXT(placeholder_ptr), placeholder_len,
|
215
|
+
status = OCIBindByName(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);
|
193
216
|
}
|
194
217
|
if (status != OCI_SUCCESS) {
|
195
218
|
chker3(status, &stmt->base, stmt->base.hp.stmt);
|
@@ -238,6 +261,7 @@ static VALUE oci8_stmt_execute(VALUE self, VALUE iteration_count)
|
|
238
261
|
oci8_stmt_t *stmt = TO_STMT(self);
|
239
262
|
oci8_svcctx_t *svcctx = oci8_get_svcctx(stmt->svc);
|
240
263
|
|
264
|
+
stmt->end_of_fetch = 0;
|
241
265
|
chker3(oci8_call_stmt_execute(svcctx, stmt, NUM2UINT(iteration_count),
|
242
266
|
svcctx->is_autocommit ? OCI_COMMIT_ON_SUCCESS : OCI_DEFAULT),
|
243
267
|
&stmt->base, stmt->base.hp.stmt);
|
@@ -245,7 +269,7 @@ static VALUE oci8_stmt_execute(VALUE self, VALUE iteration_count)
|
|
245
269
|
}
|
246
270
|
|
247
271
|
/*
|
248
|
-
* @overload __fetch(connection)
|
272
|
+
* @overload __fetch(connection, max_rows)
|
249
273
|
*
|
250
274
|
* Fetches one row and set the result to <code>@define_handles</code>.
|
251
275
|
* This is called by private methods of OCI8::Cursor.
|
@@ -255,13 +279,18 @@ static VALUE oci8_stmt_execute(VALUE self, VALUE iteration_count)
|
|
255
279
|
*
|
256
280
|
* @private
|
257
281
|
*/
|
258
|
-
static VALUE oci8_stmt_fetch(VALUE self, VALUE svc)
|
282
|
+
static VALUE oci8_stmt_fetch(VALUE self, VALUE svc, VALUE max_rows)
|
259
283
|
{
|
260
284
|
oci8_stmt_t *stmt = TO_STMT(self);
|
261
285
|
oci8_svcctx_t *svcctx = oci8_get_svcctx(svc);
|
262
286
|
sword rv;
|
263
287
|
oci8_bind_t *obind;
|
264
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
|
+
}
|
265
294
|
|
266
295
|
if (stmt->base.children != NULL) {
|
267
296
|
obind = (oci8_bind_t *)stmt->base.children;
|
@@ -271,16 +300,22 @@ static VALUE oci8_stmt_fetch(VALUE self, VALUE svc)
|
|
271
300
|
if (data_type->pre_fetch_hook != NULL) {
|
272
301
|
data_type->pre_fetch_hook(obind, stmt->svc);
|
273
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
|
+
}
|
274
306
|
}
|
275
307
|
obind = (oci8_bind_t *)obind->base.next;
|
276
308
|
} while (obind != (oci8_bind_t*)stmt->base.children);
|
277
309
|
}
|
278
|
-
rv = OCIStmtFetch_nb(svcctx, stmt->base.hp.stmt, oci8_errhp,
|
310
|
+
rv = OCIStmtFetch_nb(svcctx, stmt->base.hp.stmt, oci8_errhp, nrows, OCI_FETCH_NEXT, OCI_DEFAULT);
|
279
311
|
if (rv == OCI_NO_DATA) {
|
280
|
-
|
312
|
+
stmt->end_of_fetch = 1;
|
313
|
+
} else {
|
314
|
+
chker3(rv, &svcctx->base, stmt->base.hp.stmt);
|
281
315
|
}
|
282
|
-
|
283
|
-
|
316
|
+
chker2(OCIAttrGet(stmt->base.hp.stmt, OCI_HTYPE_STMT, &nrows, 0, OCI_ATTR_ROWS_FETCHED, oci8_errhp),
|
317
|
+
&svcctx->base);
|
318
|
+
return nrows ? UINT2NUM(nrows) : Qnil;
|
284
319
|
}
|
285
320
|
|
286
321
|
/*
|
@@ -288,7 +323,7 @@ static VALUE oci8_stmt_fetch(VALUE self, VALUE svc)
|
|
288
323
|
*
|
289
324
|
* Returns the definition of column specified by <i>pos</i>
|
290
325
|
*
|
291
|
-
* @param [
|
326
|
+
* @param [Integer] pos Column position which starts from one
|
292
327
|
* @return [OCI8::Metadata::Base]
|
293
328
|
*
|
294
329
|
* @private
|
@@ -405,7 +440,7 @@ void Init_oci8_stmt(VALUE cOCI8)
|
|
405
440
|
rb_define_private_method(cOCIStmt, "__define", oci8_define_by_pos, 2);
|
406
441
|
rb_define_private_method(cOCIStmt, "__bind", oci8_bind, 2);
|
407
442
|
rb_define_private_method(cOCIStmt, "__execute", oci8_stmt_execute, 1);
|
408
|
-
rb_define_private_method(cOCIStmt, "__fetch", oci8_stmt_fetch,
|
443
|
+
rb_define_private_method(cOCIStmt, "__fetch", oci8_stmt_fetch, 2);
|
409
444
|
rb_define_private_method(cOCIStmt, "__paramGet", oci8_stmt_get_param, 1);
|
410
445
|
rb_define_method(cOCIStmt, "rowid", oci8_stmt_get_rowid, 0);
|
411
446
|
|
data/ext/oci8/win32.c
CHANGED
@@ -21,33 +21,14 @@
|
|
21
21
|
* @private
|
22
22
|
*/
|
23
23
|
|
24
|
-
NORETURN(static void raise_error(void));
|
25
|
-
|
26
|
-
static void raise_error(void)
|
27
|
-
{
|
28
|
-
char msg[1024];
|
29
|
-
int err = GetLastError();
|
30
|
-
char *p;
|
31
|
-
|
32
|
-
sprintf(msg, "%d: ", err);
|
33
|
-
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
34
|
-
NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
35
|
-
msg + strlen(msg), sizeof(msg) - strlen(msg), NULL);
|
36
|
-
for (p = msg; *p != '\0'; p++) {
|
37
|
-
if (*p == '\n' || *p == '\r') {
|
38
|
-
*p = ' ';
|
39
|
-
}
|
40
|
-
}
|
41
|
-
rb_raise(rb_eRuntimeError, "%s", msg);
|
42
|
-
}
|
43
|
-
|
44
24
|
typedef struct {
|
45
25
|
HKEY hKey;
|
46
26
|
HKEY hSubKey;
|
47
27
|
} enum_homes_arg_t;
|
48
28
|
|
49
|
-
static VALUE enum_homes_real(
|
29
|
+
static VALUE enum_homes_real(VALUE varg)
|
50
30
|
{
|
31
|
+
enum_homes_arg_t *arg = (enum_homes_arg_t *)varg;
|
51
32
|
LONG rv;
|
52
33
|
DWORD type;
|
53
34
|
DWORD idx;
|
@@ -97,8 +78,9 @@ static VALUE enum_homes_real(enum_homes_arg_t *arg)
|
|
97
78
|
return Qnil;
|
98
79
|
}
|
99
80
|
|
100
|
-
static VALUE enum_homes_ensure(
|
81
|
+
static VALUE enum_homes_ensure(VALUE varg)
|
101
82
|
{
|
83
|
+
enum_homes_arg_t *arg = (enum_homes_arg_t *)varg;
|
102
84
|
if (arg->hKey != NULL) {
|
103
85
|
RegCloseKey(arg->hKey);
|
104
86
|
arg->hKey = NULL;
|
data/lib/oci8/bindtype.rb
CHANGED
@@ -49,7 +49,7 @@ class OCI8
|
|
49
49
|
|
50
50
|
class BasicNumberType < OCI8::BindType::OraNumber
|
51
51
|
def get()
|
52
|
-
(val = super()) && (val.
|
52
|
+
(val = super()) && (val.has_fractional_part? ? val.to_f : val.to_i)
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
@@ -172,20 +172,6 @@ class OCI8
|
|
172
172
|
end
|
173
173
|
end
|
174
174
|
|
175
|
-
class Long < OCI8::BindType::String
|
176
|
-
def self.create(con, val, param, max_array_size)
|
177
|
-
param = {:length => con.long_read_len, :char_semantics => true}
|
178
|
-
super(con, val, param, max_array_size)
|
179
|
-
end
|
180
|
-
end
|
181
|
-
|
182
|
-
class LongRaw < OCI8::BindType::RAW
|
183
|
-
def self.create(con, val, param, max_array_size)
|
184
|
-
param = {:length => con.long_read_len, :char_semantics => false}
|
185
|
-
self.new(con, val, param, max_array_size)
|
186
|
-
end
|
187
|
-
end
|
188
|
-
|
189
175
|
class CLOB
|
190
176
|
def self.create(con, val, param, max_array_size)
|
191
177
|
if param.is_a? OCI8::Metadata::Base and param.charset_form == :nchar
|
@@ -4,32 +4,79 @@ class OCI8
|
|
4
4
|
module Util
|
5
5
|
|
6
6
|
case RUBY_PLATFORM
|
7
|
-
when /mswin32|cygwin|
|
7
|
+
when /mswin32|cygwin|mingw/
|
8
|
+
|
9
|
+
require 'fiddle/import'
|
10
|
+
require 'fiddle/types'
|
11
|
+
|
12
|
+
extend Fiddle::Importer
|
13
|
+
dlload 'kernel32.dll'
|
14
|
+
include Fiddle::BasicTypes
|
15
|
+
include Fiddle::Win32Types
|
16
|
+
|
17
|
+
typealias "HANDLE", "void*"
|
18
|
+
typealias "HMODULE", "void*"
|
19
|
+
extern "DWORD GetModuleFileNameA(HMODULE, LPSTR, DWORD)"
|
20
|
+
extern "UINT GetSystemDirectoryA(LPCSTR, UINT)"
|
21
|
+
extern "UINT GetWindowsDirectoryA(LPCSTR, UINT)"
|
22
|
+
extern "HMODULE LoadLibraryExA(LPCSTR, HANDLE, DWORD)"
|
23
|
+
extern "BOOL FreeLibrary(HMODULE)"
|
8
24
|
|
9
|
-
require 'Win32API'
|
10
25
|
MAX_PATH = 260
|
11
|
-
|
12
|
-
GetSystemDirectoryA = Win32API.new('kernel32', 'GetSystemDirectoryA', 'PL', 'L')
|
13
|
-
GetWindowsDirectoryA = Win32API.new('kernel32', 'GetWindowsDirectoryA', 'PL', 'L')
|
26
|
+
DONT_RESOLVE_DLL_REFERENCES = 0x00000001
|
14
27
|
|
15
28
|
def self.check_os_specific_load_error(exc)
|
16
29
|
case exc.message
|
17
|
-
when /^193: / # "
|
30
|
+
when /^OCI\.DLL: 193\(/, /^193: / # "OCI.DLL: 193(%1 is not a valid Win32 application.)" in English
|
18
31
|
check_win32_pe_arch(exc.message.split(' - ')[1], "ruby-oci8")
|
19
32
|
dll_load_path_list.each do |path|
|
20
33
|
check_win32_pe_arch(File.join(path, '\OCI.DLL'), "Oracle client")
|
21
34
|
end
|
35
|
+
when /^OCI.DLL: 126\(/, /^126: / # "OCI.DLL: 126(The specified module could not be found.)" in English
|
36
|
+
oci_dll_files = dll_load_path_list.inject([]) do |files, path|
|
37
|
+
file = File.join(path, '\OCI.DLL')
|
38
|
+
files << file if File.exist?(file)
|
39
|
+
files
|
40
|
+
end
|
41
|
+
if oci_dll_files.empty?
|
42
|
+
raise LoadError, "Cannot find OCI.DLL in PATH."
|
43
|
+
end
|
44
|
+
if oci_dll_files.none? {|file| open(file, 'rb') {true} rescue false}
|
45
|
+
raise LoadError, "OCI.DLL in PATH isn't readable."
|
46
|
+
end
|
47
|
+
first_error = nil
|
48
|
+
oci_dll_files.each do |file|
|
49
|
+
begin
|
50
|
+
check_win32_pe_arch(file, "Oracle client")
|
51
|
+
valid_arch = true
|
52
|
+
rescue LoadError
|
53
|
+
first_error ||= $!
|
54
|
+
valid_arch = false
|
55
|
+
end
|
56
|
+
if valid_arch
|
57
|
+
handle = LoadLibraryExA(file, nil, DONT_RESOLVE_DLL_REFERENCES)
|
58
|
+
unless handle.null?
|
59
|
+
FreeLibrary(handle)
|
60
|
+
raise LoadError, <<EOS
|
61
|
+
Cannot find DLLs depended by #{file}.
|
62
|
+
See http://www.rubydoc.info/github/kubo/ruby-oci8/file/docs/install-instant-client.md#Windows
|
63
|
+
EOS
|
64
|
+
end
|
65
|
+
break
|
66
|
+
end
|
67
|
+
end
|
68
|
+
raise first_error if first_error
|
22
69
|
end
|
23
70
|
end # self.check_os_specific_load_error
|
24
71
|
|
25
72
|
def self.dll_load_path_list
|
26
73
|
buf = "\0" * MAX_PATH
|
27
74
|
paths = []
|
28
|
-
paths << buf[0, GetModuleFileNameA
|
29
|
-
paths << buf[0, GetSystemDirectoryA
|
30
|
-
paths << buf[0, GetWindowsDirectoryA
|
75
|
+
paths << buf[0, GetModuleFileNameA(nil, buf, MAX_PATH)].force_encoding("locale").gsub(/\\[^\\]*$/, '')
|
76
|
+
paths << buf[0, GetSystemDirectoryA(buf, MAX_PATH)].force_encoding("locale")
|
77
|
+
paths << buf[0, GetWindowsDirectoryA(buf, MAX_PATH)].force_encoding("locale")
|
31
78
|
paths << "."
|
32
|
-
paths + ENV['PATH'].split(';')
|
79
|
+
paths + (ENV['PATH'].split(';').reject {|path| path.empty?})
|
33
80
|
end # self.dll_load_path_list
|
34
81
|
|
35
82
|
def self.check_win32_pe_arch(filename, package)
|
data/lib/oci8/cursor.rb
CHANGED
@@ -25,7 +25,11 @@ class OCI8
|
|
25
25
|
@names = nil
|
26
26
|
@con = conn
|
27
27
|
@max_array_size = nil
|
28
|
+
@fetch_array_size = nil
|
29
|
+
@rowbuf_size = 0
|
30
|
+
@rowbuf_index = 0
|
28
31
|
__initialize(conn, sql) # Initialize the internal C structure.
|
32
|
+
self.prefetch_rows = conn.instance_variable_get(:@prefetch_rows)
|
29
33
|
end
|
30
34
|
|
31
35
|
# explicitly indicate the date type of fetched value. run this
|
@@ -38,7 +42,7 @@ class OCI8
|
|
38
42
|
# cursor.define(2, Time) # fetch the second column as Time.
|
39
43
|
# cursor.exec()
|
40
44
|
def define(pos, type, length = nil)
|
41
|
-
bindobj = make_bind_object(:type => type, :length => length)
|
45
|
+
bindobj = make_bind_object({:type => type, :length => length}, @fetch_array_size || 1)
|
42
46
|
__define(pos, bindobj)
|
43
47
|
if old = @define_handles[pos - 1]
|
44
48
|
old.send(:free)
|
@@ -58,15 +62,16 @@ class OCI8
|
|
58
62
|
# # ...or...
|
59
63
|
# cursor.bind_param(':ename', 'SMITH') # bind by name
|
60
64
|
#
|
61
|
-
# To bind as number,
|
62
|
-
#
|
63
|
-
# +type+ and Fixnum or Float to +val+.
|
65
|
+
# To bind as number, set the number intself to +val+. If its initial value
|
66
|
+
# is NULL, please set nil to +type+ and Integer, Float or OraNumber to +val+.
|
64
67
|
#
|
65
68
|
# example:
|
66
|
-
# cursor.bind_param(1, 1234) # bind as
|
69
|
+
# cursor.bind_param(1, 1234) # bind as Integer, Initial value is 1234.
|
67
70
|
# cursor.bind_param(1, 1234.0) # bind as Float, Initial value is 1234.0.
|
68
|
-
# cursor.bind_param(1, nil,
|
71
|
+
# cursor.bind_param(1, nil, Integer) # bind as Integer, Initial value is NULL.
|
69
72
|
# cursor.bind_param(1, nil, Float) # bind as Float, Initial value is NULL.
|
73
|
+
# cursor.bind_param(1, OraNumber(1234)) # bind as OraNumber, Initial value is 1234.
|
74
|
+
# cursor.bind_param(1, nil, OraNumber) # bind as OraNumber, Initial value is NULL.
|
70
75
|
#
|
71
76
|
# In case of binding a string, set the string itself to
|
72
77
|
# +val+. When the bind variable is used as output, set the
|
@@ -124,7 +129,10 @@ class OCI8
|
|
124
129
|
case type
|
125
130
|
when :select_stmt
|
126
131
|
__execute(0)
|
127
|
-
define_columns()
|
132
|
+
define_columns() if @column_metadata.size == 0
|
133
|
+
@rowbuf_size = 0
|
134
|
+
@rowbuf_index = 0
|
135
|
+
@column_metadata.size
|
128
136
|
else
|
129
137
|
__execute(1)
|
130
138
|
row_count
|
@@ -379,9 +387,10 @@ class OCI8
|
|
379
387
|
#
|
380
388
|
# FYI: Rails oracle adaptor uses 100 by default.
|
381
389
|
#
|
382
|
-
# @param [
|
390
|
+
# @param [Integer] rows The number of rows to be prefetched
|
383
391
|
def prefetch_rows=(rows)
|
384
392
|
attr_set_ub4(11, rows) # OCI_ATTR_PREFETCH_ROWS(11)
|
393
|
+
@prefetch_rows = rows
|
385
394
|
end
|
386
395
|
|
387
396
|
if OCI8::oracle_client_version >= ORAVER_12_1
|
@@ -430,12 +439,12 @@ class OCI8
|
|
430
439
|
# * OCI8::STMT_ALTER
|
431
440
|
# * OCI8::STMT_BEGIN (PL/SQL block which starts with a BEGIN keyword)
|
432
441
|
# * OCI8::STMT_DECLARE (PL/SQL block which starts with a DECLARE keyword)
|
433
|
-
# * Other
|
442
|
+
# * Other Integer value undocumented in Oracle manuals.
|
434
443
|
#
|
435
444
|
# <em>Changes between ruby-oci8 1.0 and 2.0.</em>
|
436
445
|
#
|
437
446
|
# [ruby-oci8 2.0] OCI8::STMT_* are Symbols. (:select_stmt, :update_stmt, etc.)
|
438
|
-
# [ruby-oci8 1.0] OCI8::STMT_* are
|
447
|
+
# [ruby-oci8 1.0] OCI8::STMT_* are Integers. (1, 2, 3, etc.)
|
439
448
|
#
|
440
449
|
def type
|
441
450
|
# http://docs.oracle.com/cd/E11882_01/appdev.112/e10646/ociaahan.htm#sthref5506
|
@@ -466,7 +475,7 @@ class OCI8
|
|
466
475
|
|
467
476
|
private
|
468
477
|
|
469
|
-
def make_bind_object(param)
|
478
|
+
def make_bind_object(param, fetch_array_size = nil)
|
470
479
|
case param
|
471
480
|
when Hash
|
472
481
|
key = param[:type]
|
@@ -508,26 +517,38 @@ class OCI8
|
|
508
517
|
OCI8::BindType::Mapping[key] = bindclass if bindclass
|
509
518
|
end
|
510
519
|
raise "unsupported datatype: #{key}" if bindclass.nil?
|
511
|
-
bindclass.create(@con, val, param, max_array_size)
|
520
|
+
bindclass.create(@con, val, param, fetch_array_size || max_array_size)
|
512
521
|
end
|
513
522
|
|
523
|
+
@@use_array_fetch = false
|
524
|
+
|
514
525
|
def define_columns
|
515
526
|
# http://docs.oracle.com/cd/E11882_01/appdev.112/e10646/ociaahan.htm#sthref5494
|
516
527
|
num_cols = attr_get_ub4(18) # OCI_ATTR_PARAM_COUNT(18)
|
517
|
-
1.upto(num_cols) do |i|
|
518
|
-
|
519
|
-
|
520
|
-
|
528
|
+
@column_metadata = 1.upto(num_cols).collect do |i|
|
529
|
+
__paramGet(i)
|
530
|
+
end
|
531
|
+
if @define_handles.size == 0
|
532
|
+
use_array_fetch = @@use_array_fetch
|
533
|
+
@column_metadata.each do |md|
|
534
|
+
case md.data_type
|
535
|
+
when :clob, :blob, :bfile
|
536
|
+
# Rows prefetching doesn't work for CLOB, BLOB and BFILE.
|
537
|
+
# Use array fetching to get more than one row in a network round trip.
|
538
|
+
use_array_fetch = true
|
539
|
+
end
|
540
|
+
end
|
541
|
+
@fetch_array_size = @prefetch_rows if use_array_fetch
|
542
|
+
end
|
543
|
+
@column_metadata.each_with_index do |md, i|
|
544
|
+
define_one_column(i + 1, md) unless @define_handles[i]
|
521
545
|
end
|
522
546
|
num_cols
|
523
547
|
end
|
524
548
|
|
525
549
|
def define_one_column(pos, param)
|
526
|
-
bindobj = make_bind_object(param)
|
550
|
+
bindobj = make_bind_object(param, @fetch_array_size || 1)
|
527
551
|
__define(pos, bindobj)
|
528
|
-
if old = @define_handles[pos - 1]
|
529
|
-
old.send(:free)
|
530
|
-
end
|
531
552
|
@define_handles[pos - 1] = bindobj
|
532
553
|
end
|
533
554
|
|
@@ -541,22 +562,33 @@ class OCI8
|
|
541
562
|
end
|
542
563
|
end
|
543
564
|
|
565
|
+
def fetch_row_internal
|
566
|
+
if @rowbuf_size && @rowbuf_size == @rowbuf_index
|
567
|
+
@rowbuf_size = __fetch(@con, @fetch_array_size || 1)
|
568
|
+
@rowbuf_index = 0
|
569
|
+
end
|
570
|
+
@rowbuf_size
|
571
|
+
end
|
572
|
+
|
544
573
|
def fetch_one_row_as_array
|
545
|
-
if
|
546
|
-
@define_handles.collect do |handle|
|
547
|
-
handle.send(:get_data)
|
574
|
+
if fetch_row_internal
|
575
|
+
ret = @define_handles.collect do |handle|
|
576
|
+
handle.send(:get_data, @rowbuf_index)
|
548
577
|
end
|
578
|
+
@rowbuf_index += 1
|
579
|
+
ret
|
549
580
|
else
|
550
581
|
nil
|
551
582
|
end
|
552
583
|
end
|
553
584
|
|
554
585
|
def fetch_one_row_as_hash
|
555
|
-
if
|
586
|
+
if fetch_row_internal
|
556
587
|
ret = {}
|
557
588
|
get_col_names.each_with_index do |name, idx|
|
558
|
-
ret[name] = @define_handles[idx].send(:get_data)
|
589
|
+
ret[name] = @define_handles[idx].send(:get_data, @rowbuf_index)
|
559
590
|
end
|
591
|
+
@rowbuf_index += 1
|
560
592
|
ret
|
561
593
|
else
|
562
594
|
nil
|
data/lib/oci8/metadata.rb
CHANGED
@@ -1503,7 +1503,11 @@ class OCI8
|
|
1503
1503
|
attr_get_sb1(OCI_ATTR_SCALE)
|
1504
1504
|
end
|
1505
1505
|
|
1506
|
-
# The
|
1506
|
+
# The nest level.
|
1507
|
+
#
|
1508
|
+
# Oracle manual says that it always returns zero. However it returns
|
1509
|
+
# the depth of {OCI8::ArgBase#arguments} calls when #arguments returns
|
1510
|
+
# a non-empty array.
|
1507
1511
|
def level
|
1508
1512
|
attr_get_ub2(OCI_ATTR_LEVEL)
|
1509
1513
|
end
|
@@ -1607,6 +1611,10 @@ class OCI8
|
|
1607
1611
|
|
1608
1612
|
# The list of arguments at the next level (when the argument is
|
1609
1613
|
# of a record or table type).
|
1614
|
+
#
|
1615
|
+
# This method returns an array containing type information when
|
1616
|
+
# the type is a user-defined type and the Oracle server version
|
1617
|
+
# is 12c or earlier. Otherwise, it returns an empty array.
|
1610
1618
|
def arguments
|
1611
1619
|
@arguments ||= list_arguments.to_a
|
1612
1620
|
end
|
data/lib/oci8/object.rb
CHANGED
@@ -493,6 +493,16 @@ EOS
|
|
493
493
|
Proc.new do |val| datetime_to_array(val, :date) end, # set_proc
|
494
494
|
Proc.new do |val| array_to_time(val, :local) end, # get_proc
|
495
495
|
]
|
496
|
+
when :timestamp
|
497
|
+
[ATTR_TIMESTAMP, con, SIZE_OF_POINTER, 2, ALIGNMENT_OF_POINTER,
|
498
|
+
Proc.new do |val| datetime_to_array(val, :timestamp) end, # set_proc
|
499
|
+
Proc.new do |val| array_to_time(val, :local) end, # get_proc
|
500
|
+
]
|
501
|
+
when :timestamp_tz
|
502
|
+
[ATTR_TIMESTAMP_TZ, con, SIZE_OF_POINTER, 2, ALIGNMENT_OF_POINTER,
|
503
|
+
Proc.new do |val| datetime_to_array(val, :timestamp_tz) end, # set_proc
|
504
|
+
Proc.new do |val| array_to_time(val, nil) end, # get_proc
|
505
|
+
]
|
496
506
|
when :binary_double
|
497
507
|
[ATTR_BINARY_DOUBLE, nil, SIZE_OF_DOUBLE, 2, ALIGNMENT_OF_DOUBLE]
|
498
508
|
when :binary_float
|