ruby-oci8 2.2.3 → 2.2.12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +7 -0
  2. data/ChangeLog +427 -0
  3. data/NEWS +335 -42
  4. data/README.md +20 -9
  5. data/dist-files +9 -3
  6. data/docs/bind-array-to-in_cond.md +2 -2
  7. data/docs/conflicts-local-connections-and-processes.md +7 -4
  8. data/docs/hanging-after-inactivity.md +63 -0
  9. data/docs/install-binary-package.md +15 -11
  10. data/docs/install-full-client.md +18 -21
  11. data/docs/install-instant-client.md +45 -27
  12. data/docs/install-on-osx.md +31 -120
  13. data/docs/ldap-auth-and-function-interposition.md +123 -0
  14. data/docs/number-type-mapping.md +79 -0
  15. data/docs/platform-specific-issues.md +17 -50
  16. data/docs/report-installation-issue.md +3 -0
  17. data/docs/timeout-parameters.md +3 -0
  18. data/ext/oci8/apiwrap.c.tmpl +2 -5
  19. data/ext/oci8/apiwrap.rb +6 -1
  20. data/ext/oci8/apiwrap.yml +34 -22
  21. data/ext/oci8/attr.c +4 -2
  22. data/ext/oci8/bind.c +366 -6
  23. data/ext/oci8/connection_pool.c +3 -3
  24. data/ext/oci8/encoding.c +5 -5
  25. data/ext/oci8/env.c +8 -2
  26. data/ext/oci8/error.c +24 -16
  27. data/ext/oci8/extconf.rb +8 -4
  28. data/ext/oci8/hook_funcs.c +274 -61
  29. data/ext/oci8/lob.c +31 -75
  30. data/ext/oci8/metadata.c +2 -2
  31. data/ext/oci8/object.c +72 -27
  32. data/ext/oci8/oci8.c +45 -132
  33. data/ext/oci8/oci8.h +32 -88
  34. data/ext/oci8/oci8lib.c +178 -38
  35. data/ext/oci8/ocihandle.c +37 -37
  36. data/ext/oci8/ocinumber.c +23 -18
  37. data/ext/oci8/oraconf.rb +158 -339
  38. data/ext/oci8/oradate.c +19 -19
  39. data/ext/oci8/plthook.h +10 -0
  40. data/ext/oci8/plthook_elf.c +433 -268
  41. data/ext/oci8/plthook_osx.c +40 -9
  42. data/ext/oci8/plthook_win32.c +9 -0
  43. data/ext/oci8/stmt.c +52 -17
  44. data/ext/oci8/win32.c +4 -22
  45. data/lib/oci8/bindtype.rb +1 -15
  46. data/lib/oci8/check_load_error.rb +57 -10
  47. data/lib/oci8/cursor.rb +57 -25
  48. data/lib/oci8/metadata.rb +9 -1
  49. data/lib/oci8/object.rb +10 -0
  50. data/lib/oci8/oci8.rb +33 -28
  51. data/lib/oci8/oracle_version.rb +11 -1
  52. data/lib/oci8/properties.rb +22 -0
  53. data/lib/oci8/version.rb +1 -1
  54. data/lib/oci8.rb +48 -4
  55. data/lib/ruby-oci8.rb +0 -3
  56. data/pre-distclean.rb +1 -3
  57. data/ruby-oci8.gemspec +3 -8
  58. data/setup.rb +11 -2
  59. data/test/README.md +37 -0
  60. data/test/config.rb +1 -1
  61. data/test/setup_test_object.sql +21 -13
  62. data/test/setup_test_package.sql +59 -0
  63. data/test/test_all.rb +2 -0
  64. data/test/test_bind_boolean.rb +99 -0
  65. data/test/test_bind_integer.rb +47 -0
  66. data/test/test_break.rb +11 -9
  67. data/test/test_clob.rb +4 -16
  68. data/test/test_connstr.rb +29 -13
  69. data/test/test_datetime.rb +8 -3
  70. data/test/test_object.rb +27 -9
  71. data/test/test_oci8.rb +170 -46
  72. data/test/test_oranumber.rb +12 -6
  73. data/test/test_package_type.rb +15 -3
  74. data/test/test_properties.rb +17 -0
  75. metadata +40 -54
  76. data/docs/osx-install-dev-tools.png +0 -0
  77. data/test/README +0 -42
