ruby-oci8 1.0.7 → 2.0.0

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 (89) hide show
  1. data/ChangeLog +1254 -390
  2. data/Makefile +10 -13
  3. data/README +56 -385
  4. data/VERSION +1 -1
  5. data/dist-files +26 -27
  6. data/ext/oci8/.document +1 -0
  7. data/ext/oci8/MANIFEST +0 -4
  8. data/ext/oci8/apiwrap.c.tmpl +172 -0
  9. data/ext/oci8/apiwrap.h.tmpl +61 -0
  10. data/ext/oci8/apiwrap.rb +91 -0
  11. data/ext/oci8/apiwrap.yml +1243 -0
  12. data/ext/oci8/attr.c +124 -384
  13. data/ext/oci8/bind.c +472 -164
  14. data/ext/oci8/encoding.c +196 -0
  15. data/ext/oci8/env.c +84 -253
  16. data/ext/oci8/error.c +196 -127
  17. data/ext/oci8/extconf.rb +82 -59
  18. data/ext/oci8/lob.c +710 -370
  19. data/ext/oci8/metadata.c +359 -0
  20. data/ext/oci8/object.c +622 -0
  21. data/ext/oci8/oci8.c +577 -161
  22. data/ext/oci8/oci8.h +354 -258
  23. data/ext/oci8/oci8lib.c +493 -0
  24. data/ext/oci8/ocidatetime.c +473 -0
  25. data/ext/oci8/ocinumber.c +1123 -24
  26. data/ext/oci8/oraconf.rb +72 -106
  27. data/ext/oci8/oradate.c +511 -321
  28. data/ext/oci8/stmt.c +752 -572
  29. data/ext/oci8/win32.c +131 -0
  30. data/ext/oci8/xmldb.c +383 -0
  31. data/lib/.document +2 -0
  32. data/lib/dbd/OCI8.rb +2 -17
  33. data/lib/oci8.rb.in +41 -1622
  34. data/lib/oci8/.document +5 -0
  35. data/lib/oci8/compat.rb +108 -0
  36. data/lib/oci8/datetime.rb +489 -0
  37. data/lib/oci8/encoding-init.rb +40 -0
  38. data/lib/oci8/encoding.yml +537 -0
  39. data/lib/oci8/metadata.rb +2077 -0
  40. data/lib/oci8/object.rb +548 -0
  41. data/lib/oci8/oci8.rb +773 -0
  42. data/lib/oci8/oracle_version.rb +144 -0
  43. data/metaconfig +3 -3
  44. data/ruby-oci8.gemspec +5 -5
  45. data/setup.rb +4 -4
  46. data/test/config.rb +64 -84
  47. data/test/test_all.rb +14 -21
  48. data/test/test_array_dml.rb +317 -0
  49. data/test/test_bind_raw.rb +18 -25
  50. data/test/test_bind_time.rb +78 -91
  51. data/test/test_break.rb +37 -35
  52. data/test/test_clob.rb +33 -89
  53. data/test/test_connstr.rb +5 -4
  54. data/test/test_datetime.rb +469 -0
  55. data/test/test_dbi.rb +99 -60
  56. data/test/test_dbi_clob.rb +3 -8
  57. data/test/test_metadata.rb +65 -51
  58. data/test/test_oci8.rb +151 -55
  59. data/test/test_oracle_version.rb +70 -0
  60. data/test/test_oradate.rb +76 -83
  61. data/test/test_oranumber.rb +405 -71
  62. data/test/test_rowid.rb +6 -11
  63. metadata +31 -32
  64. data/NEWS +0 -420
  65. data/ext/oci8/const.c +0 -165
  66. data/ext/oci8/define.c +0 -53
  67. data/ext/oci8/describe.c +0 -81
  68. data/ext/oci8/descriptor.c +0 -39
  69. data/ext/oci8/handle.c +0 -273
  70. data/ext/oci8/oranumber.c +0 -445
  71. data/ext/oci8/param.c +0 -37
  72. data/ext/oci8/server.c +0 -182
  73. data/ext/oci8/session.c +0 -99
  74. data/ext/oci8/svcctx.c +0 -238
  75. data/ruby-oci8.spec +0 -62
  76. data/support/README +0 -4
  77. data/support/runit/assert.rb +0 -281
  78. data/support/runit/cui/testrunner.rb +0 -101
  79. data/support/runit/error.rb +0 -4
  80. data/support/runit/method_mappable.rb +0 -20
  81. data/support/runit/robserver.rb +0 -25
  82. data/support/runit/setuppable.rb +0 -15
  83. data/support/runit/teardownable.rb +0 -16
  84. data/support/runit/testcase.rb +0 -113
  85. data/support/runit/testfailure.rb +0 -25
  86. data/support/runit/testresult.rb +0 -121
  87. data/support/runit/testsuite.rb +0 -43
  88. data/support/runit/version.rb +0 -3
  89. data/test/test_describe.rb +0 -137
