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
@@ -13,6 +13,12 @@ class OCI8
13
13
  :statement_cache_size => 0,
14
14
  :events_mode => ((OCI8.__get_prop(2) & 4) != 0), # 4 <- OCI_EVENTS in oci.h
15
15
  :cancel_read_at_exit => false,
16
+ :tcp_connect_timeout => nil,
17
+ :connect_timeout => nil,
18
+ :send_timeout => nil,
19
+ :recv_timeout => nil,
20
+ :tcp_keepalive => false,
21
+ :tcp_keepalive_time => nil,
16
22
  }
17
23
 
18
24
  # @private
@@ -53,6 +59,19 @@ class OCI8
53
59
  when :cancel_read_at_exit
54
60
  val = val ? true : false
55
61
  OCI8.__set_prop(3, val)
62
+ when :tcp_connect_timeout, :connect_timeout, :send_timeout, :recv_timeout
63
+ if !val.nil?
64
+ val = val.to_i
65
+ raise ArgumentError, "The property value for :#{name} must be nil or a positive integer." if val <= 0
66
+ end
67
+ when :tcp_keepalive
68
+ val = val ? true : false
69
+ when :tcp_keepalive_time
70
+ if !val.nil?
71
+ val = val.to_i
72
+ raise ArgumentError, "The property value for :#{name} must be nil or a positive integer." if val <= 0
73
+ end
74
+ OCI8.__set_prop(4, val)
56
75
  end
57
76
  super(name, val)
58
77
  end
@@ -132,6 +151,42 @@ class OCI8
132
151
  #
133
152
  # *Since:* 2.1.8
134
153
  #
154
+ # [:tcp_connect_timeout]
155
+ #
156
+ # See {file:docs/timeout-parameters.md}
157
+ #
158
+ # *Since:* 2.2.2
159
+ #
160
+ # [:connect_timeout]
161
+ #
162
+ # See {file:docs/timeout-parameters.md}
163
+ #
164
+ # *Since:* 2.2.2
165
+ #
166
+ # [:send_timeout]
167
+ #
168
+ # See {file:docs/timeout-parameters.md}
169
+ #
170
+ # *Since:* 2.2.2
171
+ #
172
+ # [:recv_timeout]
173
+ #
174
+ # See {file:docs/timeout-parameters.md}
175
+ #
176
+ # *Since:* 2.2.2
177
+ #
178
+ # [:tcp_keepalive]
179
+ #
180
+ # See {file:docs/hanging-after-inactivity.md}
181
+ #
182
+ # *Since:* 2.2.4
183
+ #
184
+ # [:tcp_keepalive_time]
185
+ #
186
+ # See {file:docs/hanging-after-inactivity.md}
187
+ #
188
+ # *Since:* 2.2.4
189
+ #
135
190
  # @return [a customized Hash]
136
191
  # @since 2.0.5
137
192
  #
data/lib/oci8/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  class OCI8
2
- VERSION = "2.2.0.2"
2
+ VERSION = "2.2.12"
3
3
  end
data/lib/oci8.rb CHANGED
@@ -1,4 +1,3 @@
1
-
2
1
  # --*- ruby -*--
3
2
  # This is based on yoshidam's oracle.rb.
4
3
  #
@@ -12,8 +11,11 @@ if RUBY_PLATFORM =~ /cygwin/
12
11
  # Cygwin manages environment variables by itself.
13
12
  # They don't synchroize with Win32's ones.
14
13
  # This set some Oracle's environment variables to win32's enviroment.
15
- require 'Win32API'
16
- 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
+
17
19
  ['NLS_LANG', 'TNS_ADMIN', 'LOCAL'].each do |name|
18
20
  val = ENV[name]
19
21
  win32setenv.call(name, val && val.dup)
@@ -64,16 +66,56 @@ when 'rbx'
64
66
  so_basename += 'rbx'
65
67
  when 'jruby'
66
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'
67
71
  else
68
72
  raise 'unsupported ruby engine: ' + RUBY_ENGINE
69
73
  end
70
74
 
