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.
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
  }