data/ext/oci8/oci8.h CHANGED
@@ -21,8 +21,23 @@ extern "C"
21
21
  }
22
22
  #endif
23
23
 
24
+ /*
25
+ * Oracle version number format in 32-bit integer.
26
+ *
27
+ * Oracle 12c or earier Oracle 18c or later
28
+ *
29
+ * hexadecimal -> dotted version number hexadecimal -> dotted version number
30
+ * 0c102304 -> 12.1.2.3.4 12012034 -> 18.1.2.3.4
31
+ * ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
32
+ * 0c ------------' | | | | 2 bytes 12 ------------' | | | | 2 bytes
33
+ * 1 --------------' | | | 1 byte 01 -------------' | | | 2 bytes
34
+ * 02 --------------' | | 2 bytes 2 --------------' | | 1 byte
35
+ * 3 ---------------' | 1 byte 03 --------------' | 2 bytes
36
+ * 04 ---------------' 2 bytes 4 ---------------' 1 byte
37
+ */
24
38
  #define ORAVERNUM(major, minor, update, patch, port_update) \
25
- (((major) << 24) | ((minor) << 20) | ((update) << 12) | ((patch) << 8) | (port_update))
39
+ (((major) >= 18) ? (((major) << 24) | ((minor) << 16) | ((update) << 12) | ((patch) << 4) | (port_update)) \
40
+ : (((major) << 24) | ((minor) << 20) | ((update) << 12) | ((patch) << 8) | (port_update)))
26
41
 
27
42
  #define ORAVER_8_0 ORAVERNUM(8, 0, 0, 0, 0)
28
43
  #define ORAVER_8_1 ORAVERNUM(8, 1, 0, 0, 0)
@@ -32,6 +47,7 @@ extern "C"
32
47
  #define ORAVER_10_2 ORAVERNUM(10, 2, 0, 0, 0)
33
48
  #define ORAVER_11_1 ORAVERNUM(11, 1, 0, 0, 0)
34
49
  #define ORAVER_12_1 ORAVERNUM(12, 1, 0, 0, 0)
50
+ #define ORAVER_18 ORAVERNUM(18, 0, 0, 0, 0)
35
51
 
36
52
  #include "extconf.h"
37
53
  #include <ruby/encoding.h>
@@ -73,88 +89,6 @@ typedef orasb8 sb8;
73
89
  #endif
74
90
  #endif
75
91
 
