ruby-oci8 2.2.6.1 → 2.2.7
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|