ruby-oci8 2.2.6.1 → 2.2.10

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.
@@ -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
  {
@@ -148,7 +148,7 @@ int plthook_open_by_handle(plthook_t **plthook_out, void *hndl)
148
148
  RTLD_LAZY | RTLD_NOLOAD,
149
149
  RTLD_LAZY | RTLD_NOLOAD | RTLD_FIRST,
150
150
  };
151
- int flag_idx;
151
+ size_t flag_idx;
152
152
  #define NUM_FLAGS (sizeof(flags) / sizeof(flags[0]))
153
153
 
154
154
  if (hndl == NULL) {
@@ -196,8 +196,8 @@ static int plthook_open_real(plthook_t **plthook_out, const struct mach_header *
196
196
  struct segment_command_ *segments[NUM_SEGMENTS];
197
197
  int segment_idx = 0;
198
198
  unsigned int nbind;
199
- int addrdiff = 0;
200
- int i;
199
+ ptrdiff_t addrdiff = 0;
200
+ uint32_t i;
201
201
 
202
202
  memset(segments, 0, sizeof(segments));
203
203
  #ifdef __LP64__
@@ -320,14 +320,14 @@ static int plthook_open_real(plthook_t **plthook_out, const struct mach_header *
320
320
  return 0;
321
321
  }
322
322
 
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, 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)
324
324
  {
325
325
  const uint8_t *ptr = base + lazy_bind_off + addrdiff;
326
326
  const uint8_t *end = ptr + lazy_bind_size;
327
327
  const char *sym_name;
328
328
  int seg_index = 0;
329
329
  uint64_t seg_offset = 0;
330
- int count, skip;
330
+ uint64_t count, skip;
331
331
  unsigned int idx;
332
332
  DEBUG_BIND("get_bind_addr(%p, 0x%x, 0x%x", base, lazy_bind_off, lazy_bind_size);
333
333
  for (idx = 0; segments[idx] != NULL; idx++) {
@@ -341,7 +341,7 @@ static unsigned int get_bind_addr(plthook_t *plthook, const uint8_t *base, uint3
341
341
  uint8_t imm = *ptr & BIND_IMMEDIATE_MASK;
342
342
  uint64_t ulebval;
343
343
  int64_t slebval;
344
- int i;
344
+ uint64_t i;
345
345
 
346
346
  DEBUG_BIND("0x%02x: ", *ptr);
347
347
  ptr++;
@@ -410,10 +410,10 @@ static unsigned int get_bind_addr(plthook_t *plthook, const uint8_t *base, uint3
410
410
  return idx;
411
411
  }
412
412
 
413
- 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)
414
414
  {
415
415
  if (plthook != NULL) {
416
- uint32_t vmaddr = segments[seg_index]->vmaddr;
416
+ uint64_t vmaddr = segments[seg_index]->vmaddr;
417
417
  plthook->entries[*idx].name = sym_name;
418
418
  plthook->entries[*idx].addr = (void**)(base + vmaddr + seg_offset);
419
419
  }
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
  /*
@@ -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
@@ -26,8 +26,9 @@ typedef struct {
26
26
  HKEY hSubKey;
27
27
  } enum_homes_arg_t;
28
28
 
29
- static VALUE enum_homes_real(enum_homes_arg_t *arg)
29
+ static VALUE enum_homes_real(VALUE varg)
30
30
  {
31
+ enum_homes_arg_t *arg = (enum_homes_arg_t *)varg;
31
32
  LONG rv;
32
33
  DWORD type;
33
34
  DWORD idx;
@@ -77,8 +78,9 @@ static VALUE enum_homes_real(enum_homes_arg_t *arg)
77
78
  return Qnil;
78
79
  }
79
80
 
80
- static VALUE enum_homes_ensure(enum_homes_arg_t *arg)
81
+ static VALUE enum_homes_ensure(VALUE varg)
81
82
  {
83
+ enum_homes_arg_t *arg = (enum_homes_arg_t *)varg;
82
84
  if (arg->hKey != NULL) {
83
85
  RegCloseKey(arg->hKey);
84
86
  arg->hKey = NULL;
data/lib/oci8/bindtype.rb CHANGED
@@ -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
@@ -6,14 +6,24 @@ class OCI8
6
6
  case RUBY_PLATFORM
7
7
  when /mswin32|cygwin|mingw32|bccwin32/
8
8
 
9
- require 'Win32API'
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)"
24
+
10
25
  MAX_PATH = 260
11
- GetModuleFileNameA = Win32API.new('kernel32.dll', 'GetModuleFileNameA', 'PPL', 'L')
12
- GetSystemDirectoryA = Win32API.new('kernel32.dll', 'GetSystemDirectoryA', 'PL', 'L')
13
- GetWindowsDirectoryA = Win32API.new('kernel32.dll', 'GetWindowsDirectoryA', 'PL', 'L')
14
- LoadLibraryExA = Win32API.new('kernel32.dll', 'LoadLibraryExA', 'PPL', 'P')
15
- FreeLibrary = Win32API.new('kernel32.dll', 'FreeLibrary', 'P', 'L')
16
- LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020
26
+ DONT_RESOLVE_DLL_REFERENCES = 0x00000001
17
27
 
18
28
  def self.check_os_specific_load_error(exc)
19
29
  case exc.message
@@ -23,25 +33,50 @@ class OCI8
23
33
  check_win32_pe_arch(File.join(path, '\OCI.DLL'), "Oracle client")
24
34
  end
25
35
  when /^OCI.DLL: 126\(/, /^126: / # "OCI.DLL: 126(The specified module could not be found.)" in English
26
- handle = LoadLibraryExA.call('OCI.DLL', nil, LOAD_LIBRARY_AS_IMAGE_RESOURCE)
27
- unless handle.null?
28
- FreeLibrary.call(handle)
29
- raise LoadError, <<EOS
30
- OCI.DLL is in the PATH but its dependent modules are not found.
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}.
31
62
  See http://www.rubydoc.info/github/kubo/ruby-oci8/file/docs/install-instant-client.md#Windows
32
63
  EOS
64
+ end
65
+ break
66
+ end
33
67
  end
68
+ raise first_error if first_error
34
69
  end
35
70
  end # self.check_os_specific_load_error
36
71
 
37
72
  def self.dll_load_path_list
38
73
  buf = "\0" * MAX_PATH
39
74
  paths = []
40
- paths << buf[0, GetModuleFileNameA.call(nil, buf, MAX_PATH)].force_encoding("locale").gsub(/\\[^\\]*$/, '')
41
- paths << buf[0, GetSystemDirectoryA.call(buf, MAX_PATH)].force_encoding("locale")
42
- 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")
43
78
  paths << "."
44
- paths + ENV['PATH'].split(';')
79
+ paths + (ENV['PATH'].split(';').reject {|path| path.empty?})
45
80
  end # self.dll_load_path_list
46
81
 
47
82
  def self.check_win32_pe_arch(filename, package)
data/lib/oci8/cursor.rb CHANGED
@@ -25,7 +25,11 @@ class OCI8
25
25
  @names = nil
26
26
  @con = conn
27
27
  @max_array_size = nil
28
+ @fetch_array_size = nil
29
+ @rowbuf_size = 0
30
+ @rowbuf_index = 0
28
31
  __initialize(conn, sql) # Initialize the internal C structure.
32
+ self.prefetch_rows = conn.instance_variable_get(:@prefetch_rows)
29
33
  end
30
34
 
31
35
  # explicitly indicate the date type of fetched value. run this
@@ -38,7 +42,7 @@ class OCI8
38
42
  # cursor.define(2, Time) # fetch the second column as Time.
39
43
  # cursor.exec()
40
44
  def define(pos, type, length = nil)
41
- bindobj = make_bind_object(:type => type, :length => length)
45
+ bindobj = make_bind_object({:type => type, :length => length}, @fetch_array_size || 1)
42
46
  __define(pos, bindobj)
43
47
  if old = @define_handles[pos - 1]
44
48
  old.send(:free)
@@ -126,6 +130,8 @@ class OCI8
126
130
  when :select_stmt
127
131
  __execute(0)
128
132
  define_columns() if @column_metadata.size == 0
133
+ @rowbuf_size = 0
134
+ @rowbuf_index = 0
129
135
  @column_metadata.size
130
136
  else
131
137
  __execute(1)
@@ -384,6 +390,7 @@ class OCI8
384
390
  # @param [Integer] rows The number of rows to be prefetched
385
391
  def prefetch_rows=(rows)
386
392
  attr_set_ub4(11, rows) # OCI_ATTR_PREFETCH_ROWS(11)
393
+ @prefetch_rows = rows
387
394
  end
388
395
 
389
396
  if OCI8::oracle_client_version >= ORAVER_12_1
@@ -468,7 +475,7 @@ class OCI8
468
475
 
469
476
  private
470
477
 
471
- def make_bind_object(param)
478
+ def make_bind_object(param, fetch_array_size = nil)
472
479
  case param
473
480
  when Hash
474
481
  key = param[:type]
@@ -510,22 +517,37 @@ class OCI8
510
517
  OCI8::BindType::Mapping[key] = bindclass if bindclass
511
518
  end
512
519
  raise "unsupported datatype: #{key}" if bindclass.nil?
513
- bindclass.create(@con, val, param, max_array_size)
520
+ bindclass.create(@con, val, param, fetch_array_size || max_array_size)
514
521
  end
515
522
 
523
+ @@use_array_fetch = false
524
+
516
525
  def define_columns
517
526
  # http://docs.oracle.com/cd/E11882_01/appdev.112/e10646/ociaahan.htm#sthref5494
518
527
  num_cols = attr_get_ub4(18) # OCI_ATTR_PARAM_COUNT(18)
519
- 1.upto(num_cols) do |i|
520
- parm = __paramGet(i)
521
- define_one_column(i, parm) unless @define_handles[i - 1]
522
- @column_metadata[i - 1] = parm
528
+ @column_metadata = 1.upto(num_cols).collect do |i|
529
+ __paramGet(i)
530
+ end
531
+ if @define_handles.size == 0
532
+ use_array_fetch = @@use_array_fetch
533
+ @column_metadata.each do |md|
534
+ case md.data_type
535
+ when :clob, :blob, :bfile
536
+ # Rows prefetching doesn't work for CLOB, BLOB and BFILE.
537
+ # Use array fetching to get more than one row in a network round trip.
538
+ use_array_fetch = true
539
+ end
540
+ end
541
+ @fetch_array_size = @prefetch_rows if use_array_fetch
542
+ end
543
+ @column_metadata.each_with_index do |md, i|
544
+ define_one_column(i + 1, md) unless @define_handles[i]
523
545
  end
524
546
  num_cols
525
547
  end
526
548
 
527
549
  def define_one_column(pos, param)
528
- bindobj = make_bind_object(param)
550
+ bindobj = make_bind_object(param, @fetch_array_size || 1)
529
551
  __define(pos, bindobj)
530
552
  @define_handles[pos - 1] = bindobj
531
553
  end
@@ -540,22 +562,33 @@ class OCI8
540
562
  end
541
563
  end
542
564
 
565
+ def fetch_row_internal
566
+ if @rowbuf_size && @rowbuf_size == @rowbuf_index
567
+ @rowbuf_size = __fetch(@con, @fetch_array_size || 1)
568
+ @rowbuf_index = 0
569
+ end
570
+ @rowbuf_size
571
+ end
572
+
543
573
  def fetch_one_row_as_array
544
- if __fetch(@con)
545
- @define_handles.collect do |handle|
546
- handle.send(:get_data)
574
+ if fetch_row_internal
575
+ ret = @define_handles.collect do |handle|
576
+ handle.send(:get_data, @rowbuf_index)
547
577
  end
578
+ @rowbuf_index += 1
579
+ ret
548
580
  else
549
581
  nil
550
582
  end
551
583
  end
552
584
 
553
585
  def fetch_one_row_as_hash
554
- if __fetch(@con)
586
+ if fetch_row_internal
555
587
  ret = {}
556
588
  get_col_names.each_with_index do |name, idx|
557
- ret[name] = @define_handles[idx].send(:get_data)
589
+ ret[name] = @define_handles[idx].send(:get_data, @rowbuf_index)
558
590
  end
591
+ @rowbuf_index += 1
559
592
  ret
560
593
  else
561
594
  nil
data/lib/oci8/oci8.rb CHANGED
@@ -169,7 +169,6 @@ class OCI8
169
169
  # @private
170
170
  def parse_internal(sql)
171
171
  cursor = OCI8::Cursor.new(self, sql)
172
- cursor.prefetch_rows = @prefetch_rows if @prefetch_rows
173
172
  cursor
174
173
  end
175
174
 
@@ -305,6 +304,7 @@ class OCI8
305
304
  # @return [Array] an array of first row.
306
305
  def select_one(sql, *bindvars)
307
306
  cursor = self.parse(sql)
307
+ cursor.prefetch_rows = 1
308
308
  begin
309
309
  cursor.exec(*bindvars)
310
310
  row = cursor.fetch
data/lib/oci8/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  class OCI8
2
- VERSION = "2.2.6.1"
2
+ VERSION = "2.2.10"
3
3
  end
data/lib/oci8.rb CHANGED
@@ -11,8 +11,11 @@ if RUBY_PLATFORM =~ /cygwin/
11
11
  # Cygwin manages environment variables by itself.
12
12
  # They don't synchroize with Win32's ones.
13
13
  # This set some Oracle's environment variables to win32's enviroment.
14
- require 'Win32API'
15
- win32setenv = Win32API.new('Kernel32.dll', 'SetEnvironmentVariableA', 'PP', 'I')
14
+ require 'fiddle'
15
+ win32setenv = Fiddle::Function.new( Fiddle.dlopen('Kernel32.dll')['SetEnvironmentVariableA'],
16
+ [Fiddle::TYPE_VOIDP,Fiddle::TYPE_VOIDP],
17
+ Fiddle::TYPE_INT )
18
+
16
19
  ['NLS_LANG', 'TNS_ADMIN', 'LOCAL'].each do |name|
17
20
  val = ENV[name]
18
21
  win32setenv.call(name, val && val.dup)
@@ -63,6 +66,8 @@ when 'rbx'
63
66
  so_basename += 'rbx'
64
67
  when 'jruby'
65
68
  raise "Ruby-oci8 doesn't support jruby because its C extension support is in development in jruby 1.6 and deprecated in jruby 1.7."
69
+ when 'truffleruby'
70
+ so_basename += 'truffleruby'
66
71
  else
67
72
  raise 'unsupported ruby engine: ' + RUBY_ENGINE
68
73
  end
@@ -95,7 +100,7 @@ begin
95
100
 
96
101
  ruby_arch = [nil].pack('P').size == 8 ? :x64 : :x86
97
102
  ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
98
- if dll_arch.call(File.join(path, 'OCI.DLL')) == ruby_arch
103
+ if !path.empty? && dll_arch.call(File.join(path, 'OCI.DLL')) == ruby_arch
99
104
  dll_dir = RubyInstaller::Runtime.add_dll_directory(path)
100
105
  break
101
106
  end
@@ -105,7 +110,7 @@ end
105
110
 
106
111
  begin
107
112
  require so_basename
108
- rescue LoadError, OCIError
113
+ rescue LoadError
109
114
  require 'oci8/check_load_error'
110
115
  OCI8::Util::check_load_error($!)
111
116
  raise
data/ruby-oci8.gemspec CHANGED
@@ -34,7 +34,6 @@ spec = Gem::Specification.new do |s|
34
34
  s.description = <<EOS
35
35
  ruby-oci8 is a ruby interface for Oracle using OCI8 API. It is available with Oracle 10g or later including Oracle Instant Client.
36
36
  EOS
37
- s.has_rdoc = 'yard'
38
37
  s.authors = ['Kubo Takehiro']
39
38
  s.platform = gem_platform
40
39
  s.license = 'BSD-2-Clause'
@@ -51,7 +50,7 @@ EOS
51
50
  # add map files to analyze a core (minidump) file.
52
51
  so_vers.each do |ver|
53
52
  map_file = 'ext/oci8/oci8lib_#{ver}.map'
54
- so_files << map_file if File.exists? map_file
53
+ so_files << map_file if File.exist? map_file
55
54
  end
56
55
 
57
56
  # least version in so_vers
@@ -79,7 +78,7 @@ EOS
79
78
  end
80
79
  files << 'lib/oci8.rb'
81
80
  end
82
- s.require_paths = ['lib', 'ext/oci8']
81
+ s.require_paths = ['lib']
83
82
  s.files = files
84
83
  s.test_files = 'test/test_all.rb'
85
84
  s.extra_rdoc_files = ['README.md']
data/setup.rb CHANGED
@@ -189,7 +189,16 @@ class ConfigTable
189
189
  'the make program to compile ruby extentions' ] ],
190
190
  [ 'without-ext', [ 'no',
191
191
  'yes/no',
192
- 'does not compile/install ruby extentions' ] ]
192
+ 'does not compile/install ruby extentions' ] ],
193
+ [ 'with-instant-client-dir', ['',
194
+ 'path',
195
+ 'path to the Oracle instant client directory'] ],
196
+ [ 'with-instant-client-lib', ['',
197
+ 'path',
198
+ 'path to the Oracle instant client libraries'] ],
199
+ [ 'with-instant-client-include', ['',
200
+ 'path',
201
+ 'path to the Oracle instant client header files'] ]
193
202
  ]
194
203
  multipackage_descripters = [
195
204
  [ 'with', [ '',
@@ -277,7 +286,7 @@ class ConfigTable
277
286
 
278
287
  def initialize_from_table
279
288
  @table = {}
280
- DESCRIPTER.each do |k, (default, vname, desc, default2)|
289
+ DESCRIPTER.each do |k, (default, *)|
281
290
  @table[k] = default
282
291
  end
283
292
  end
data/test/README.md ADDED
@@ -0,0 +1,37 @@
1
+ Before running unit test:
2
+
3
+ 1. Connect to Oracle as sys
4
+ ```shell
5
+ $ sqlplus sys/<password_of_sys> as sysdba
6
+ SQL>
7
+ ```
8
+ 2. Create user ruby
9
+ ```sql
10
+ SQL> CREATE USER ruby IDENTIFIED BY oci8 DEFAULT TABLESPACE users TEMPORARY TABLESPACE temp;
11
+ SQL> alter user ruby quota unlimited on users;
12
+ ```
13
+ 3. Grant the privilege to connect and execute.
14
+ ```sql
15
+ SQL> GRANT connect, resource, create view, create synonym TO ruby;
16
+ SQL> GRANT execute ON dbms_lock TO ruby;
17
+ ```
18
+ 4. Connect as ruby user.
19
+ ```shell
20
+ $ sqlplus ruby/oci8
21
+ SQL>
22
+ ```
23
+ 5. Create object types
24
+ ```sql
25
+ SQL> @test/setup_test_object.sql
26
+ SQL> @test/setup_test_package.sql
27
+ ```
28
+ 6. change $dbname in test/config.rb.
29
+
30
+ Then run the following command:
31
+ ```shell
32
+ $ make check
33
+ ```
34
+ or
35
+ ```
36
+ $ nmake check (If your compiler is MS Visual C++.)
37
+ ````
data/test/config.rb CHANGED
@@ -134,7 +134,7 @@ class Minitest::Test
134
134
 
135
135
  def get_oci8_connection()
136
136
  OCI8.new($dbuser, $dbpass, $dbname)
137
- rescue OCIError
137
+ rescue OCIError
138
138
  raise if $!.code != 12516 && $!.code != 12520
139
139
  # sleep a few second and try again if
140
140
  # the error code is ORA-12516 or ORA-12520.