ruby-oci8 2.2.0.2 → 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 (83) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +1 -6
  3. data/ChangeLog +600 -0
  4. data/NEWS +426 -35
  5. data/README.md +27 -9
  6. data/dist-files +13 -2
  7. data/docs/bind-array-to-in_cond.md +38 -0
  8. data/docs/conflicts-local-connections-and-processes.md +98 -0
  9. data/docs/hanging-after-inactivity.md +63 -0
  10. data/docs/install-binary-package.md +15 -11
  11. data/docs/install-full-client.md +18 -21
  12. data/docs/install-instant-client.md +45 -27
  13. data/docs/install-on-osx.md +31 -117
  14. data/docs/ldap-auth-and-function-interposition.md +123 -0
  15. data/docs/number-type-mapping.md +79 -0
  16. data/docs/platform-specific-issues.md +17 -50
  17. data/docs/report-installation-issue.md +11 -8
  18. data/docs/timeout-parameters.md +94 -0
  19. data/ext/oci8/apiwrap.c.tmpl +2 -5
  20. data/ext/oci8/apiwrap.rb +6 -1
  21. data/ext/oci8/apiwrap.yml +39 -143
  22. data/ext/oci8/attr.c +4 -2
  23. data/ext/oci8/bind.c +421 -9
  24. data/ext/oci8/connection_pool.c +3 -3
  25. data/ext/oci8/encoding.c +5 -5
  26. data/ext/oci8/env.c +8 -2
  27. data/ext/oci8/error.c +24 -16
  28. data/ext/oci8/extconf.rb +35 -63
  29. data/ext/oci8/hook_funcs.c +274 -61
  30. data/ext/oci8/lob.c +31 -75
  31. data/ext/oci8/metadata.c +8 -6
  32. data/ext/oci8/object.c +119 -29
  33. data/ext/oci8/oci8.c +46 -133
  34. data/ext/oci8/oci8.h +40 -123
  35. data/ext/oci8/oci8lib.c +178 -46
  36. data/ext/oci8/ocihandle.c +37 -37
  37. data/ext/oci8/ocinumber.c +24 -35
  38. data/ext/oci8/oraconf.rb +168 -337
  39. data/ext/oci8/oradate.c +19 -19
  40. data/ext/oci8/plthook.h +10 -0
  41. data/ext/oci8/plthook_elf.c +433 -268
  42. data/ext/oci8/plthook_osx.c +40 -9
  43. data/ext/oci8/plthook_win32.c +16 -1
  44. data/ext/oci8/stmt.c +52 -17
  45. data/ext/oci8/win32.c +4 -22
  46. data/lib/oci8/bindtype.rb +10 -17
  47. data/lib/oci8/check_load_error.rb +57 -10
  48. data/lib/oci8/compat.rb +5 -1
  49. data/lib/oci8/connection_pool.rb +74 -3
  50. data/lib/oci8/cursor.rb +70 -31
  51. data/lib/oci8/metadata.rb +9 -1
  52. data/lib/oci8/object.rb +14 -1
  53. data/lib/oci8/oci8.rb +184 -58
  54. data/lib/oci8/ocihandle.rb +0 -16
  55. data/lib/oci8/oracle_version.rb +11 -1
  56. data/lib/oci8/properties.rb +55 -0
  57. data/lib/oci8/version.rb +1 -1
  58. data/lib/oci8.rb +48 -4
  59. data/lib/ruby-oci8.rb +1 -0
  60. data/pre-distclean.rb +1 -3
  61. data/ruby-oci8.gemspec +4 -9
  62. data/setup.rb +11 -2
  63. data/test/README.md +37 -0
  64. data/test/config.rb +8 -1
  65. data/test/setup_test_object.sql +42 -14
  66. data/test/setup_test_package.sql +59 -0
  67. data/test/test_all.rb +4 -0
  68. data/test/test_bind_array.rb +70 -0
  69. data/test/test_bind_boolean.rb +99 -0
  70. data/test/test_bind_integer.rb +47 -0
  71. data/test/test_break.rb +11 -9
  72. data/test/test_clob.rb +5 -17
  73. data/test/test_connstr.rb +142 -0
  74. data/test/test_datetime.rb +8 -3
  75. data/test/test_metadata.rb +2 -1
  76. data/test/test_object.rb +99 -18
  77. data/test/test_oci8.rb +170 -46
  78. data/test/test_oranumber.rb +12 -6
  79. data/test/test_package_type.rb +17 -3
  80. data/test/test_properties.rb +17 -0
  81. metadata +45 -55
  82. data/docs/osx-install-dev-tools.png +0 -0
  83. data/test/README +0 -42