75
+ dll_dir = nil
76
+ begin
77
+ require 'ruby_installer/runtime' # RubyInstaller2 for Windows
78
+
79
+ dll_arch = proc do |file|
80
+ begin
81
+ File.open(file, 'rb') do |f|
82
+ if f.read(2) == 'MZ' # IMAGE_DOS_HEADER.e_magic
83
+ f.seek(60, IO::SEEK_SET)
84
+ pe_offset = f.read(4).unpack('V')[0] # IMAGE_DOS_HEADER.e_lfanew
85
+ f.seek(pe_offset)
86
+ if f.read(4) == "PE\000\000" # IMAGE_NT_HEADERS.Signature
87
+ case f.read(2).unpack('v')[0] # IMAGE_FILE_HEADER.Machine
88
+ when 0x014c # IMAGE_FILE_MACHINE_I386
89
+ :x86
90
+ when 0x8664 # IMAGE_FILE_MACHINE_AMD64
91
+ :x64
92
+ end
93
+ end
94
+ end
95
+ end
96
+ rescue
97
+ nil
98
+ end
99
+ end
100
+
101
+ ruby_arch = [nil].pack('P').size == 8 ? :x64 : :x86
102
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
103
+ if !path.empty? && dll_arch.call(File.join(path, 'OCI.DLL')) == ruby_arch
104
+ dll_dir = RubyInstaller::Runtime.add_dll_directory(path)
105
+ break
106
+ end
107
+ end
108
+ rescue LoadError
109
+ end
110
+
71
111
  begin
72
112
  require so_basename
73
- rescue LoadError, OCIError
113
+ rescue LoadError
74
114
  require 'oci8/check_load_error'
75
115
  OCI8::Util::check_load_error($!)
76
116
  raise
117
+ ensure
118
+ dll_dir.remove if dll_dir
77
119
  end
78
120
 
79
121
  require 'oci8/version.rb'
@@ -103,6 +145,8 @@ class OCI8
103
145
  ORAVER_11_1 = OCI8::OracleVersion.new(11, 1)
104
146
  # @private
105
147
  ORAVER_12_1 = OCI8::OracleVersion.new(12, 1)
148
+ # @private
149
+ ORAVER_18 = OCI8::OracleVersion.new(18)
106
150
 
107
151
  # @private
108
152
  @@oracle_client_version = OCI8::OracleVersion.new(self.oracle_client_vernum)
data/lib/ruby-oci8.rb ADDED
@@ -0,0 +1 @@
1
+ require 'oci8'
data/pre-distclean.rb CHANGED
@@ -1,6 +1,4 @@
1
- rm_f "#{curr_objdir}/lib/oci8.rb"
2
- rm_f "#{curr_objdir}/ext/oci8/oci8lib_18.map"
3
- rm_f "#{curr_objdir}/ext/oci8/oci8lib_191.map"
1
+ rm_f "#{curr_objdir}/ext/oci8/oci8lib_*.map"
4
2
  if RUBY_PLATFORM =~ /cygwin/
5
3
  rm_f "#{curr_objdir}/ext/oci8/OCI.def"
6
4
  rm_f "#{curr_objdir}/ext/oci8/libOCI.a"
data/ruby-oci8.gemspec CHANGED
@@ -34,10 +34,9 @@ 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
- s.license = '2-clause BSD-style license'
39
+ s.license = 'BSD-2-Clause'
41
40
  files = File.read('dist-files').split("\n")
42
41
  if gem_platform == Gem::Platform::RUBY
43
42
  s.extensions << 'ext/oci8/extconf.rb'
@@ -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
@@ -64,11 +63,7 @@ EOS
64
63
  raise "No compiled binary are found. Run make in advance."
65
64
  when 1
66
65
  puts "Binary gem for ruby #{so_vers.first}"
67
- if so_vers[0] < '2.0.0'
68
- s.required_ruby_version = "~> #{so_vermin}"
69
- else
70
- s.required_ruby_version = "~> #{so_vermin}.0"
71
- end
66
+ s.required_ruby_version = "~> #{so_vermin}"
72
67
  else
73
68
  puts "Binary gem for ruby #{so_vers.join(', ')}"
74
69
  s.required_ruby_version = ">= #{so_vermin}"
@@ -83,7 +78,7 @@ EOS
83
78
  end
84
79
  files << 'lib/oci8.rb'
