ruby-oci8 2.2.5.1-x86-mingw32 → 2.2.9-x86-mingw32

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -2,7 +2,7 @@ Ruby-oci8
2
2
  =========
3
3
 
4
4
  [![Gem Version](https://badge.fury.io/rb/ruby-oci8.svg)](http://badge.fury.io/rb/ruby-oci8)
5
- [![Circle CI](https://circleci.com/gh/kubo/ruby-oci8.png?style=shield)](https://circleci.com/gh/kubo/ruby-oci8)
5
+ [![Build Status](https://travis-ci.com/kubo/ruby-oci8.svg?branch=master)](https://travis-ci.com/kubo/ruby-oci8)
6
6
 
7
7
  What is ruby-oci8
8
8
  -----------------
data/dist-files CHANGED
@@ -80,7 +80,7 @@ lib/oci8/oracle_version.rb
80
80
  lib/oci8/properties.rb
81
81
  lib/oci8/version.rb
82
82
  lib/ruby-oci8.rb
83
- test/README
83
+ test/README.md
84
84
  test/config.rb
85
85
  test/setup_test_object.sql
86
86
  test/setup_test_package.sql
@@ -109,4 +109,5 @@ test/test_oracle_version.rb
109
109
  test/test_oradate.rb
110
110
  test/test_oranumber.rb
111
111
  test/test_package_type.rb
112
+ test/test_properties.rb
112
113
  test/test_rowid.rb
@@ -18,7 +18,7 @@ Look at {file:docs/install-on-osx.md} for OS X.
18
18
  Install Oracle Instant Client Packages
19
19
  --------------------------------------
20
20
 
21
- ### Donwload Instant Client Packages
21
+ ### Download Instant Client Packages
22
22
 
23
23
  Download the following packages from [Oracle Technology Network](http://www.oracle.com/technetwork/database/features/instant-client/index-097480.html).
24
24
 
@@ -110,6 +110,7 @@ Package" or copy a runtime library to the directory where `ruby.exe` resides.
110
110
 
111
111
  | Oracle Version | Package | Runtime Library|
112
112
  |---|---|---|
113
+ | 18.3 | [Microsoft Visual C++ 2013 Redistributable Package][2013] | MSVCR120.DLL |
113
114
  | 12.2.0.x | [Microsoft Visual C++ 2013 Redistributable Package][2013] | MSVCR120.DLL |
114
115
  | 12.1.0.x | [Microsoft Visual C++ 2010 Redistributable Package][2010] | MSVCR100.DLL |
115
116
  | 11.2.0.x | Microsoft Visual C++ 2005 SP1 Redistributable Package ([x86][2005SP1_x86], [x64][2005SP1_x64]) | MSVCR80.DLL(The file version must be 8.0.50727.762.) |
@@ -39,7 +39,7 @@ Download the following packages from [Oracle Technology Network][]
39
39
 
40
40
  * Instant Client Package - Basic (`instantclient-basic-macos.x64-12.1.0.2.0.zip`) or Basic Lite (`instantclient-basiclite-macos.x64-12.1.0.2.0.zip`)
41
41
  * Instant Client Package - SDK (`instantclient-sdk-macos.x64-12.1.0.2.0.zip`)
42
- * Instant Client Package - SQL*Plus (`instantclient-sdk-macos.x64-12.1.0.2.0.zip`) (optionally)
42
+ * Instant Client Package - SQL*Plus (`instantclient-sqlplus-macos.x64-12.1.0.2.0.zip`) (optionally)
43
43
 
44
44
  ### Install Oracle Instant Client Packages via Homebrew
45
45
 
@@ -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
@@ -140,6 +145,8 @@ class OCI8
140
145
  ORAVER_11_1 = OCI8::OracleVersion.new(11, 1)
141
146
  # @private
142
147
  ORAVER_12_1 = OCI8::OracleVersion.new(12, 1)
148
+ # @private
149
+ ORAVER_18 = OCI8::OracleVersion.new(18)
143
150
 
144
151
  # @private
145
152
  @@oracle_client_version = OCI8::OracleVersion.new(self.oracle_client_vernum)
@@ -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)
@@ -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
@@ -1503,7 +1503,11 @@ class OCI8
1503
1503
  attr_get_sb1(OCI_ATTR_SCALE)
1504
1504
  end
1505
1505
 
1506
- # The datatype levels. This attribute always returns zero.
1506
+ # The nest level.
1507
+ #
1508
+ # Oracle manual says that it always returns zero. However it returns
1509
+ # the depth of {OCI8::ArgBase#arguments} calls when #arguments returns
1510
+ # a non-empty array.
1507
1511
  def level
1508
1512
  attr_get_ub2(OCI_ATTR_LEVEL)
1509
1513
  end
@@ -1607,6 +1611,10 @@ class OCI8
1607
1611
 
1608
1612
  # The list of arguments at the next level (when the argument is
1609
1613
  # of a record or table type).
1614
+ #
1615
+ # This method returns an array containing type information when
1616
+ # the type is a user-defined type and the Oracle server version
1617
+ # is 12c or earlier. Otherwise, it returns an empty array.
1610
1618
  def arguments
1611
1619
  @arguments ||= list_arguments.to_a
1612
1620
  end
@@ -493,6 +493,16 @@ EOS
493
493
  Proc.new do |val| datetime_to_array(val, :date) end, # set_proc
494
494
  Proc.new do |val| array_to_time(val, :local) end, # get_proc
495
495
  ]
496
+ when :timestamp
497
+ [ATTR_TIMESTAMP, con, SIZE_OF_POINTER, 2, ALIGNMENT_OF_POINTER,
498
+ Proc.new do |val| datetime_to_array(val, :timestamp) end, # set_proc
499
+ Proc.new do |val| array_to_time(val, :local) end, # get_proc
500
+ ]
501
+ when :timestamp_tz
502
+ [ATTR_TIMESTAMP_TZ, con, SIZE_OF_POINTER, 2, ALIGNMENT_OF_POINTER,
503
+ Proc.new do |val| datetime_to_array(val, :timestamp_tz) end, # set_proc
504
+ Proc.new do |val| array_to_time(val, nil) end, # get_proc
505
+ ]
496
506
  when :binary_double
497
507
  [ATTR_BINARY_DOUBLE, nil, SIZE_OF_DOUBLE, 2, ALIGNMENT_OF_DOUBLE]
498
508
  when :binary_float
@@ -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
@@ -340,6 +340,12 @@ class OCI8
340
340
 
341
341
  # Returns the Oracle server version.
342
342
  #
343
+ # When the Oracle client version is 12c or earlier and
344
+ # the Oracle server version is 18c or later, this method
345
+ # doesn't return *full* version number such as '18.3.0.0.0'.
346
+ # It returns version number whose number components after
347
+ # the first dot are zeros such as '18.0.0.0.0'.
348
+ #
343
349
  # @see OCI8.oracle_client_version
344
350
  # @return [OCI8::OracleVersion]
345
351
  def oracle_server_version
@@ -66,6 +66,12 @@ class OCI8
66
66
  major, minor, update, patch, port_update = arg.split('.').collect do |v|
67
67
  v.to_i
68
68
  end
69
+ elsif arg >= 0x12000000
70
+ major = (arg & 0xFF000000) >> 24
71
+ minor = (arg & 0x00FF0000) >> 16
72
+ update = (arg & 0x0000F000) >> 12
73
+ patch = (arg & 0x00000FF0) >> 4
74
+ port_update = (arg & 0x0000000F)
69
75
  elsif arg >= 0x08000000
70
76
  major = (arg & 0xFF000000) >> 24
71
77
  minor = (arg & 0x00F00000) >> 20
@@ -80,7 +86,11 @@ class OCI8
80
86
  @update = update || 0
81
87
  @patch = patch || 0
82
88
  @port_update = port_update || 0
83
- @vernum = (@major << 24) | (@minor << 20) | (@update << 12) | (@patch << 8) | @port_update
89
+ @vernum = if @major >= 18
90
+ (@major << 24) | (@minor << 16) | (@update << 12) | (@patch << 4) | @port_update
91
+ else
92
+ (@major << 24) | (@minor << 20) | (@update << 12) | (@patch << 8) | @port_update
93
+ end
84
94
  end
85
95
 
86
96
  # Compares +self+ and +other+.
@@ -1,3 +1,3 @@
1
1
  class OCI8
2
- VERSION = "2.2.5.1"
2
+ VERSION = "2.2.9"
3
3
  end
Binary file
Binary file
Binary file
Binary file
@@ -1,4 +1 @@
1
- if caller[0] !~ /\/bundler\/runtime\.rb:\d+:in `require'/
2
- warn "Don't require 'ruby-oci8'. Use \"require 'oci8'\" instead. 'ruby-oci8.rb' was added only for 'Bundler.require'."
3
- end
4
1
  require 'oci8'