@@ -0,0 +1,493 @@
1
+ /* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * Copyright (C) 2002-2008 KUBO Takehiro <kubo@jiubao.org>
4
+ */
5
+
6
+ #include "oci8.h"
7
+
8
+ #define DEBUG_CORE_FILE 1
9
+ #ifdef DEBUG_CORE_FILE
10
+ #include <signal.h>
11
+ #endif
12
+
13
+ static oci8_base_class_t oci8_base_class = {
14
+ NULL,
15
+ NULL,
16
+ sizeof(oci8_base_t),
17
+ };
18
+
19
+ ID oci8_id_new;
20
+ ID oci8_id_get;
21
+ ID oci8_id_set;
22
+ ID oci8_id_keys;
23
+ int oci8_in_finalizer = 0;
24
+ VALUE oci8_cOCIHandle;
25
+
26
+ static ID id_oci8_class;
27
+
28
+ static VALUE mOCI8BindType;
29
+ static VALUE cOCI8BindTypeBase;
30
+
31
+ static VALUE oci8_handle_initialize(VALUE self)
32
+ {
33
+ rb_raise(rb_eNameError, "private method `new' called for %s:Class", rb_class2name(CLASS_OF(self)));
34
+ }
35
+
36
+ void oci8_base_free(oci8_base_t *base)
37
+ {
38
+ while (base->children != NULL) {
39
+ oci8_base_free(base->children);
40
+ }
41
+ oci8_unlink_from_parent(base);
42
+ if (base->klass->free != NULL)
43
+ base->klass->free(base);
44
+ if (base->type >= OCI_DTYPE_FIRST)
45
+ OCIDescriptorFree(base->hp.ptr, base->type);
46
+ else if (base->type >= OCI_HTYPE_FIRST)
47
+ OCIHandleFree(base->hp.ptr, base->type);
48
+ base->type = 0;
49
+ base->hp.ptr = NULL;
50
+ }
51
+
52
+ static VALUE oci8_handle_free(VALUE self)
53
+ {
54
+ oci8_base_t *base = DATA_PTR(self);
55
+
56
+ oci8_base_free(base);
57
+ return self;
58
+ }
59
+
60
+ static void oci8_handle_mark(oci8_base_t *base)
61
+ {
62
+ if (base->klass->mark != NULL)
63
+ base->klass->mark(base);
64
+ }
65
+
66
+ static void oci8_handle_cleanup(oci8_base_t *base)
67
+ {
68
+ oci8_base_free(base);
69
+ free(base);
70
+ }
71
+
72
+ static VALUE oci8_s_allocate(VALUE klass)
73
+ {
74
+ oci8_base_t *base;
75
+ const oci8_base_class_t *base_class;
76
+ VALUE superklass;
77
+ VALUE obj;
78
+
79
+ superklass = klass;
80
+ while (!RTEST(rb_ivar_defined(superklass, id_oci8_class))) {
81
+ superklass = RCLASS_SUPER(superklass);
82
+ if (superklass == rb_cObject)
83
+ rb_raise(rb_eRuntimeError, "private method `new' called for %s:Class", rb_class2name(klass));
84
+ }
85
+ obj = rb_ivar_get(superklass, id_oci8_class);
86
+ base_class = DATA_PTR(obj);
87
+
88
+ base = xmalloc(base_class->size);
89
+ memset(base, 0, base_class->size);
90
+
91
+ obj = Data_Wrap_Struct(klass, oci8_handle_mark, oci8_handle_cleanup, base);
92
+ base->self = obj;
93
+ base->klass = base_class;
94
+ base->parent = NULL;
95
+ base->next = base;
96
+ base->prev = base;
97
+ base->children = NULL;
98
+ return obj;
99
+ }
100
+
101
+ static void at_exit_func(VALUE val)
102
+ {
103
+ oci8_in_finalizer = 1;
104
+ }
105
+
106
+ void
107
+ Init_oci8lib()
108
+ {
109
+ VALUE cOCI8;
110
+ VALUE obj;
111
+
112
+ #ifdef RUNTIME_API_CHECK
113
+ Init_oci8_apiwrap();
114
+ if (have_OCIClientVersion) {
115
+ sword major, minor, update, patch, port_update;
116
+ OCIClientVersion(&major, &minor, &update, &patch, &port_update);
117
+ oracle_client_version = ORAVERNUM(major, minor, update, patch, port_update);
118
+ }
119
+ #endif
120
+
121
+ id_oci8_class = rb_intern("__oci8_class__");
122
+ oci8_id_new = rb_intern("new");
123
+ oci8_id_get = rb_intern("get");
124
+ oci8_id_set = rb_intern("set");
125
+ oci8_id_keys = rb_intern("keys");
126
+ rb_set_end_proc(at_exit_func, Qnil);
127
+
128
+ Init_oci8_error();
129
+ Init_oci8_env();
130
+
131
+ /* OCIHandle class */
132
+ oci8_cOCIHandle = rb_define_class("OCIHandle", rb_cObject);
133
+ rb_define_alloc_func(oci8_cOCIHandle, oci8_s_allocate);
134
+ rb_define_method(oci8_cOCIHandle, "initialize", oci8_handle_initialize, 0);
135
+ rb_define_method(oci8_cOCIHandle, "free", oci8_handle_free, 0);
136
+ obj = Data_Wrap_Struct(rb_cObject, 0, 0, &oci8_base_class);
137
+ rb_ivar_set(oci8_cOCIHandle, id_oci8_class, obj);
138
+
139
+ /* OCI8 class */
140
+ cOCI8 = Init_oci8();
141
+ /* OCI8::BindType module */
142
+ mOCI8BindType = rb_define_module_under(cOCI8, "BindType");
143
+ /* OCI8::BindType::Base class */
144
+ cOCI8BindTypeBase = rb_define_class_under(mOCI8BindType, "Base", oci8_cOCIHandle);
145
+
146
+ /* Handle */
147
+ Init_oci8_bind(cOCI8BindTypeBase);
148
+ Init_oci8_stmt(cOCI8);
149
+
150
+ /* Encoding */
151
+ Init_oci8_encoding(cOCI8);
152
+
153
+ /* register allocators */
154
+ Init_oci8_metadata(cOCI8);
155
+ Init_oci8_lob(cOCI8);
156
+
157
+ Init_ora_date();
158
+ Init_oci_number(cOCI8);
159
+ Init_oci_datetime();
160
+ Init_oci_object(cOCI8);
161
+ Init_oci_xmldb();
162
+
163
+ #ifdef USE_WIN32_C
164
+ Init_oci8_win32(cOCI8);
165
+ #endif
166
+
167
+ #ifdef DEBUG_CORE_FILE
168
+ signal(SIGSEGV, SIG_DFL);
169
+ #endif
170
+ }
171
+
172
+ VALUE oci8_define_class(const char *name, oci8_base_class_t *base_class)
173
+ {
174
+ VALUE klass = rb_define_class(name, oci8_cOCIHandle);
175
+ VALUE obj = Data_Wrap_Struct(rb_cObject, 0, 0, base_class);
176
+ rb_ivar_set(klass, id_oci8_class, obj);
177
+ return klass;
178
+ }
179
+
180
+ VALUE oci8_define_class_under(VALUE outer, const char *name, oci8_base_class_t *base_class)
181
+ {
182
+ VALUE klass = rb_define_class_under(outer, name, oci8_cOCIHandle);
183
+ VALUE obj = Data_Wrap_Struct(rb_cObject, 0, 0, base_class);
184
+ rb_ivar_set(klass, id_oci8_class, obj);
185
+ return klass;
186
+ }
187
+
188
+ VALUE oci8_define_bind_class(const char *name, const oci8_bind_class_t *bind_class)
189
+ {
190
+ VALUE klass = rb_define_class_under(mOCI8BindType, name, cOCI8BindTypeBase);
191
+ VALUE obj = Data_Wrap_Struct(rb_cObject, 0, 0, (void*)bind_class);
192
+ rb_ivar_set(klass, id_oci8_class, obj);
193
+ return klass;
194
+ }
195
+
196
+ void oci8_link_to_parent(oci8_base_t *base, oci8_base_t *parent)
197
+ {
198
+ if (base->parent != NULL) {
199
+ oci8_unlink_from_parent(base);
200
+ }
201
+ if (parent->children == NULL) {
202
+ parent->children = base;
203
+ } else {
204
+ base->next = parent->children;
205
+ base->prev = parent->children->prev;
206
+ parent->children->prev->next = base;
207
+ parent->children->prev = base;
208
+ }
209
+ base->parent = parent;
210
+ }
211
+
212
+ void oci8_unlink_from_parent(oci8_base_t *base)
213
+ {
214
+ if (base->parent == NULL) {
215
+ return;
216
+ }
217
+ if (base->next == base) {
218
+ base->parent->children = NULL;
219
+ } else {
220
+ if (base->parent->children == base) {
221
+ base->parent->children = base->next;
222
+ }
223
+ base->next->prev = base->prev;
224
+ base->prev->next = base->next;
225
+ base->next = base;
226
+ base->prev = base;
227
+ }
228
+ base->parent = NULL;
229
+ }
230
+
231
+ #ifdef RUBY_VM
232
+ typedef struct {
233
+ dvoid *hndlp;
234
+ OCIError *errhp;
235
+ } ocibreak_arg_t;
236
+
237
+ static VALUE call_OCIBreak(void *user_data)
238
+ {
239
+ ocibreak_arg_t *arg = (ocibreak_arg_t *)user_data;
240
+ OCIBreak(arg->hndlp, arg->errhp);
241
+ return Qnil;
242
+ }
243
+
244
+ static void oci8_unblock_func(void *user_data)
245
+ {
246
+ oci8_svcctx_t *svcctx = (oci8_svcctx_t *)user_data;
247
+ if (svcctx->base.hp.ptr != NULL) {
248
+ ocibreak_arg_t arg;
249
+ arg.hndlp = svcctx->base.hp.ptr;
250
+ arg.errhp = oci8_errhp;
251
+ rb_thread_blocking_region(call_OCIBreak, &arg, NULL, NULL);
252
+ }
253
+ }
254
+
255
+ /* ruby 1.9 */
256
+ sword oci8_blocking_region(oci8_svcctx_t *svcctx, rb_blocking_function_t func, void *data)
257
+ {
258
+ if (svcctx->non_blocking) {
259
+ sword rv;
260
+
261
+ if (!NIL_P(svcctx->executing_thread)) {
262
+ rb_raise(rb_eRuntimeError /* FIXME */, "executing in another thread");
263
+ }
264
+ svcctx->executing_thread = rb_thread_current();
265
+ rv = (sword)rb_thread_blocking_region(func, data, oci8_unblock_func, svcctx);
266
+ svcctx->executing_thread = Qnil;
267
+ if (rv == OCI_ERROR) {
268
+ if (oci8_get_error_code(oci8_errhp) == 1013) {
269
+ rb_raise(eOCIBreak, "Canceled by user request.");
270
+ }
271
+ }
272
+ return rv;
273
+ } else {
274
+ return (sword)func(data);
275
+ }
276
+ }
277
+ #else /* RUBY_VM */
278
+
279
+ /* ruby 1.8 */
280
+ sword oci8_blocking_region(oci8_svcctx_t *svcctx, rb_blocking_function_t func, void *data)
281
+ {
282
+ struct timeval tv;
283
+ sword rv;
284
+
285
+ if (!NIL_P(svcctx->executing_thread)) {
286
+ rb_raise(rb_eRuntimeError /* FIXME */, "executing in another thread");
287
+ }
288
+ tv.tv_sec = 0;
289
+ tv.tv_usec = 100000;
290
+ svcctx->executing_thread = rb_thread_current();
291
+ while ((rv = func(data)) == OCI_STILL_EXECUTING) {
292
+ rb_thread_wait_for(tv);
293
+ if (tv.tv_usec < 500000)
294
+ tv.tv_usec <<= 1;
295
+ }
296
+ if (rv == OCI_ERROR) {
297
+ if (oci8_get_error_code(oci8_errhp) == 1013) {
298
+ if (have_OCIReset)
299
+ OCIReset(svcctx->base.hp.ptr, oci8_errhp);
300
+ svcctx->executing_thread = Qnil;
301
+ rb_raise(eOCIBreak, "Canceled by user request.");
302
+ }
303
+ }
304
+ svcctx->executing_thread = Qnil;
305
+ return rv;
306
+ }
307
+ #endif /* RUBY_VM */
308
+
309
+ typedef struct {
310
+ oci8_svcctx_t *svcctx;
311
+ const char *sql_text;
312
+ ub4 num_define_vars;
313
+ oci8_exec_sql_var_t *define_vars;
314
+ ub4 num_bind_vars;
315
+ oci8_exec_sql_var_t *bind_vars;
316
+ int raise_on_error;
317
+ OCIStmt *stmtp;
318
+ } cb_arg_t;
319
+
320
+ static VALUE exec_sql(cb_arg_t *arg);
321
+ static VALUE ensure_func(cb_arg_t *arg);
322
+
323
+ /*
324
+ * utility function to execute a single SQL statement
325
+ */
326
+ sword oci8_exec_sql(oci8_svcctx_t *svcctx, const char *sql_text, ub4 num_define_vars, oci8_exec_sql_var_t *define_vars, ub4 num_bind_vars, oci8_exec_sql_var_t *bind_vars, int raise_on_error)
327
+ {
328
+ cb_arg_t arg;
329
+
330
+ oci8_check_pid_consistency(svcctx);
331
+ arg.svcctx = svcctx;
332
+ arg.sql_text = sql_text;
333
+ arg.num_define_vars = num_define_vars;
334
+ arg.define_vars = define_vars;
335
+ arg.num_bind_vars = num_bind_vars;
336
+ arg.bind_vars = bind_vars;
337
+ arg.raise_on_error = raise_on_error;
338
+ arg.stmtp = NULL;
339
+ return (sword)rb_ensure(exec_sql, (VALUE)&arg, ensure_func, (VALUE)&arg);
340
+ }
341
+
342
+ static VALUE exec_sql(cb_arg_t *arg)
343
+ {
344
+ ub4 pos;
345
+ sword rv;
346
+
347
+ rv = OCIHandleAlloc(oci8_envhp, (dvoid*)&arg->stmtp, OCI_HTYPE_STMT, 0, NULL);
348
+ if (rv != OCI_SUCCESS) {
349
+ oci8_env_raise(oci8_envhp, rv);
350
+ }
351
+ oci_lc(OCIStmtPrepare(arg->stmtp, oci8_errhp, (text*)arg->sql_text,
352
+ strlen(arg->sql_text), OCI_NTV_SYNTAX, OCI_DEFAULT));
353
+ for (pos = 0; pos < arg->num_define_vars; pos++) {
354
+ arg->define_vars[pos].hp = NULL;
355
+ oci_lc(OCIDefineByPos(arg->stmtp, (OCIDefine**)&arg->define_vars[pos].hp,
356
+ oci8_errhp, pos + 1, arg->define_vars[pos].valuep,
357
+ arg->define_vars[pos].value_sz,
358
+ arg->define_vars[pos].dty, arg->define_vars[pos].indp,
359
+ arg->define_vars[pos].alenp, NULL, OCI_DEFAULT));
360
+ }
361
+ for (pos = 0; pos < arg->num_bind_vars; pos++) {
362
+ arg->bind_vars[pos].hp = NULL;
363
+ oci_lc(OCIBindByPos(arg->stmtp, (OCIBind**)&arg->bind_vars[pos].hp,
364
+ oci8_errhp, pos + 1, arg->bind_vars[pos].valuep,
365
+ arg->bind_vars[pos].value_sz, arg->bind_vars[pos].dty,
366
+ arg->bind_vars[pos].indp, arg->bind_vars[pos].alenp,
367
+ NULL, 0, NULL, OCI_DEFAULT));
368
+ }
369
+ rv = OCIStmtExecute_nb(arg->svcctx, arg->svcctx->base.hp.svc, arg->stmtp, oci8_errhp, 1, 0, NULL, NULL, OCI_DEFAULT);
370
+ if (rv == OCI_ERROR) {
371
+ if (oci8_get_error_code(oci8_errhp) == 1000) {
372
+ /* run GC to close unreferred cursors
373
+ * when ORA-01000 (maximum open cursors exceeded).
374
+ */
375
+ rb_gc();
376
+ rv = OCIStmtExecute_nb(arg->svcctx, arg->svcctx->base.hp.svc, arg->stmtp, oci8_errhp, 1, 0, NULL, NULL, OCI_DEFAULT);
377
+ }
378
+ }
379
+ if (arg->raise_on_error) {
380
+ oci_lc(rv);
381
+ }
382
+ return (VALUE)rv;
383
+ }
384
+
385
+ static VALUE ensure_func(cb_arg_t *arg)
386
+ {
387
+ if (arg->stmtp != NULL) {
388
+ OCIHandleFree(arg->stmtp, OCI_HTYPE_STMT);
389
+ }
390
+ return Qnil;
391
+ }
392
+
393
+ #if defined RUNTIME_API_CHECK
394
+
395
+ #ifndef _WIN32
396
+ #include <dlfcn.h>
397
+ #endif
398
+
399
+ void *oci8_find_symbol(const char *symbol_name)
400
+ {
401
+ #if defined _WIN32
402
+ /* Windows */
403
+ static HMODULE hModule = NULL;
404
+
405
+ if (hModule == NULL) {
406
+ hModule = LoadLibrary("OCI.DLL");
407
+ if (hModule == NULL) {
408
+ char message[512];
409
+ int error = GetLastError();
410
+ char *p;
411
+
412
+ memset(message, 0, sizeof(message));
413
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), message, sizeof(message), NULL);
414
+ for (p = message; *p; p++) {
415
+ if (*p == '\n' || *p == '\r')
416
+ *p = ' ';
417
+ }
418
+ rb_raise(rb_eLoadError, "OCI.DLL: %d(%s)", error, message);
419
+ }
420
+ }
421
+ return GetProcAddress(hModule, symbol_name);
422
+ #else
423
+ /* UNIX */
424
+ static void *handle = NULL;
425
+
426
+ if (handle == NULL) {
427
+ static const char * const sonames[] = {
428
+ #if defined(__CYGWIN__)
429
+ /* Windows(Cygwin) */
430
+ "OCI.DLL",
431
+ #elif defined(_AIX)
432
+ /* AIX */
433
+ "libclntsh.a(shr.o)",
434
+ #elif defined(__hppa)
435
+ /* HP-UX(PA-RISC) */
436
+ "libclntsh.sl.11.1",
437
+ "libclntsh.sl.10.1",
438
+ "libclntsh.sl.9.0",
439
+ "libclntsh.sl.8.0",
440
+ #elif defined(__APPLE__)
441
+ /* Mac OS X */
442
+ "libclntsh.dylib.11.1",
443
+ "libclntsh.dylib.10.1",
444
+ #else
445
+ /* Linux, Solaris and HP-UX(IA64) */
446
+ "libclntsh.so.11.1",
447
+ "libclntsh.so.10.1",
448
+ "libclntsh.so.9.0",
449
+ "libclntsh.so.8.0",
450
+ #endif
451
+ };
452
+ #define NUM_SONAMES (sizeof(sonames)/sizeof(sonames[0]))
453
+ size_t idx;
454
+ VALUE err = rb_ary_new();
455
+
456
+ #ifdef _AIX
457
+ #define DLOPEN_FLAG (RTLD_LAZY|RTLD_GLOBAL|RTLD_MEMBER)
458
+ #else
459
+ #define DLOPEN_FLAG (RTLD_LAZY|RTLD_GLOBAL)
460
+ #endif
461
+ for (idx = 0; idx < NUM_SONAMES; idx++) {
462
+ handle = dlopen(sonames[idx], DLOPEN_FLAG);
463
+ if (handle != NULL) {
464
+ break;
465
+ }
466
+ rb_ary_push(err, rb_locale_str_new_cstr(dlerror()));
467
+ }
468
+ if (handle == NULL) {
469
+ VALUE msg;
470
+
471
+ msg = rb_str_buf_new(NUM_SONAMES * 50);
472
+ for (idx = 0; idx < NUM_SONAMES; idx++) {
473
+ const char *errmsg = RSTRING_PTR(RARRAY_PTR(err)[idx]);
474
+ if (idx != 0) {
475
+ rb_str_buf_cat2(msg, " ");
476
+ }
477
+ if (strstr(errmsg, sonames[idx]) == NULL) {
478
+ /* prepend "soname: " if soname is not found in
479
+ * the error message.
480
+ */
481
+ rb_str_buf_cat2(msg, sonames[idx]);
482
+ rb_str_buf_cat2(msg, ": ");
483
+ }
484
+ rb_str_buf_append(msg, RARRAY_PTR(err)[idx]);
485
+ rb_str_buf_cat2(msg, ";");
486
+ }
487
+ rb_exc_raise(rb_exc_new3(rb_eLoadError, msg));
488
+ }
489
+ }
490
+ return dlsym(handle, symbol_name);
491
+ #endif /* defined _WIN32 */
492
+ }
493
+ #endif /* RUNTIME_API_CHECK */