85
80
  end
86
- s.require_paths = ['lib', 'ext/oci8']
81
+ s.require_paths = ['lib']
87
82
  s.files = files
88
83
  s.test_files = 'test/test_all.rb'
89
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
@@ -125,9 +125,16 @@ end
125
125
 
126
126
  class Minitest::Test
127
127
 
128
+ # @!visibility private
129
+ # dirty hack to suppress "warning: constant ::Fixnum is deprecated"
130
+ Fixnum = (0.class == ::Integer) ? ::Integer : ::Fixnum
131
+ # @!visibility private
132
+ # dirty hack to suppress "warning: constant ::Bignum is deprecated"
133
+ Bignum = (0.class == ::Integer) ? ::Integer : ::Bignum
134
+
128
135
  def get_oci8_connection()
129
136
  OCI8.new($dbuser, $dbpass, $dbname)
130
- rescue OCIError
137
+ rescue OCIError
131
138
  raise if $!.code != 12516 && $!.code != 12520
132
139
  # sleep a few second and try again if
133
140
  # the error code is ORA-12516 or ORA-12520.
@@ -10,6 +10,10 @@ drop type rb_test_obj_elem_array
10
10
  /
11
11
  drop type rb_test_obj_elem
12
12
  /
13
+ drop type rb_test_obj_sub
14
+ /
15
+ drop type rb_test_obj_base
16
+ /
13
17
  create type rb_test_obj_elem as object (
14
18
  x integer,
15
19
  y integer
@@ -57,6 +61,8 @@ create type rb_test_obj as object (
57
61
  obj_array_val rb_test_obj_elem_array,
58
62
  obj_ary_of_ary_val rb_test_obj_elem_ary_of_ary,
59
63
  date_val date,
64
+ timestamp_val timestamp(9),
65
+ timestamp_tz_val timestamp(9) with time zone,
60
66
  -- date_array_val rb_test_date_array,
61
67
 
62
68
  constructor function rb_test_obj(n number) return self as result,
@@ -68,19 +74,23 @@ create type rb_test_obj as object (
68
74
  member procedure member_proc(n in integer)
69
75
  )
70
76
  /
71
- create or replace type body rb_test_obj is
72
-
77
+ create type body rb_test_obj is
73
78
  constructor function rb_test_obj(n number) return self as result is
74
- function to_test_date(n number) return date is
75
- begin
76
- return to_date(to_char(1990 + n, 'FM0000') ||
77
- to_char(mod(round(n) * 5, 12) + 1, 'FM00') ||
78
- to_char(mod(round(n) * 7, 27) + 1, 'FM00') ||
79
- to_char(mod(round(n) * 9, 24), 'FM00') ||
80
- to_char(mod(round(n) * 11, 60), 'FM00') ||
81
- to_char(mod(round(n) * 13, 60), 'FM00'), 'yyyymmddhh24miss');
82
- end;
79
+ str varchar(28);
80
+ ts timestamp(9);
81
+ ts_tz timestamp(9) with time zone;
83
82
  begin
83
+ str := to_char(1990 + n, 'FM0000') ||
84
+ to_char(mod(round(n) * 5, 12) + 1, 'FM00') ||
85
+ to_char(mod(round(n) * 7, 27) + 1, 'FM00') ||
86
+ to_char(mod(round(n) * 9, 24), 'FM00') ||
87
+ to_char(mod(round(n) * 11, 60), 'FM00') ||
88
+ to_char(mod(round(n) * 13, 60), 'FM00') ||
89
+ to_char(mod(round(n) * 333333333, 1000000000), 'FM000000000');
90
+ ts := to_timestamp(str, 'yyyymmddhh24missff9');
91
+ str := str || to_char(mod(round(n) * 15, 24) - 11, 'FMS00') ||
92
+ to_char(mod(round(n) * 17, 60), 'FM00');
93
+ ts_tz := to_timestamp_tz(str, 'yyyymmddhh24missff9tzhtzm');
84
94
  self.int_val := n;
85
95
  self.flt_val := n;
86
96
  self.num_val := n;
@@ -92,7 +102,9 @@ create or replace type body rb_test_obj is
92
102
  self.nclob_val := to_clob(n);
93
103
  self.blob_val := to_blob(utl_raw.cast_to_raw(to_char(n)));
94
104
  self.obj_val := rb_test_obj_elem(n, n + 1);
95
- self.date_val := to_test_date(n);
105
+ self.date_val := ts;
106
+ self.timestamp_val := ts;
107
+ self.timestamp_tz_val := ts_tz;
96
108
  if self.int_val != 1 then
97
109
  self.int_array_val := rb_test_int_array(n, n + 1, n + 2);
98
110
  self.flt_array_val := rb_test_flt_array(n, n + 1, n + 2);
@@ -116,7 +128,7 @@ create or replace type body rb_test_obj is
116
128
 
117
129
  static function test_object_version return integer is
118
130
  begin
119
- return 2;
131
+ return 4;
120
132
  end;
121
133
 
122
134
  static function class_func(n number) return rb_test_obj is
@@ -167,5 +179,21 @@ begin
167
179
  end loop;
168
180
  end;
169
181
  /
170
- commit
182
+
183
+ create type rb_test_obj_base as object (
184
+ id varchar2(30)
185
+ ) not final
186
+ /
187
+ create type rb_test_obj_sub under rb_test_obj_base (
188
+ subid varchar2(30)
189
+ ) final
190
+ /
191
+ create or replace function rb_test_obj_get_object(get_base integer) return rb_test_obj_base is
192
+ begin
193
+ if get_base = 0 then
194
+ return rb_test_obj_base('base');
195
+ else
196
+ return rb_test_obj_sub('sub', 'subid');
197
+ end if;
198
+ end;
171
199
  /
@@ -0,0 +1,59 @@
1
+ create or replace package rb_test_pkg is
2
+ package_version pls_integer := 1;
3
+
4
+ type array_of_integer is array(50) of integer;
5
+ type table_of_pls_integer is table of pls_integer;
6
+ type table_of_boolean is table of boolean;
7
+ type indexed_table_of_varchar2 is table of varchar2(10) index by varchar2(5);
8
+ type rec1 is record (i pls_integer, j integer);
9
+ type rec2 is record (b boolean, it indexed_table_of_varchar2, rec rec1);
10
+ type table_of_rec1 is table of rec1;
11
+ type table_of_rec2 is table of rec2;
12
+
13
+ function sum_table_of_pls_integer(tbl in table_of_pls_integer) return pls_integer;
14
+ function add_rec1_values(tbl in table_of_rec1) return pls_integer;
15
+ procedure out_rec1_values(tbl out table_of_rec1);
16
+ end;
17
+ /
18
+ create or replace package body rb_test_pkg is
19
+ function sum_table_of_pls_integer(tbl in table_of_pls_integer) return pls_integer is
20
+ i pls_integer;
21
+ ret pls_integer := 0;
22
+ begin
23
+ for i in tbl.first..tbl.last loop
24
+ ret := ret + tbl(i);
25
+ end loop;
26
+ return ret;
27
+ end;
28
+
29
+ function add_rec1_values(tbl in table_of_rec1) return pls_integer is
30
+ i pls_integer;
31
+ ret pls_integer := 0;
32
+ begin
33
+ for i in tbl.first..tbl.last loop
34
+ ret := ret + nvl(tbl(i).i, 0) + nvl(tbl(i).j, 0);
35
+ end loop;
36
+ return ret;
37
+ end;
38
+
39
+ procedure out_rec1_values(tbl out table_of_rec1) is
40
+ i pls_integer;
41
+ rec1val rec1;
42
+ begin
43
+ tbl := table_of_rec1();
44
+ for i in 1..20 loop
45
+ tbl.extend;
46
+ if i mod 6 != 0 then
47
+ if i mod 3 != 0 then
48
+ rec1val.i := i;
49
+ rec1val.j := i;
50
+ else
51
+ rec1val.i := null;
52
+ rec1val.j := null;
53
+ end if;
54
+ tbl(i) := rec1val;
55
+ end if;
56
+ end loop;
57
+ end;
58
+ end;
59
+ /
data/test/test_all.rb CHANGED
@@ -5,9 +5,11 @@ require "#{srcdir}/config"
5
5
 
6
6
  require "#{srcdir}/test_oradate"
7
7
  require "#{srcdir}/test_oranumber"
8
+ require "#{srcdir}/test_bind_array.rb"
8
9
  require "#{srcdir}/test_bind_string"
9
10
  require "#{srcdir}/test_bind_time"
10
11
  require "#{srcdir}/test_bind_raw"
12
+ require "#{srcdir}/test_bind_integer"
11
13
  if $test_clob
12
14
  require "#{srcdir}/test_clob"
13
15
  end
@@ -24,6 +26,7 @@ require "#{srcdir}/test_oracle_version"
24
26
  require "#{srcdir}/test_error"
25
27
  require "#{srcdir}/test_connection_pool"
26
28
  require "#{srcdir}/test_object"
29
+ require "#{srcdir}/test_properties.rb"
27
30
 
28
31
  if OCI8.respond_to? :encoding
29
32
  require "#{srcdir}/test_encoding"
@@ -31,6 +34,7 @@ end
31
34
 
32
35
  if $oracle_version >= OCI8::ORAVER_12_1
33
36
  require "#{srcdir}/test_package_type"
37
+ require "#{srcdir}/test_bind_boolean.rb"
34
38
  end
35
39
 
36
40
  # Ruby/DBI
@@ -0,0 +1,70 @@
1
+ require 'oci8'
2
+ require File.dirname(__FILE__) + '/config'
3
+
4
+ class TestBindArray < Minitest::Test
5
+
6
+ def test_bind_array_names
7
+ assert_equal(":id_0", OCI8::in_cond(:id, []).names)
8
+ assert_equal(":id_0", OCI8::in_cond(:id, [1]).names)
9
+ assert_equal(":id_0, :id_1", OCI8::in_cond(:id, [1, 2]).names)
10
+ assert_equal(":id_0, :id_1, :id_2", OCI8::in_cond(:id, [1, 2, 3]).names)
11
+ end
12
+
13
+ def test_bind_array_values
14
+ assert_equal([[nil, String, nil]], OCI8::in_cond(:id, []).values)
15
+ assert_equal([[1, nil, nil]], OCI8::in_cond(:id, [1]).values)
16
+ assert_equal([[1, nil, nil], [2, nil, nil]], OCI8::in_cond(:id, [1, 2]).values)
17
+ assert_equal([[1, nil, nil], [2, nil, nil], [3, nil, nil]], OCI8::in_cond(:id, [1, 2, 3]).values)
18
+ end
19
+
20
+ def test_bind_array_values_containg_nil
21
+ assert_equal([[nil, String]], OCI8::in_cond(:id, [nil]).values)
22
+ assert_equal([[nil, Fixnum], [2, nil, nil], [3, nil, nil]], OCI8::in_cond(:id, [nil, 2, 3]).values)
23
+ assert_equal([[1, nil, nil], [nil, Fixnum], [3, nil, nil]], OCI8::in_cond(:id, [1, nil, 3]).values)
24
+ end
25
+
26
+ def test_bind_array_values_with_type
27
+ assert_equal([[nil, Integer, nil]], OCI8::in_cond(:id, [], Integer).values)
28
+ assert_equal([[1, Integer, nil]], OCI8::in_cond(:id, [1], Integer).values)
29
+ assert_equal([[1, Integer, nil], [2, Integer, nil]], OCI8::in_cond(:id, [1, 2], Integer).values)
30
+ assert_equal([[1, Integer, nil], [2, Integer, nil], [3, Integer, nil]], OCI8::in_cond(:id, [1, 2, 3], Integer).values)
31
+ assert_equal([[nil, Integer, nil], [2, Integer, nil], [3, Integer, nil]], OCI8::in_cond(:id, [nil, 2, 3], Integer).values)
32
+ assert_equal([[1, Integer, nil], [nil, Integer, nil], [3, Integer, nil]], OCI8::in_cond(:id, [1, nil, 3], Integer).values)
33
+ end
34
+
35
+ def test_select
36
+ @conn = get_oci8_connection
37
+ begin
38
+ drop_table('test_table')
39
+ @conn.exec(<<EOS)
40
+ CREATE TABLE test_table (ID NUMBER(38))
41
+ EOS
42
+ cursor = @conn.parse('insert into test_table values(:1)')
43
+ cursor.bind_param(1, nil, Integer)
44
+ [1, 3, 5].each do |id|
45
+ cursor.exec(id)
46
+ end
47
+ cursor.close
48
+
49
+ [
50
+ [],
51
+ [1],
52
+ [1, 2],
53
+ [1, 2, 3],
54
+ [nil],
55
+ [nil, 2, 3],
56
+ [1, nil, 3],
57
+ ].each do |ids|
58
+ in_cond = OCI8::in_cond(:id, ids)
59
+ cursor = @conn.exec("select * from test_table where id in (#{in_cond.names}) order by id", *in_cond.values)
60
+ ([1, 3, 5] & ids).each do |id|
61
+ assert_equal(id, cursor.fetch[0])
62
+ end
63
+ end
64
+
65
+ drop_table('test_table')
66
+ ensure
67
+ @conn.logoff
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,99 @@
1
+ # Low-level API
2
+ require 'oci8'
3
+ require File.dirname(__FILE__) + '/config'
4
+
5
+ class TestBindBoolean < Minitest::Test
6
+ def setup
7
+ @conn = get_oci8_connection()
8
+ end
9
+
10
+ def test_set_raw
11
+ stmt = <<EOS
12
+ DECLARE
13
+ bool_val boolean;
14
+ int_val pls_integer;
15
+ BEGIN
16
+ bool_val := :in;
17
+ IF bool_val THEN
18
+ int_val := 1;
19
+ ELSE
20
+ int_val := 0;
21
+ END IF;
22
+ :out := int_val;
23
+ END;
24
+ EOS
25
+ # explicit bind
26
+ cursor = @conn.parse(stmt)
27
+ cursor.bind_param(:in, nil, TrueClass)
28
+ cursor.bind_param(:out, nil, Integer)
29
+
30
+ cursor[:in] = true
31
+ cursor.exec
32
+ assert_equal(1, cursor[:out])
33
+
34
+ cursor[:in] = false
35
+ cursor.exec
36
+ assert_equal(0, cursor[:out])
37
+
38
+ # implicit bind
39
+ do_block_cnt = 0
40
+ @conn.exec(stmt, true, 0) do |in_val, out_val|
41
+ assert_equal(true, in_val)
42
+ assert_equal(1, out_val)
43
+ do_block_cnt += 1
44
+ end
45
+
46
+ @conn.exec(stmt, false, 0) do |in_val, out_val|
47
+ assert_equal(false, in_val)
48
+ assert_equal(0, out_val)
49
+ do_block_cnt += 1
50
+ end
51
+ assert_equal(2, do_block_cnt)
52
+ end
53
+
54
+ def test_get_raw
55
+ stmt = <<EOS
56
+ DECLARE
57
+ int_val pls_integer;
58
+ bool_val boolean;
59
+ BEGIN
60
+ int_val := :in;
61
+ IF int_val <> 0 THEN
62
+ bool_val := TRUE;
63
+ ELSE
64
+ bool_val := FALSE;
65
+ END IF;
66
+ :out := bool_val;
67
+ END;
68
+ EOS
69
+ cursor = @conn.parse(stmt)
70
+ cursor.bind_param(:in, nil, Integer)
71
+ cursor.bind_param(:out, nil, TrueClass)
72
+
73
+ cursor[:in] = 1
74
+ cursor.exec
75
+ assert_equal(true, cursor[:out])
76
+
77
+ cursor[:in] = 0
78
+ cursor.exec
79
+ assert_equal(false, cursor[:out])
80
+
81
+ do_block_cnt = 0
82
+ @conn.exec(stmt, 1, true) do |in_val, out_val|
83
+ assert_equal(1, in_val)
84
+ assert_equal(true, out_val)
85
+ do_block_cnt += 1
86
+ end
87
+
88
+ @conn.exec(stmt, 0, true) do |in_val, out_val|
89
+ assert_equal(0, in_val)
90
+ assert_equal(false, out_val)
91
+ do_block_cnt += 1
92
+ end
93
+ assert_equal(2, do_block_cnt)
94
+ end
95
+
96
+ def teardown
97
+ @conn.logoff
98
+ end
99
+ end