ruby-oci8 2.2.0.2 → 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/.yardopts +1 -6
- data/ChangeLog +600 -0
- data/NEWS +426 -35
- data/README.md +27 -9
- data/dist-files +13 -2
- 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 +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 -117
- 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 +11 -8
- data/docs/timeout-parameters.md +94 -0
- data/ext/oci8/apiwrap.c.tmpl +2 -5
- data/ext/oci8/apiwrap.rb +6 -1
- data/ext/oci8/apiwrap.yml +39 -143
- data/ext/oci8/attr.c +4 -2
- data/ext/oci8/bind.c +421 -9
- 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 +35 -63
- data/ext/oci8/hook_funcs.c +274 -61
- data/ext/oci8/lob.c +31 -75
- data/ext/oci8/metadata.c +8 -6
- data/ext/oci8/object.c +119 -29
- data/ext/oci8/oci8.c +46 -133
- data/ext/oci8/oci8.h +40 -123
- data/ext/oci8/oci8lib.c +178 -46
- data/ext/oci8/ocihandle.c +37 -37
- data/ext/oci8/ocinumber.c +24 -35
- data/ext/oci8/oraconf.rb +168 -337
- 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 +16 -1
- data/ext/oci8/stmt.c +52 -17
- data/ext/oci8/win32.c +4 -22
- data/lib/oci8/bindtype.rb +10 -17
- data/lib/oci8/check_load_error.rb +57 -10
- data/lib/oci8/compat.rb +5 -1
- data/lib/oci8/connection_pool.rb +74 -3
- data/lib/oci8/cursor.rb +70 -31
- data/lib/oci8/metadata.rb +9 -1
- data/lib/oci8/object.rb +14 -1
- data/lib/oci8/oci8.rb +184 -58
- data/lib/oci8/ocihandle.rb +0 -16
- data/lib/oci8/oracle_version.rb +11 -1
- data/lib/oci8/properties.rb +55 -0
- data/lib/oci8/version.rb +1 -1
- data/lib/oci8.rb +48 -4
- data/lib/ruby-oci8.rb +1 -0
- data/pre-distclean.rb +1 -3
- data/ruby-oci8.gemspec +4 -9
- data/setup.rb +11 -2
- data/test/README.md +37 -0
- data/test/config.rb +8 -1
- data/test/setup_test_object.sql +42 -14
- data/test/setup_test_package.sql +59 -0
- data/test/test_all.rb +4 -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_break.rb +11 -9
- data/test/test_clob.rb +5 -17
- data/test/test_connstr.rb +142 -0
- data/test/test_datetime.rb +8 -3
- data/test/test_metadata.rb +2 -1
- data/test/test_object.rb +99 -18
- data/test/test_oci8.rb +170 -46
- data/test/test_oranumber.rb +12 -6
- data/test/test_package_type.rb +17 -3
- data/test/test_properties.rb +17 -0
- metadata +45 -55
- 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
@@ -51,12 +51,18 @@
|
|
51
51
|
#define __attribute__(arg)
|
52
52
|
#endif
|
53
53
|
|
54
|
-
#
|
54
|
+
#if defined _LP64 /* data model: I32/LP64 */
|
55
|
+
#define SIZE_T_FMT "lu"
|
56
|
+
#elif defined _WIN64 /* data model: IL32/P64 */
|
55
57
|
#define SIZE_T_FMT "I64u"
|
56
58
|
#else
|
57
59
|
#define SIZE_T_FMT "u"
|
58
60
|
#endif
|
59
61
|
|
62
|
+
#ifdef __CYGWIN__
|
63
|
+
#define stricmp strcasecmp
|
64
|
+
#endif
|
65
|
+
|
60
66
|
typedef struct {
|
61
67
|
const char *mod_name;
|
62
68
|
const char *name;
|
@@ -87,6 +93,15 @@ int plthook_open(plthook_t **plthook_out, const char *filename)
|
|
87
93
|
return plthook_open_real(plthook_out, hMod);
|
88
94
|
}
|
89
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
|
+
|
90
105
|
int plthook_open_by_address(plthook_t **plthook_out, void *address)
|
91
106
|
{
|
92
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
|
@@ -203,10 +189,13 @@ OCI8::BindType::Mapping[String] = OCI8::BindType::String
|
|
203
189
|
OCI8::BindType::Mapping[OraNumber] = OCI8::BindType::OraNumber
|
204
190
|
OCI8::BindType::Mapping['BigDecimal'] = OCI8::BindType::BigDecimal
|
205
191
|
OCI8::BindType::Mapping['Rational'] = OCI8::BindType::Rational
|
206
|
-
OCI8::BindType::Mapping[Fixnum] = OCI8::BindType::Integer
|
207
192
|
OCI8::BindType::Mapping[Float] = OCI8::BindType::Float
|
208
193
|
OCI8::BindType::Mapping[Integer] = OCI8::BindType::Integer
|
209
|
-
|
194
|
+
unless 0.class == Integer
|
195
|
+
# ruby before integer unification
|
196
|
+
OCI8::BindType::Mapping[Fixnum] = OCI8::BindType::Integer
|
197
|
+
OCI8::BindType::Mapping[Bignum] = OCI8::BindType::Integer
|
198
|
+
end
|
210
199
|
OCI8::BindType::Mapping[OraDate] = OCI8::BindType::OraDate
|
211
200
|
OCI8::BindType::Mapping[Time] = OCI8::BindType::Time
|
212
201
|
OCI8::BindType::Mapping[Date] = OCI8::BindType::Date
|
@@ -216,6 +205,10 @@ OCI8::BindType::Mapping[OCI8::NCLOB] = OCI8::BindType::NCLOB
|
|
216
205
|
OCI8::BindType::Mapping[OCI8::BLOB] = OCI8::BindType::BLOB
|
217
206
|
OCI8::BindType::Mapping[OCI8::BFILE] = OCI8::BindType::BFILE
|
218
207
|
OCI8::BindType::Mapping[OCI8::Cursor] = OCI8::BindType::Cursor
|
208
|
+
if defined? OCI8::BindType::Boolean
|
209
|
+
OCI8::BindType::Mapping[TrueClass] = OCI8::BindType::Boolean
|
210
|
+
OCI8::BindType::Mapping[FalseClass] = OCI8::BindType::Boolean
|
211
|
+
end
|
219
212
|
|
220
213
|
# implicitly define
|
221
214
|
|
@@ -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/compat.rb
CHANGED
@@ -70,7 +70,7 @@ class OCI8
|
|
70
70
|
constants.each do |name|
|
71
71
|
next if name.to_s.index("SQLT_") != 0
|
72
72
|
val = const_get name.intern
|
73
|
-
if val.is_a?
|
73
|
+
if val.is_a? Integer
|
74
74
|
SQLT_NAMES[val] = name
|
75
75
|
end
|
76
76
|
end
|
@@ -79,6 +79,10 @@ class OCI8
|
|
79
79
|
alias autocommit autocommit?
|
80
80
|
|
81
81
|
class Cursor
|
82
|
+
# @!visibility private
|
83
|
+
# dirty hack to suppress "warning: constant ::Fixnum is deprecated"
|
84
|
+
Fixnum = (0.class == ::Integer) ? ::Integer : ::Fixnum
|
85
|
+
|
82
86
|
def self.select_number_as=(val)
|
83
87
|
if val == Fixnum
|
84
88
|
@@bind_unknown_number = OCI8::BindType::Fixnum
|
data/lib/oci8/connection_pool.rb
CHANGED
@@ -13,17 +13,88 @@ class OCI8
|
|
13
13
|
#
|
14
14
|
# This is equivalent to Oracle JDBC Driver {OCI Connection Pooling}[http://docs.oracle.com/cd/E11882_01/java.112/e16548/ociconpl.htm#JJDBC28789].
|
15
15
|
#
|
16
|
-
#
|
16
|
+
# Note that this is different with generally called connection pooling.
|
17
|
+
# Generally connection pooling caches connections in a pool.
|
18
|
+
# When an application needs a new connection, a connection is got from
|
19
|
+
# the pool. So that the amount of time to establish a connection is
|
20
|
+
# reduced. However connection pooling in ruby-oci8 is different with
|
21
|
+
# above.
|
22
|
+
#
|
23
|
+
# One Oracle connection is devided into two layers: One is physical
|
24
|
+
# connection such as TCP/IP. The other is logical connection which
|
25
|
+
# is used by an application. The connection pooling in ruby-oci8
|
26
|
+
# caches physical connections in a pool, not logical connections.
|
27
|
+
# When an application needs a new connection, a logical connection
|
28
|
+
# is created via a physical connection, which needs time to
|
29
|
+
# establish a connection unlike generally called connection pooling.
|
30
|
+
# When an application sends a query via a logical connection, a
|
31
|
+
# physical connection is got from the pool. The physical connection
|
32
|
+
# returns to the pool automatically when the query finishes.
|
33
|
+
# As long as logical connections are used sequentially, only one
|
34
|
+
# physical connection is used. When an application sends
|
35
|
+
# queries at a time, it needs more than one physical connection
|
36
|
+
# because one physical connection cannot transmit more then one
|
37
|
+
# query at a time.
|
38
|
+
#
|
39
|
+
# Example:
|
17
40
|
# # Create a connection pool.
|
41
|
+
# # The number of initial physical connections: 1
|
42
|
+
# # The number of maximum physical connections: 5
|
43
|
+
# # the connection increment parameter: 2
|
18
44
|
# # username and password are required to establish an implicit primary session.
|
19
45
|
# cpool = OCI8::ConnectionPool.new(1, 5, 2, username, password, database)
|
20
46
|
#
|
21
|
-
# #
|
47
|
+
# # The number of physical connections: 1
|
48
|
+
# # The number of logical connections: 0
|
49
|
+
#
|
50
|
+
# # Create a session.
|
22
51
|
# # Pass the connection pool to the third argument.
|
23
52
|
# conn1 = OCI8.new(username, password, cpool)
|
24
53
|
#
|
25
|
-
# #
|
54
|
+
# # One logical connection was created.
|
55
|
+
# # The number of physical connections: 1
|
56
|
+
# # The number of logical connections: 1
|
57
|
+
#
|
58
|
+
# # Create another session.
|
26
59
|
# conn2 = OCI8.new(username, password, cpool)
|
60
|
+
#
|
61
|
+
# # Another logical connection was created.
|
62
|
+
# # The number of physical connections: 1
|
63
|
+
# # The number of logical connections: 2
|
64
|
+
#
|
65
|
+
# # Use conn1 and conn2 sequentially
|
66
|
+
# conn1.exec('...')
|
67
|
+
# conn2.exec('...')
|
68
|
+
#
|
69
|
+
# # Both logical connections use one physical connection.
|
70
|
+
# # The number of physical connections: 1
|
71
|
+
# # The number of logical connections: 2
|
72
|
+
#
|
73
|
+
# thr1 = Thread.new do
|
74
|
+
# conn1.exec('...')
|
75
|
+
# end
|
76
|
+
# thr2 = Thread.new do
|
77
|
+
# conn2.exec('...')
|
78
|
+
# end
|
79
|
+
# thr1.join
|
80
|
+
# thr2.join
|
81
|
+
#
|
82
|
+
# # Logical connections cannot use one physical connection at a time.
|
83
|
+
# # So that the number of physical connections is incremented.
|
84
|
+
# # The number of physical connections: 3
|
85
|
+
# # The number of logical connections: 2
|
86
|
+
#
|
87
|
+
# conn1.logoff
|
88
|
+
#
|
89
|
+
# # One logical connection was closed.
|
90
|
+
# # The number of physical connections: 3
|
91
|
+
# # The number of logical connections: 1
|
92
|
+
#
|
93
|
+
# conn2.logoff
|
94
|
+
#
|
95
|
+
# # All logical connections were closed.
|
96
|
+
# # The number of physical connections: 3
|
97
|
+
# # The number of logical connections: 0
|
27
98
|
#
|
28
99
|
class ConnectionPool
|
29
100
|
|