@@ -73,10 +73,10 @@ struct plthook {
73
73
  };
74
74
 
75
75
  static int plthook_open_real(plthook_t **plthook_out, const struct mach_header *mh);
76
- static unsigned int get_bind_addr(plthook_t *plthook, const uint8_t *base, uint32_t lazy_bind_off, uint32_t lazy_bind_size, struct segment_command_ **segments, int addrdiff);
76
+ static unsigned int get_bind_addr(plthook_t *plthook, const uint8_t *base, uint32_t lazy_bind_off, uint32_t lazy_bind_size, struct segment_command_ **segments, ptrdiff_t addrdiff);
77
77
 
78
78
  static void set_errmsg(const char *fmt, ...) __attribute__((__format__ (__printf__, 1, 2)));
79
- static void set_bind_addr(unsigned int *idx, plthook_t *plthook, const uint8_t *base, const char *sym_name, int seg_index, int seg_offset, struct segment_command_ **segments);
79
+ static void set_bind_addr(unsigned int *idx, plthook_t *plthook, const uint8_t *base, const char *sym_name, int seg_index, uint64_t seg_offset, struct segment_command_ **segments);
80
80
 
81
81
  static uint64_t uleb128(const uint8_t **p)
82
82
  {
@@ -142,6 +142,37 @@ int plthook_open(plthook_t **plthook_out, const char *filename)
142
142
  return plthook_open_real(plthook_out, _dyld_get_image_header(idx));
143
143
  }
144
144
 
145
+ int plthook_open_by_handle(plthook_t **plthook_out, void *hndl)
146
+ {
147
+ int flags[] = {
148
+ RTLD_LAZY | RTLD_NOLOAD,
149
+ RTLD_LAZY | RTLD_NOLOAD | RTLD_FIRST,
150
+ };
151
+ size_t flag_idx;
152
+ #define NUM_FLAGS (sizeof(flags) / sizeof(flags[0]))
153
+
154
+ if (hndl == NULL) {
155
+ set_errmsg("NULL handle");
156
+ return PLTHOOK_FILE_NOT_FOUND;
157
+ }
158
+ for (flag_idx = 0; flag_idx < NUM_FLAGS; flag_idx++) {
159
+ const char *image_name = NULL;
160
+ uint32_t idx = 0;
161
+
162
+ do {
163
+ void *handle = dlopen(image_name, flags[flag_idx]);
164
+ if (handle != NULL) {
165
+ dlclose(handle);
166
+ if (handle == hndl) {
167
+ return plthook_open_real(plthook_out, _dyld_get_image_header(idx));
168
+ }
169
+ }
170
+ } while ((image_name = _dyld_get_image_name(++idx)) != NULL);
171
+ }
172
+ set_errmsg("Cannot find the image correspond to handle %p", hndl);
173
+ return PLTHOOK_FILE_NOT_FOUND;
174
+ }
175
+
145
176
  int plthook_open_by_address(plthook_t **plthook_out, void *address)