76
- /*
77
- * Use TypedData on ruby 1.9.3 and later.
78
- */
79
- #ifndef HAVE_RB_DATA_TYPE_T_FUNCTION
80
-
81
- /*
82
- * Don't use TypedData even though ruby 1.9.2 has it because the
83
- * definitions are slightly different from ruby 1.9.3 and later.
84
- */
85
- #define rb_data_type_t oci8_data_type_t
86
- #undef TypedData_Make_Struct
87
- #undef TypedData_Wrap_Struct
88
- #undef TypedData_Get_Struct
89
- #undef RTYPEDDATA_DATA
90
- #undef RUBY_DEFAULT_FREE
91
-
92
- /*
93
- * To pass compilation on ruby 1.9.2 and earlier.
94
- */
95
- typedef struct oci8_data_type_struct rb_data_type_t;
96
- struct oci8_data_type_struct {
97
- const char *wrap_struct_name;
98
- struct {
99
- void (*dmark)(void*);
100
- void (*dfree)(void*);
101
- size_t (*dsize)(const void *);
102
- } function;
103
- const rb_data_type_t *parent;
104
- void *data;
105
- };
106
- #define TypedData_Make_Struct(klass, type, data_type, sval) \
107
- Data_Make_Struct((klass), type, (data_type)->function.dmark, (data_type)->function.dfree, (sval))
108
- #define TypedData_Wrap_Struct(klass, data_type, sval) \
109
- Data_Wrap_Struct((klass), (data_type)->function.dmark, (data_type)->function.dfree, (sval))
110
- #define TypedData_Get_Struct(obj, type, data_type, sval) \
111
- Data_Get_Struct((obj), type, (sval))
112
- #define RTYPEDDATA_DATA(obj) DATA_PTR(obj)
113
- #define RUBY_DEFAULT_FREE xfree
114
- #endif
115
-
116
- /* a new function in ruby 1.9.3.
117
- * define a compatible macro for ruby 1.9.2 or lower.
118
- */
119
- #ifndef HAVE_RB_CLASS_SUPERCLASS
120
- #ifdef RCLASS_SUPER
121
- #define rb_class_superclass(cls) RCLASS_SUPER(cls)
122
- #else
123
- #define rb_class_superclass(cls) (RCLASS(cls)->super)
124
- #endif
125
- #endif
126
-
127
- /* new macros in ruby 2.1.0
128
- */
129
- #ifndef RARRAY_AREF
130
- #define RARRAY_AREF(a, i) (RARRAY_PTR(a)[i])
131
- #endif
132
- #ifndef RARRAY_CONST_PTR
133
- #define RARRAY_CONST_PTR(a) RARRAY_PTR(a)
134
- #endif
135
- #ifndef RB_OBJ_WRITE
136
- #define RB_OBJ_WRITE(a, slot, b) do {*(slot) = (b);} while (0)
137
- #endif
138
- #ifndef RB_OBJ_WRITTEN
139
- #define RB_OBJ_WRITTEN(a, oldv, b) do {(void)oldv;} while (0)
140
- #endif
141
-
142
- /* new macros in ruby 2.4.0
143
- */
144
- #ifndef ALWAYS_INLINE
145
- #if defined(__GNUC__) && ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
146
- /* gcc version >= 3.1 */
147
- #define ALWAYS_INLINE(x) __attribute__((always_inline)) x
148
- #endif
149
- #ifdef _MSC_VER
150
- /* microsoft c */
151
- #define ALWAYS_INLINE(x) __forceinline x
152
- #endif
153
- #ifndef ALWAYS_INLINE
154
- #define ALWAYS_INLINE(x) x
155
- #endif
156
- #endif /* ALWAYS_INLINE */
157
-
158
92
  /* macros depends on the compiler.
159
93
  * LIKELY(x) hint for the compiler that 'x' is 1(TRUE) in many cases.
160
94
  * UNLIKELY(x) hint for the compiler that 'x' is 0(FALSE) in many cases.
@@ -316,6 +250,7 @@ typedef struct oci8_svcctx {
316
250
  const oci8_logoff_strategy_t *logoff_strategy;
317
251
  OCISession *usrhp;
318
252
  OCIServer *srvhp;
253
+ ub4 server_version;
319
254
  rb_pid_t pid;
320
255
  unsigned char state;
321
256
  char is_autocommit;
@@ -340,7 +275,8 @@ typedef struct {
340
275
  } oci8_exec_sql_var_t;
341
276
 
342
277
  #define oci8_raise(err, status, stmt) oci8_do_raise(err, status, stmt, __FILE__, __LINE__)
343
- #define oci8_env_raise(err, status) oci8_do_env_raise(err, status, __FILE__, __LINE__)
278
+ #define oci8_env_raise(env, status) oci8_do_env_raise(env, status, 0, __FILE__, __LINE__)
279
+ #define oci8_env_free_and_raise(env, status) oci8_do_env_raise(env, status, 1, __FILE__, __LINE__)
344
280
  #define oci8_raise_init_error() oci8_do_raise_init_error(__FILE__, __LINE__)
345
281
  #define oci8_raise_by_msgno(msgno, default_msg) oci8_do_raise_by_msgno(msgno, default_msg, __FILE__, __LINE__)
346
282
 
@@ -364,7 +300,7 @@ OCIEnv *oci8_make_envhp(void);
364
300
  extern oci8_tls_key_t oci8_tls_key; /* native thread key */
365
301
  OCIError *oci8_make_errhp(void);
366
302
 
