ruby-oci8 2.2.6.1 → 2.2.7
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.
- data/ChangeLog +52 -3
- data/NEWS +106 -54
- data/dist-files +1 -1
- data/docs/install-instant-client.md +1 -0
- data/ext/oci8/apiwrap.yml +20 -0
- data/ext/oci8/bind.c +364 -3
- data/ext/oci8/lob.c +22 -29
- data/ext/oci8/object.c +37 -24
- data/ext/oci8/oci8.c +9 -11
- data/ext/oci8/oraconf.rb +2 -2
- data/ext/oci8/stmt.c +47 -12
- data/lib/oci8.rb +1 -1
- data/lib/oci8/bindtype.rb +0 -14
- data/lib/oci8/check_load_error.rb +51 -16
- data/lib/oci8/cursor.rb +46 -13
- data/lib/oci8/oci8.rb +1 -1
- data/lib/oci8/version.rb +1 -1
- data/ruby-oci8.gemspec +1 -2
- data/test/README.md +40 -0
- data/test/config.rb +1 -1
- data/test/test_oci8.rb +154 -43
- metadata +4 -6
- data/test/README +0 -42
data/ext/oci8/object.c
CHANGED
@@ -680,43 +680,53 @@ static VALUE oci8_named_collection_alloc(VALUE klass)
|
|
680
680
|
return oci8_allocate_typeddata(klass, &oci8_named_collection_data_type);
|
681
681
|
}
|
682
682
|
|
683
|
+
typedef struct {
|
684
|
+
oci8_bind_t bind;
|
685
|
+
VALUE *obj;
|
686
|
+
} bind_named_type_t;
|
687
|
+
|
683
688
|
static void bind_named_type_mark(oci8_base_t *base)
|
684
689
|
{
|
685
|
-
|
686
|
-
oci8_hp_obj_t *oho = (oci8_hp_obj_t *)obind->valuep;
|
690
|
+
bind_named_type_t *bnt = (bind_named_type_t *)base;
|
687
691
|
|
688
|
-
if (
|
692
|
+
if (bnt->obj != NULL) {
|
689
693
|
ub4 idx = 0;
|
690
694
|
|
691
695
|
do {
|
692
|
-
rb_gc_mark(
|
693
|
-
} while (++idx <
|
696
|
+
rb_gc_mark(bnt->obj[idx]);
|
697
|
+
} while (++idx < bnt->bind.maxar_sz);
|
694
698
|
}
|
695
|
-
rb_gc_mark(
|
699
|
+
rb_gc_mark(bnt->bind.tdo);
|
696
700
|
}
|
697
701
|
|
698
702
|
static void bind_named_type_free(oci8_base_t *base)
|
699
703
|
{
|
700
|
-
|
701
|
-
|
704
|
+
bind_named_type_t *bnt = (bind_named_type_t *)base;
|
705
|
+
void **hp = (void **)bnt->bind.valuep;
|
702
706
|
|
703
|
-
if (
|
707
|
+
if (hp != NULL) {
|
704
708
|
ub4 idx = 0;
|
705
709
|
|
706
710
|
do {
|
707
|
-
if (
|
708
|
-
OCIObjectFree(oci8_envhp, oci8_errhp,
|
709
|
-
|
711
|
+
if (hp[idx] != NULL) {
|
712
|
+
OCIObjectFree(oci8_envhp, oci8_errhp, hp[idx], OCI_DEFAULT);
|
713
|
+
hp[idx] = NULL;
|
710
714
|
}
|
711
|
-
} while (++idx <
|
715
|
+
} while (++idx < bnt->bind.maxar_sz);
|
716
|
+
}
|
717
|
+
if (bnt->obj != NULL) {
|
718
|
+
xfree(bnt->obj);
|
719
|
+
bnt->obj = NULL;
|
712
720
|
}
|
713
721
|
oci8_bind_free(base);
|
714
722
|
}
|
715
723
|
|
716
724
|
static VALUE bind_named_type_get(oci8_bind_t *obind, void *data, void *null_struct)
|
717
725
|
{
|
718
|
-
|
719
|
-
|
726
|
+
bind_named_type_t *bnt = (bind_named_type_t *)obind;
|
727
|
+
ub4 idx = obind->curar_idx;
|
728
|
+
|
729
|
+
return bnt->obj[idx];
|
720
730
|
}
|
721
731
|
|
722
732
|
static void bind_named_type_set(oci8_bind_t *obind, void *data, void **null_structp, VALUE val)
|
@@ -726,10 +736,12 @@ static void bind_named_type_set(oci8_bind_t *obind, void *data, void **null_stru
|
|
726
736
|
|
727
737
|
static void bind_named_type_init(oci8_bind_t *obind, VALUE svc, VALUE val, VALUE length)
|
728
738
|
{
|
739
|
+
bind_named_type_t *bnt = (bind_named_type_t *)obind;
|
729
740
|
VALUE tdo_obj = length;
|
730
741
|
|
731
742
|
obind->value_sz = sizeof(void*);
|
732
|
-
obind->alloc_sz = sizeof(
|
743
|
+
obind->alloc_sz = sizeof(void*);
|
744
|
+
bnt->obj = xcalloc(sizeof(VALUE), obind->maxar_sz ? obind->maxar_sz : 1);
|
733
745
|
|
734
746
|
CHECK_TDO(tdo_obj);
|
735
747
|
RB_OBJ_WRITE(obind->base.self, &obind->tdo, tdo_obj);
|
@@ -737,7 +749,8 @@ static void bind_named_type_init(oci8_bind_t *obind, VALUE svc, VALUE val, VALUE
|
|
737
749
|
|
738
750
|
static void bind_named_type_init_elem(oci8_bind_t *obind, VALUE svc)
|
739
751
|
{
|
740
|
-
|
752
|
+
bind_named_type_t *bnt = (bind_named_type_t *)obind;
|
753
|
+
void **hp = (void **)obind->valuep;
|
741
754
|
oci8_base_t *tdo = DATA_PTR(obind->tdo);
|
742
755
|
OCITypeCode tc = OCITypeTypeCode(oci8_envhp, oci8_errhp, tdo->hp.tdo);
|
743
756
|
VALUE klass = Qnil;
|
@@ -755,14 +768,14 @@ static void bind_named_type_init_elem(oci8_bind_t *obind, VALUE svc)
|
|
755
768
|
}
|
756
769
|
svcctx = oci8_get_svcctx(svc);
|
757
770
|
do {
|
758
|
-
|
759
|
-
RB_OBJ_WRITTEN(obind->base.self, Qundef,
|
760
|
-
obj = DATA_PTR(
|
761
|
-
RB_OBJ_WRITE(
|
762
|
-
obj->instancep = (char**)&
|
771
|
+
bnt->obj[idx] = rb_class_new_instance(0, NULL, klass);
|
772
|
+
RB_OBJ_WRITTEN(obind->base.self, Qundef, bnt->obj[idx]);
|
773
|
+
obj = DATA_PTR(bnt->obj[idx]);
|
774
|
+
RB_OBJ_WRITE(bnt->obj[idx], &obj->tdo, obind->tdo);
|
775
|
+
obj->instancep = (char**)&hp[idx];
|
763
776
|
obj->null_structp = (char**)&obind->u.null_structs[idx];
|
764
777
|
oci8_link_to_parent(&obj->base, &obind->base);
|
765
|
-
RB_OBJ_WRITTEN(
|
778
|
+
RB_OBJ_WRITTEN(bnt->obj[idx], Qundef, obind->base.self);
|
766
779
|
|
767
780
|
chker2(OCIObjectNew(oci8_envhp, oci8_errhp, svcctx->base.hp.svc, tc, tdo->hp.tdo, NULL, OCI_DURATION_SESSION, TRUE, (dvoid**)obj->instancep),
|
768
781
|
&svcctx->base);
|
@@ -804,7 +817,7 @@ static const oci8_bind_data_type_t bind_named_type_data_type = {
|
|
804
817
|
#endif
|
805
818
|
},
|
806
819
|
bind_named_type_free,
|
807
|
-
sizeof(
|
820
|
+
sizeof(bind_named_type_t)
|
808
821
|
},
|
809
822
|
bind_named_type_get,
|
810
823
|
bind_named_type_set,
|
data/ext/oci8/oci8.c
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
/*
|
3
3
|
* oci8.c - part of ruby-oci8
|
4
4
|
*
|
5
|
-
* Copyright (C) 2002-
|
5
|
+
* Copyright (C) 2002-2019 Kubo Takehiro <kubo@jiubao.org>
|
6
6
|
*
|
7
7
|
*/
|
8
8
|
#include "oci8.h"
|
@@ -734,14 +734,9 @@ static VALUE oci8_set_autocommit(VALUE self, VALUE val)
|
|
734
734
|
/*
|
735
735
|
* @overload long_read_len
|
736
736
|
*
|
737
|
-
*
|
738
|
-
*
|
739
|
-
*
|
740
|
-
* If the actual data length is longer than long_read_len,
|
741
|
-
* the fetched valud is truncated and the value of {OCI8#last_error}
|
742
|
-
* become {OCISuccessWithInfo} whose message is "ORA-01406: fetched column value was truncated".
|
743
|
-
*
|
744
|
-
* Note: long_read_len is also used for maximum length of XMLTYPE data type.
|
737
|
+
* @deprecated This has no effect since ruby-oci8 2.2.7.
|
738
|
+
* LONG, LONG RAW and XMLTYPE columns are fetched up to 4 gigabytes
|
739
|
+
* without this parameter.
|
745
740
|
*
|
746
741
|
* @return [Integer]
|
747
742
|
* @see #long_read_len=
|
@@ -749,14 +744,16 @@ static VALUE oci8_set_autocommit(VALUE self, VALUE val)
|
|
749
744
|
static VALUE oci8_long_read_len(VALUE self)
|
750
745
|
{
|
751
746
|
oci8_svcctx_t *svcctx = oci8_get_svcctx(self);
|
747
|
+
rb_warning("OCI8.long_read_len has no effect since ruby-oci8 2.2.7");
|
752
748
|
return svcctx->long_read_len;
|
753
749
|
}
|
754
750
|
|
755
751
|
/*
|
756
752
|
* @overload long_read_len=(length)
|
757
753
|
*
|
758
|
-
*
|
759
|
-
*
|
754
|
+
* @deprecated This has no effect since ruby-oci8 2.2.7.
|
755
|
+
* LONG, LONG RAW and XMLTYPE columns are fetched up to 4 gigabytes
|
756
|
+
* without this parameter.
|
760
757
|
*
|
761
758
|
* @param [Integer] length
|
762
759
|
* @see #long_read_len
|
@@ -766,6 +763,7 @@ static VALUE oci8_set_long_read_len(VALUE self, VALUE val)
|
|
766
763
|
oci8_svcctx_t *svcctx = oci8_get_svcctx(self);
|
767
764
|
Check_Type(val, T_FIXNUM);
|
768
765
|
RB_OBJ_WRITE(self, &svcctx->long_read_len, val);
|
766
|
+
rb_warning("OCI8.long_read_len= has no effect since ruby-oci8 2.2.7");
|
769
767
|
return val;
|
770
768
|
}
|
771
769
|
|
data/ext/oci8/oraconf.rb
CHANGED
@@ -584,7 +584,7 @@ EOS
|
|
584
584
|
if try_run("int main() { return 0; }")
|
585
585
|
puts "ok"
|
586
586
|
else
|
587
|
-
puts "
|
587
|
+
puts "failed"
|
588
588
|
raise "C compiler doesn't work correctly."
|
589
589
|
end
|
590
590
|
end # check_cc
|
@@ -630,7 +630,7 @@ EOS
|
|
630
630
|
STDOUT.flush
|
631
631
|
rubyhdrdir = RbConfig::CONFIG["rubyhdrdir"] || RbConfig::CONFIG['archdir']
|
632
632
|
unless File.exist?(rubyhdrdir + '/ruby.h')
|
633
|
-
puts "
|
633
|
+
puts "failed"
|
634
634
|
if RUBY_PLATFORM =~ /darwin/ and File.exist?("#{RbConfig::CONFIG['archdir']}/../universal-darwin8.0/ruby.h")
|
635
635
|
raise <<EOS
|
636
636
|
#{RbConfig::CONFIG['archdir']}/ruby.h doesn't exist.
|
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)
|
@@ -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;
|
@@ -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
|
/*
|
@@ -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/lib/oci8.rb
CHANGED
@@ -95,7 +95,7 @@ begin
|
|
95
95
|
|
96
96
|
ruby_arch = [nil].pack('P').size == 8 ? :x64 : :x86
|
97
97
|
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
98
|
-
if dll_arch.call(File.join(path, 'OCI.DLL')) == ruby_arch
|
98
|
+
if !path.empty? && dll_arch.call(File.join(path, 'OCI.DLL')) == ruby_arch
|
99
99
|
dll_dir = RubyInstaller::Runtime.add_dll_directory(path)
|
100
100
|
break
|
101
101
|
end
|
data/lib/oci8/bindtype.rb
CHANGED
@@ -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
|
@@ -6,14 +6,24 @@ class OCI8
|
|
6
6
|
case RUBY_PLATFORM
|
7
7
|
when /mswin32|cygwin|mingw32|bccwin32/
|
8
8
|
|
9
|
-
require '
|
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)"
|
24
|
+
|
10
25
|
MAX_PATH = 260
|
11
|
-
|
12
|
-
GetSystemDirectoryA = Win32API.new('kernel32.dll', 'GetSystemDirectoryA', 'PL', 'L')
|
13
|
-
GetWindowsDirectoryA = Win32API.new('kernel32.dll', 'GetWindowsDirectoryA', 'PL', 'L')
|
14
|
-
LoadLibraryExA = Win32API.new('kernel32.dll', 'LoadLibraryExA', 'PPL', 'P')
|
15
|
-
FreeLibrary = Win32API.new('kernel32.dll', 'FreeLibrary', 'P', 'L')
|
16
|
-
LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020
|
26
|
+
DONT_RESOLVE_DLL_REFERENCES = 0x00000001
|
17
27
|
|
18
28
|
def self.check_os_specific_load_error(exc)
|
19
29
|
case exc.message
|
@@ -23,25 +33,50 @@ class OCI8
|
|
23
33
|
check_win32_pe_arch(File.join(path, '\OCI.DLL'), "Oracle client")
|
24
34
|
end
|
25
35
|
when /^OCI.DLL: 126\(/, /^126: / # "OCI.DLL: 126(The specified module could not be found.)" in English
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
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}.
|
31
62
|
See http://www.rubydoc.info/github/kubo/ruby-oci8/file/docs/install-instant-client.md#Windows
|
32
63
|
EOS
|
64
|
+
end
|
65
|
+
break
|
66
|
+
end
|
33
67
|
end
|
68
|
+
raise first_error if first_error
|
34
69
|
end
|
35
70
|
end # self.check_os_specific_load_error
|
36
71
|
|
37
72
|
def self.dll_load_path_list
|
38
73
|
buf = "\0" * MAX_PATH
|
39
74
|
paths = []
|
40
|
-
paths << buf[0, GetModuleFileNameA
|
41
|
-
paths << buf[0, GetSystemDirectoryA
|
42
|
-
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")
|
43
78
|
paths << "."
|
44
|
-
paths + ENV['PATH'].split(';')
|
79
|
+
paths + (ENV['PATH'].split(';').reject {|path| path.empty?})
|
45
80
|
end # self.dll_load_path_list
|
46
81
|
|
47
82
|
def self.check_win32_pe_arch(filename, package)
|