146
177
  {
147
178
  Dl_info dlinfo;
@@ -165,8 +196,8 @@ static int plthook_open_real(plthook_t **plthook_out, const struct mach_header *
165
196
  struct segment_command_ *segments[NUM_SEGMENTS];
166
197
  int segment_idx = 0;
167
198
  unsigned int nbind;
168
- int addrdiff = 0;
169
- int i;
199
+ ptrdiff_t addrdiff = 0;
200
+ uint32_t i;
170
201
 
171
202
  memset(segments, 0, sizeof(segments));
172
203
  #ifdef __LP64__
@@ -289,14 +320,14 @@ static int plthook_open_real(plthook_t **plthook_out, const struct mach_header *
289
320
  return 0;
290
321
  }
291
322
 
292
- static unsigned int get_bind_addr(plthook_t *plthook, const uint8_t *base, uint32_t lazy_bind_off, uint32_t lazy_bind_size, struct segment_command_ **segments, int addrdiff)
323
+ static unsigned int get_bind_addr(plthook_t *plthook, const uint8_t *base, uint32_t lazy_bind_off, uint32_t lazy_bind_size, struct segment_command_ **segments, ptrdiff_t addrdiff)
293
324
  {
294
325
  const uint8_t *ptr = base + lazy_bind_off + addrdiff;
295
326
  const uint8_t *end = ptr + lazy_bind_size;
296
327
  const char *sym_name;
297
328
  int seg_index = 0;
298
329
  uint64_t seg_offset = 0;
299
- int count, skip;
330
+ uint64_t count, skip;
300
331
  unsigned int idx;
301
332
  DEBUG_BIND("get_bind_addr(%p, 0x%x, 0x%x", base, lazy_bind_off, lazy_bind_size);
302
333
  for (idx = 0; segments[idx] != NULL; idx++) {
@@ -310,7 +341,7 @@ static unsigned int get_bind_addr(plthook_t *plthook, const uint8_t *base, uint3
310
341
  uint8_t imm = *ptr & BIND_IMMEDIATE_MASK;
311
342
  uint64_t ulebval;
312
343
  int64_t slebval;
313
- int i;
344
+ uint64_t i;
314
345
 
315
346
  DEBUG_BIND("0x%02x: ", *ptr);
316
347
  ptr++;
@@ -379,10 +410,10 @@ static unsigned int get_bind_addr(plthook_t *plthook, const uint8_t *base, uint3
379
410
  return idx;
380
411
  }
381
412
 
382
- static void set_bind_addr(unsigned int *idx, plthook_t *plthook, const uint8_t *base, const char *sym_name, int seg_index, int seg_offset, struct segment_command_ **segments)
413
+ static void set_bind_addr(unsigned int *idx, plthook_t *plthook, const uint8_t *base, const char *sym_name, int seg_index, uint64_t seg_offset, struct segment_command_ **segments)
383
414
  {
384
415
  if (plthook != NULL) {
385
- uint32_t vmaddr = segments[seg_index]->vmaddr;
416
+ uint64_t vmaddr = segments[seg_index]->vmaddr;
386
417
  plthook->entries[*idx].name = sym_name;
387
418
  plthook->entries[*idx].addr = (void**)(base + vmaddr + seg_offset);
388
419
  }
@@ -51,12 +51,18 @@
51
51
  #define __attribute__(arg)
52
52
  #endif
53
53
 
54
- #ifdef _WIN64
54
+ #if defined _LP64 /* data model: I32/LP64 */
55
+ #define SIZE_T_FMT "lu"
56
+ #elif defined _WIN64 /* data model: IL32/P64 */
55
57
  #define SIZE_T_FMT "I64u"
56
58
  #else
57
59
  #define SIZE_T_FMT "u"
58
60
  #endif
59
61
 
62
+ #ifdef __CYGWIN__
63
+ #define stricmp strcasecmp
64
+ #endif
65
+
60
66
  typedef struct {
61
67
  const char *mod_name;
62
68
  const char *name;
@@ -87,6 +93,15 @@ int plthook_open(plthook_t **plthook_out, const char *filename)
87
93
  return plthook_open_real(plthook_out, hMod);
88
94
  }
89
95
 
96
+ int plthook_open_by_handle(plthook_t **plthook_out, void *hndl)
97
+ {
98
+ if (hndl == NULL) {
99
+ set_errmsg("NULL handle");
100
+ return PLTHOOK_FILE_NOT_FOUND;
101
+ }
102
+ return plthook_open_real(plthook_out, (HMODULE)hndl);
103
+ }
104
+
90
105
  int plthook_open_by_address(plthook_t **plthook_out, void *address)
91
106
  {
92
107
  HMODULE hMod;
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
- int use_stmt_release;
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)
@@ -77,7 +78,7 @@ static VALUE oci8_stmt_initialize(VALUE self, VALUE svc, VALUE sql)
77
78
  if (!NIL_P(sql)) {
78
79
  OCI8SafeStringValue(sql);
79
80
 
80
- rv = OCIStmtPrepare2(svcctx->base.hp.svc, &stmt->base.hp.stmt, oci8_errhp, RSTRING_ORATEXT(sql), RSTRING_LEN(sql), NULL, 0, OCI_NTV_SYNTAX, OCI_DEFAULT);
81
+ rv = OCIStmtPrepare2(svcctx->base.hp.svc, &stmt->base.hp.stmt, oci8_errhp, RSTRING_ORATEXT(sql), RSTRING_LENINT(sql), NULL, 0, OCI_NTV_SYNTAX, OCI_DEFAULT);
81
82
  if (IS_OCI_ERROR(rv)) {
82
83
  chker2(rv, &svcctx->base);
83
84
  }
@@ -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
- status = OCIDefineByPos(stmt->base.hp.stmt, &obind->base.hp.dfn, oci8_errhp, position, obind->valuep, obind->value_sz, data_type->dty, NIL_P(obind->tdo) ? obind->u.inds : NULL, NULL, 0, OCI_DEFAULT);
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;
@@ -163,10 +178,10 @@ static VALUE oci8_bind(VALUE self, VALUE vplaceholder, VALUE vbindobj)
163
178
  */
164
179
  VALUE symval = rb_sym2str(vplaceholder);
165
180
  const char *symname = RSTRING_PTR(symval);
166
- size_t len = RSTRING_LEN(symval);
181
+ ub4 len = RSTRING_LENINT(symval);
167
182
  #else
168
183
  const char *symname = rb_id2name(SYM2ID(vplaceholder));
169
- size_t len = strlen(symname);
184
+ ub4 len = (ub4)strlen(symname);
170
185
  #endif
171
186
  placeholder_ptr = ALLOCA_N(char, len + 1);
172
187
  placeholder_len = len + 1;
@@ -177,7 +192,7 @@ static VALUE oci8_bind(VALUE self, VALUE vplaceholder, VALUE vbindobj)
177
192
  } else {
178
193
  OCI8StringValue(vplaceholder);
179
194
  placeholder_ptr = RSTRING_PTR(vplaceholder);
180
- placeholder_len = RSTRING_LEN(vplaceholder);
195
+ placeholder_len = RSTRING_LENINT(vplaceholder);
181
196
  }
182
197
  obind = TO_BIND(vbindobj); /* 2 */
183
198
  if (obind->base.hp.bnd != 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
- indp = NIL_P(obind->tdo) ? obind->u.inds : NULL;
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, obind->valuep, obind->value_sz, data_type->dty, indp, NULL, 0, 0, 0, OCI_DEFAULT);
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, obind->valuep, obind->value_sz, data_type->dty, indp, NULL, 0, 0, 0, OCI_DEFAULT);
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, 1, OCI_FETCH_NEXT, OCI_DEFAULT);
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
- return Qfalse;
312
+ stmt->end_of_fetch = 1;
313
+ } else {
314
+ chker3(rv, &svcctx->base, stmt->base.hp.stmt);
281
315
  }
282
- chker3(rv, &svcctx->base, stmt->base.hp.stmt);
283
- return Qtrue;
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
  /*
@@ -288,7 +323,7 @@ static VALUE oci8_stmt_fetch(VALUE self, VALUE svc)
288
323
  *
289
324
  * Returns the definition of column specified by <i>pos</i>
290
325
  *
291
- * @param [Fixnum] pos Column position which starts from one
326
+ * @param [Integer] pos Column position which starts from one
292
327
  * @return [OCI8::Metadata::Base]
293
328
  *
294
329
  * @private
@@ -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, 1);
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/ext/oci8/win32.c CHANGED
@@ -21,33 +21,14 @@
21
21
  * @private
22
22
  */
23
23
 
24
- NORETURN(static void raise_error(void));
25
-
26
- static void raise_error(void)
27
- {
28
- char msg[1024];
29
- int err = GetLastError();
30
- char *p;
31
-
32
- sprintf(msg, "%d: ", err);
33
- FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
34
- NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
35
- msg + strlen(msg), sizeof(msg) - strlen(msg), NULL);
36
- for (p = msg; *p != '\0'; p++) {
37
- if (*p == '\n' || *p == '\r') {
38
- *p = ' ';
39
- }
40
- }
41
- rb_raise(rb_eRuntimeError, "%s", msg);
42
- }
43
-
44
24
  typedef struct {
45
25
  HKEY hKey;
46
26
  HKEY hSubKey;
47
27
  } enum_homes_arg_t;
48
28
 
49
- static VALUE enum_homes_real(enum_homes_arg_t *arg)
29
+ static VALUE enum_homes_real(VALUE varg)
50
30
  {
31
+ enum_homes_arg_t *arg = (enum_homes_arg_t *)varg;
51
32
  LONG rv;
52
33
  DWORD type;
53
34
  DWORD idx;
@@ -97,8 +78,9 @@ static VALUE enum_homes_real(enum_homes_arg_t *arg)
97
78
  return Qnil;
98
79
  }
99
80
 
100
- static VALUE enum_homes_ensure(enum_homes_arg_t *arg)
81
+ static VALUE enum_homes_ensure(VALUE varg)
101
82
  {
83
+ enum_homes_arg_t *arg = (enum_homes_arg_t *)varg;
102
84
  if (arg->hKey != NULL) {
103
85
  RegCloseKey(arg->hKey);
104
86
  arg->hKey = NULL;
data/lib/oci8/bindtype.rb CHANGED
@@ -49,7 +49,7 @@ class OCI8
49
49
 
50
50
  class BasicNumberType < OCI8::BindType::OraNumber
51
51
  def get()
52
- (val = super()) && (val.has_decimal_part? ? val.to_f : val.to_i)
52
+ (val = super()) && (val.has_fractional_part? ? val.to_f : val.to_i)
53
53
  end
54
54
  end
55
55
 
@@ -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
@@ -203,10 +189,13 @@ OCI8::BindType::Mapping[String] = OCI8::BindType::String
203
189
  OCI8::BindType::Mapping[OraNumber] = OCI8::BindType::OraNumber
204
190
  OCI8::BindType::Mapping['BigDecimal'] = OCI8::BindType::BigDecimal
205
191
  OCI8::BindType::Mapping['Rational'] = OCI8::BindType::Rational
206
- OCI8::BindType::Mapping[Fixnum] = OCI8::BindType::Integer
207
192
  OCI8::BindType::Mapping[Float] = OCI8::BindType::Float
208
193
  OCI8::BindType::Mapping[Integer] = OCI8::BindType::Integer
209
- OCI8::BindType::Mapping[Bignum] = OCI8::BindType::Integer
194
+ unless 0.class == Integer
195
+ # ruby before integer unification
196
+ OCI8::BindType::Mapping[Fixnum] = OCI8::BindType::Integer
197
+ OCI8::BindType::Mapping[Bignum] = OCI8::BindType::Integer
198
+ end
210
199
  OCI8::BindType::Mapping[OraDate] = OCI8::BindType::OraDate
211
200
  OCI8::BindType::Mapping[Time] = OCI8::BindType::Time
212
201
  OCI8::BindType::Mapping[Date] = OCI8::BindType::Date
@@ -216,6 +205,10 @@ OCI8::BindType::Mapping[OCI8::NCLOB] = OCI8::BindType::NCLOB
216
205
  OCI8::BindType::Mapping[OCI8::BLOB] = OCI8::BindType::BLOB
217
206
  OCI8::BindType::Mapping[OCI8::BFILE] = OCI8::BindType::BFILE
218
207
  OCI8::BindType::Mapping[OCI8::Cursor] = OCI8::BindType::Cursor
208
+ if defined? OCI8::BindType::Boolean
209
+ OCI8::BindType::Mapping[TrueClass] = OCI8::BindType::Boolean
210
+ OCI8::BindType::Mapping[FalseClass] = OCI8::BindType::Boolean
211
+ end
219
212
 
220
213
  # implicitly define
221
214
 
@@ -4,32 +4,79 @@ class OCI8
4
4
  module Util
5
5
 
6
6
  case RUBY_PLATFORM
7
- when /mswin32|cygwin|mingw32|bccwin32/
7
+ when /mswin32|cygwin|mingw/
8
+
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)"
8
24
 
9
- require 'Win32API'
10
25
  MAX_PATH = 260
11
- GetModuleFileNameA = Win32API.new('kernel32', 'GetModuleFileNameA', 'PPL', 'L')
12
- GetSystemDirectoryA = Win32API.new('kernel32', 'GetSystemDirectoryA', 'PL', 'L')
13
- GetWindowsDirectoryA = Win32API.new('kernel32', 'GetWindowsDirectoryA', 'PL', 'L')
26
+ DONT_RESOLVE_DLL_REFERENCES = 0x00000001
14
27
 
15
28
  def self.check_os_specific_load_error(exc)
16
29
  case exc.message
17
- when /^193: / # "193: %1 is not a valid Win32 application." in English
30
+ when /^OCI\.DLL: 193\(/, /^193: / # "OCI.DLL: 193(%1 is not a valid Win32 application.)" in English
18
31
  check_win32_pe_arch(exc.message.split(' - ')[1], "ruby-oci8")
19
32
  dll_load_path_list.each do |path|
20
33
  check_win32_pe_arch(File.join(path, '\OCI.DLL'), "Oracle client")
21
34
  end
35
+ when /^OCI.DLL: 126\(/, /^126: / # "OCI.DLL: 126(The specified module could not be found.)" in English
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}.
62
+ See http://www.rubydoc.info/github/kubo/ruby-oci8/file/docs/install-instant-client.md#Windows
63
+ EOS
64
+ end
65
+ break
66
+ end
67
+ end
68
+ raise first_error if first_error
22
69
  end
23
70
  end # self.check_os_specific_load_error
24
71
 
25
72
  def self.dll_load_path_list
26
73
  buf = "\0" * MAX_PATH
27
74
  paths = []
28
- paths << buf[0, GetModuleFileNameA.call(nil, buf, MAX_PATH)].force_encoding("locale").gsub(/\\[^\\]*$/, '')
29
- paths << buf[0, GetSystemDirectoryA.call(buf, MAX_PATH)].force_encoding("locale")
30
- paths << buf[0, GetWindowsDirectoryA.call(buf, MAX_PATH)].force_encoding("locale")
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")
31
78
  paths << "."
32
- paths + ENV['PATH'].split(';')
79
+ paths + (ENV['PATH'].split(';').reject {|path| path.empty?})
33
80
  end # self.dll_load_path_list
34
81
 
35
82
  def self.check_win32_pe_arch(filename, package)
data/lib/oci8/compat.rb CHANGED
@@ -70,7 +70,7 @@ class OCI8
70
70
  constants.each do |name|
71
71
  next if name.to_s.index("SQLT_") != 0
72
72
  val = const_get name.intern
73
- if val.is_a? Fixnum
73
+ if val.is_a? Integer
74
74
  SQLT_NAMES[val] = name
75
75
  end
76
76
  end
@@ -79,6 +79,10 @@ class OCI8
79
79
  alias autocommit autocommit?
80
80
 
81
81
  class Cursor
82
+ # @!visibility private
83
+ # dirty hack to suppress "warning: constant ::Fixnum is deprecated"
84
+ Fixnum = (0.class == ::Integer) ? ::Integer : ::Fixnum
85
+
82
86
  def self.select_number_as=(val)
83
87
  if val == Fixnum
84
88
  @@bind_unknown_number = OCI8::BindType::Fixnum
@@ -13,17 +13,88 @@ class OCI8
13
13
  #
14
14
  # This is equivalent to Oracle JDBC Driver {OCI Connection Pooling}[http://docs.oracle.com/cd/E11882_01/java.112/e16548/ociconpl.htm#JJDBC28789].
15
15
  #
16
- # Usage:
16
+ # Note that this is different with generally called connection pooling.
17
+ # Generally connection pooling caches connections in a pool.
18
+ # When an application needs a new connection, a connection is got from
19
+ # the pool. So that the amount of time to establish a connection is
20
+ # reduced. However connection pooling in ruby-oci8 is different with
21
+ # above.
22
+ #
23
+ # One Oracle connection is devided into two layers: One is physical
24
+ # connection such as TCP/IP. The other is logical connection which
25
+ # is used by an application. The connection pooling in ruby-oci8
26
+ # caches physical connections in a pool, not logical connections.
27
+ # When an application needs a new connection, a logical connection
28
+ # is created via a physical connection, which needs time to
29
+ # establish a connection unlike generally called connection pooling.
30
+ # When an application sends a query via a logical connection, a
31
+ # physical connection is got from the pool. The physical connection
32
+ # returns to the pool automatically when the query finishes.
33
+ # As long as logical connections are used sequentially, only one
34
+ # physical connection is used. When an application sends
35
+ # queries at a time, it needs more than one physical connection
36
+ # because one physical connection cannot transmit more then one
37
+ # query at a time.
38
+ #
39
+ # Example:
17
40
  # # Create a connection pool.
41
+ # # The number of initial physical connections: 1
42
+ # # The number of maximum physical connections: 5
43
+ # # the connection increment parameter: 2
18
44
  # # username and password are required to establish an implicit primary session.
19
45
  # cpool = OCI8::ConnectionPool.new(1, 5, 2, username, password, database)
20
46
  #
21
- # # Get a session from the pool.
47
+ # # The number of physical connections: 1
48
+ # # The number of logical connections: 0
49
+ #
50
+ # # Create a session.
22
51
  # # Pass the connection pool to the third argument.
23
52
  # conn1 = OCI8.new(username, password, cpool)
24
53
  #
25
- # # Get another session.
54
+ # # One logical connection was created.
55
+ # # The number of physical connections: 1
56
+ # # The number of logical connections: 1
57
+ #
58
+ # # Create another session.
26
59
  # conn2 = OCI8.new(username, password, cpool)
60
+ #
61
+ # # Another logical connection was created.
62
+ # # The number of physical connections: 1
63
+ # # The number of logical connections: 2
64
+ #
65
+ # # Use conn1 and conn2 sequentially
66
+ # conn1.exec('...')
67
+ # conn2.exec('...')
68
+ #
69
+ # # Both logical connections use one physical connection.
70
+ # # The number of physical connections: 1
71
+ # # The number of logical connections: 2
72
+ #
73
+ # thr1 = Thread.new do
74
+ # conn1.exec('...')
75
+ # end
76
+ # thr2 = Thread.new do
77
+ # conn2.exec('...')
78
+ # end
79
+ # thr1.join
80
+ # thr2.join
81
+ #
82
+ # # Logical connections cannot use one physical connection at a time.
83
+ # # So that the number of physical connections is incremented.
84
+ # # The number of physical connections: 3
85
+ # # The number of logical connections: 2
86
+ #
87
+ # conn1.logoff
88
+ #
89
+ # # One logical connection was closed.
90
+ # # The number of physical connections: 3
91
+ # # The number of logical connections: 1
92
+ #
93
+ # conn2.logoff
94
+ #
95
+ # # All logical connections were closed.
96
+ # # The number of physical connections: 3
97
+ # # The number of logical connections: 0
27
98
  #
28
99
  class ConnectionPool
29
100