ruby-oci8 2.2.0.2 → 2.2.12

Sign up to get free protection for your applications and to get access to all the features.
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