367
- static inline OCIError *oci8_get_errhp()
303
+ static inline OCIError *oci8_get_errhp(void)
368
304
  {
369
305
  OCIError *errhp = (OCIError *)oci8_tls_get(oci8_tls_key);
370
306
  return LIKELY(errhp != NULL) ? errhp : oci8_make_errhp();
@@ -406,7 +342,8 @@ void *oci8_check_typeddata(VALUE obj, const oci8_handle_data_type_t *data_type,
406
342
  extern VALUE eOCIException;
407
343
  extern VALUE eOCIBreak;
408
344
  void Init_oci8_error(void);
409
- NORETURN(void oci8_do_env_raise(OCIEnv *, sword status, const char *file, int line));
345
+ NORETURN(void oci8_do_raise(OCIError *errhp, sword status, OCIStmt *stmthp, const char *file, int line));
346
+ NORETURN(void oci8_do_env_raise(OCIEnv *envhp, sword status, int free_envhp, const char *file, int line));
410
347
  NORETURN(void oci8_do_raise_init_error(const char *file, int line));
411
348
  sb4 oci8_get_error_code(OCIError *errhp);
412
349
  VALUE oci8_get_error_message(ub4 msgno, const char *default_msg);
@@ -488,8 +425,8 @@ OCINumber *oci8_dbl_to_onum(OCINumber *result, double dbl, OCIError *errhp);
488
425
  void Init_oci_datetime(void);
489
426
  VALUE oci8_make_ocidate(OCIDate *od);
490
427
  OCIDate *oci8_set_ocidate(OCIDate *od, VALUE val);
491
- VALUE oci8_make_ocidatetime(OCIDateTime *dttm);
492
- OCIDateTime *oci8_set_ocidatetime(OCIDateTime *dttm, VALUE val);
428
+ VALUE oci8_make_ocitimestamp(OCIDateTime *dttm, boolean have_tz);
429
+ OCIDateTime *oci8_set_ocitimestamp_tz(OCIDateTime *dttm, VALUE val, VALUE svc);
493
430
  VALUE oci8_make_interval_ym(OCIInterval *s);
494
431
  VALUE oci8_make_interval_ds(OCIInterval *s);
495
432
 
@@ -514,6 +451,13 @@ void Init_oci8_win32(VALUE cOCI8);
514
451
  /* hook_funcs.c */
515
452
  void oci8_install_hook_functions(void);
516
453
  void oci8_shutdown_sockets(void);
454
+ #ifdef HAVE_PLTHOOK
455
+ extern int oci8_cancel_read_at_exit;
456
+ extern int oci8_tcp_keepalive_time;
457
+ #else
458
+ #define oci8_cancel_read_at_exit (-1)
459
+ #define oci8_tcp_keepalive_time (-1)
460
+ #endif
517
461
 
518
462
  #define OCI8StringValue(v) do { \
519
463
  StringValue(v); \
data/ext/oci8/oci8lib.c CHANGED
@@ -7,6 +7,10 @@
7
7
  #ifdef HAVE_RUBY_THREAD_H
8
8
  #include <ruby/thread.h>
9
9
  #endif
10
+ #if defined(HAVE_PLTHOOK) && !defined(WIN32)
11
+ #include <dlfcn.h>
12
+ #include "plthook.h"
13
+ #endif
10
14
 
11
15
  ID oci8_id_at_last_error;
12
16
  ID oci8_id_get;
@@ -67,14 +71,130 @@ static VALUE bind_base_alloc(VALUE klass)
67
71
  rb_raise(rb_eNameError, "private method `new' called for %s:Class", rb_class2name(klass));
68
72
  }
69
73
 
74
+ #if defined(HAVE_PLTHOOK) && !defined(WIN32) && !defined(__CYGWIN__) && !defined(TRUFFLERUBY)
75
+ static const char *find_libclntsh(void *handle)
76
+ {
77
+ void *symaddr = dlsym(handle, "OCIEnvCreate");
78
+ Dl_info info;
79
+ #ifdef __APPLE__
80
+ const char *basename = "libclntsh.dylib";
81
+ #else
82
+ const char *basename = "libclntsh.so";
83
+ #endif
84
+ const char *p;
85
+
86
+ if (symaddr == NULL) {
87
+ return NULL;
88
+ }
89
+ if (dladdr(symaddr, &info) == 0) {
90
+ return NULL;
91
+ }
92
+ if ((p = strrchr(info.dli_fname, '/')) == NULL) {
93
+ return NULL;
94
+ }
95
+ if (strncmp(p + 1, basename, strlen(basename)) != 0) {
96
+ return NULL;
97
+ }
98
+ return info.dli_fname;
99
+ }
100
+
101
+ /*
102
+ * Symbol prefix depends on the platform.
103
+ * Linux x86_64 - no prefix
104
+ * Linux x86_32 - "_"
105
+ * macOS - "@_"
106
+ */
107
+ static const char *find_symbol_prefix(plthook_t *ph, size_t *len)
108
+ {
109
+ unsigned int pos = 0;
110
+ const char *name;
111
+ void **addr;
112
+
113
+ while (plthook_enum(ph, &pos, &name, &addr) == 0) {
114
+ const char *p = strstr(name, "OCIEnvCreate");
115
+ if (p != NULL) {
116
+ *len = p - name;
117
+ return name;
118
+ }
119
+ }
120
+ return NULL;
121
+ }
122
+
123
+ /*
124
+ * Fix PLT entries against function interposition.
125
+ * See: http://www.rubydoc.info/github/kubo/ruby-oci8/file/docs/ldap-auth-and-function-interposition.md
126
+ */
127
+ static void rebind_internal_symbols(void)
128
+ {
129
+ const char *libfile;
130
+ void *handle;
131
+ int flags = RTLD_LAZY | RTLD_NOLOAD;
132
+ plthook_t *ph;
133
+ unsigned int pos = 0;
134
+ const char *name;
135
+ void **addr;
136
+ const char *prefix;
137
+ size_t prefix_len;
138
+
139
+ #ifdef RTLD_FIRST
140
+ flags |= RTLD_FIRST; /* for macOS */
141
+ #endif
142
+
143
+ libfile = find_libclntsh(RTLD_DEFAULT); /* normal case */
144
+ if (libfile == NULL) {
145
+ libfile = find_libclntsh(RTLD_NEXT); /* special case when OCIEnvCreate is hooked by LD_PRELOAD */
146
+ }
147
+ if (libfile == NULL) {
148
+ return;
149
+ }
150
+ handle = dlopen(libfile, flags);
151
+ if (handle == NULL) {
152
+ return;
153
+ }
154
+ if (plthook_open(&ph, libfile) != 0) {
155
+ dlclose(handle);
156
+ return;
157
+ }
158
+ prefix = find_symbol_prefix(ph, &prefix_len);
159
+ if (prefix == NULL) {
160
+ dlclose(handle);
161
+ plthook_close(ph);
162
+ return;
163
+ }
164
+ while (plthook_enum(ph, &pos, &name, &addr) == 0) {
165
+ void *funcaddr;
166
+ if (prefix_len != 0) {
167
+ if (strncmp(name, prefix, prefix_len) != 0) {
168
+ continue;
169
+ }
170
+ name += prefix_len;
171
+ }
172
+ if (strncmp(name, "OCI", 3) == 0) {
173
+ /* exclude functions starting with OCI not to prevent LD_PRELOAD hooking */
174
+ continue;
175
+ }
176
+ funcaddr = dlsym(handle, name);
177
+ if (funcaddr != NULL && *addr != funcaddr) {
178
+ /* If libclntsh.so exports and imports same functions, their
179
+ * PLT entries are forcedly modified to point to itself not
180
+ * to use functions in other libraries.
181
+ */
182
+ *addr = funcaddr;
183
+ }
184
+ }
185
+ plthook_close(ph);
186
+ dlclose(handle);
187
+ }
188
+ #endif
189
+
70
190
  #ifdef _WIN32
71
191
  __declspec(dllexport)
72
192
  #endif
73
193
  void
74
- Init_oci8lib()
194
+ Init_oci8lib(void)
75
195
  {
76
196
  VALUE cOCI8;
77
- OCIEnv *envhp;
197
+ OCIEnv *envhp = NULL;
78
198
  OCIError *errhp;
79
199
  sword rv;
80
200
 
@@ -106,6 +226,9 @@ Init_oci8lib()
106
226
  oracle_client_version = ORAVERNUM(major, minor, update, patch, port_update);
107
227
  }
108
228
  #endif
229
+ #if defined(HAVE_PLTHOOK) && !defined(WIN32) && !defined(__CYGWIN__) && !defined(TRUFFLERUBY)
230
+ rebind_internal_symbols();
231
+ #endif
109
232
 
110
233
  oci8_id_at_last_error = rb_intern("@last_error");
111
234
  oci8_id_get = rb_intern("get");
@@ -153,7 +276,11 @@ Init_oci8lib()
153
276
  /* allocate a temporary errhp to pass Init_oci_number() */
154
277
  rv = OCIEnvCreate(&envhp, oci8_env_mode, NULL, NULL, NULL, NULL, 0, NULL);
155
278
  if (rv != OCI_SUCCESS) {
156
- oci8_raise_init_error();
279
+ if (envhp != NULL) {
280
+ oci8_env_free_and_raise(envhp, rv);
281
+ } else {
282
+ oci8_raise_init_error();
283
+ }
157
284
  }
158
285
  rv = OCIHandleAlloc(envhp, (dvoid *)&errhp, OCI_HTYPE_ERROR, 0, NULL);
159
286
  if (rv != OCI_SUCCESS)
@@ -334,6 +461,7 @@ sword oci8_call_without_gvl(oci8_svcctx_t *svcctx, void *(*func)(void *), void *
334
461
  parg.func = func;
335
462
  parg.data = data;
336
463
  rv = (sword)rb_protect(protected_call, (VALUE)&parg, &state);
464
+ RB_OBJ_WRITE(svcctx->base.self, &svcctx->executing_thread, Qnil);
337
465
  if (state) {
338
466
  rb_jump_tag(state);
339
467
  }
@@ -354,8 +482,8 @@ typedef struct {
354
482
  OCIStmt *stmtp;
355
483
  } cb_arg_t;
356
484
 
357
- static VALUE exec_sql(cb_arg_t *arg);
358
- static VALUE ensure_func(cb_arg_t *arg);
485
+ static VALUE exec_sql(VALUE varg);
486
+ static VALUE ensure_func(VALUE varg);
359
487
 
360
488
  /*
361
489
  * utility function to execute a single SQL statement
@@ -376,13 +504,14 @@ sword oci8_exec_sql(oci8_svcctx_t *svcctx, const char *sql_text, ub4 num_define_
376
504
  return (sword)rb_ensure(exec_sql, (VALUE)&arg, ensure_func, (VALUE)&arg);
377
505
  }
378
506
 
379
- static VALUE exec_sql(cb_arg_t *arg)
507
+ static VALUE exec_sql(VALUE varg)
380
508
  {
509
+ cb_arg_t *arg = (cb_arg_t *)varg;
381
510
  ub4 pos;
382
511
  sword rv;
383
512
 
384
513
  chker2(OCIStmtPrepare2(arg->svcctx->base.hp.svc, &arg->stmtp, oci8_errhp,
385
- (text*)arg->sql_text, strlen(arg->sql_text), NULL, 0,
514
+ (text*)arg->sql_text, (ub4)strlen(arg->sql_text), NULL, 0,
386
515
  OCI_NTV_SYNTAX, OCI_DEFAULT),
387
516
  &arg->svcctx->base);
388
517
  for (pos = 0; pos < arg->num_define_vars; pos++) {
@@ -419,8 +548,9 @@ static VALUE exec_sql(cb_arg_t *arg)
419
548
  return (VALUE)rv;
420
549
  }
421
550
 
422
- static VALUE ensure_func(cb_arg_t *arg)
551
+ static VALUE ensure_func(VALUE varg)
423
552
  {
553
+ cb_arg_t *arg = (cb_arg_t *)varg;
424
554
  if (arg->stmtp != NULL) {
425
555
  OCIStmtRelease(arg->stmtp, oci8_errhp, NULL, 0, OCI_DEFAULT);
426
556
  }
@@ -431,6 +561,24 @@ static VALUE ensure_func(cb_arg_t *arg)
431
561
 
432
562
  #ifndef _WIN32
433
563
  #include <dlfcn.h>
564
+ static void *load_file(const char *filename, int flags, VALUE errors)
565
+ {
566
+ void *handle = dlopen(filename, flags);
567
+
568
+ if (handle == NULL) {
569
+ char *err = dlerror();
570
+ VALUE msg;
571
+
572
+ if (strstr(err, filename) == NULL) {
573
+ msg = rb_sprintf("%s: %s", filename, err);
574
+ msg = rb_enc_associate_index(msg, rb_locale_encindex());
575
+ } else {
576
+ msg = rb_locale_str_new_cstr(err);
577
+ }
578
+ rb_ary_push(errors, msg);
579
+ }
580
+ return handle;
581
+ }
434
582
  #endif
435
583
 
436
584
  void *oci8_find_symbol(const char *symbol_name)
@@ -473,58 +621,50 @@ void *oci8_find_symbol(const char *symbol_name)
473
621
  "libclntsh.sl.12.1",
474
622
  "libclntsh.sl.11.1",
475
623
  "libclntsh.sl.10.1",
476
- "libclntsh.sl.9.0",
477
- "libclntsh.sl.8.0",
478
624
  #elif defined(__APPLE__)
479
625
  /* Mac OS X */
626
+ "libclntsh.dylib",
480
627
  "libclntsh.dylib.12.1",
481
628
  "libclntsh.dylib.11.1",
482
629
  "libclntsh.dylib.10.1",
483
630
  #else
484
631
  /* Linux, Solaris and HP-UX(IA64) */
632
+ "libclntsh.so",
485
633
  "libclntsh.so.12.1",
486
634
  "libclntsh.so.11.1",
487
635
  "libclntsh.so.10.1",
488
- "libclntsh.so.9.0",
489
- "libclntsh.so.8.0",
490
636
  #endif
491
637
  };
492
638
  #define NUM_SONAMES (sizeof(sonames)/sizeof(sonames[0]))
639
+ #if defined(_AIX) /* AIX */
640
+ #define BASE_SONAME "libclntsh.a(shr.o)"
641
+ #elif defined(__hppa) /* HP-UX(PA-RISC) */
642
+ #define BASE_SONAME "libclntsh.sl"
643
+ #elif !defined(__CYGWIN__) && !defined(__APPLE__)
644
+ #define BASE_SONAME "libclntsh.so"
645
+ #endif
493
646
  size_t idx;
494
- volatile VALUE err = rb_ary_new();
647
+ VALUE err = rb_ary_new();
495
648
 
496
649
  #ifdef _AIX
497
650
  #define DLOPEN_FLAG (RTLD_LAZY|RTLD_GLOBAL|RTLD_MEMBER)
498
651
  #else
499
652
  #define DLOPEN_FLAG (RTLD_LAZY|RTLD_GLOBAL)
500
653
  #endif
501
- for (idx = 0; idx < NUM_SONAMES; idx++) {
502
- handle = dlopen(sonames[idx], DLOPEN_FLAG);
503
- if (handle != NULL) {
504
- break;
505
- }
506
- rb_ary_push(err, rb_locale_str_new_cstr(dlerror()));
654
+ #ifdef BASE_SONAME
655
+ char *oracle_home = getenv("ORACLE_HOME");
656
+
657
+ if (oracle_home != NULL) {
658
+ VALUE fname = rb_str_buf_cat2(rb_str_buf_new_cstr(oracle_home), "/lib/" BASE_SONAME);
659
+ handle = load_file(StringValueCStr(fname), DLOPEN_FLAG, err);
660
+ RB_GC_GUARD(fname);
661
+ }
662
+ #endif
663
+ for (idx = 0; handle == NULL && idx < NUM_SONAMES; idx++) {
664
+ handle = load_file(sonames[idx], DLOPEN_FLAG, err);
507
665
  }
508
666
  if (handle == NULL) {
509
- VALUE msg;
510
- const VALUE *arr = RARRAY_CONST_PTR(err);
511
-
512
- msg = rb_str_buf_new(NUM_SONAMES * 50);
513
- for (idx = 0; idx < NUM_SONAMES; idx++) {
514
- const char *errmsg = RSTRING_PTR(arr[idx]);
515
- if (idx != 0) {
516
- rb_str_buf_cat2(msg, " ");
517
- }
518
- if (strstr(errmsg, sonames[idx]) == NULL) {
519
- /* prepend "soname: " if soname is not found in
520
- * the error message.
521
- */
522
- rb_str_buf_cat2(msg, sonames[idx]);
523
- rb_str_buf_cat2(msg, ": ");
524
- }
525
- rb_str_buf_append(msg, arr[idx]);
526
- rb_str_buf_cat2(msg, ";");
527
- }
667
+ VALUE msg = rb_ary_join(err, rb_usascii_str_new_cstr("; "));
528
668
  rb_exc_raise(rb_exc_new3(rb_eLoadError, msg));
529
669
  }
530
670
  }