ruby-oci8 2.2.3 → 2.2.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. checksums.yaml +7 -0
  2. data/ChangeLog +427 -0
  3. data/NEWS +335 -42
  4. data/README.md +20 -9
  5. data/dist-files +9 -3
  6. data/docs/bind-array-to-in_cond.md +2 -2
  7. data/docs/conflicts-local-connections-and-processes.md +7 -4
  8. data/docs/hanging-after-inactivity.md +63 -0
  9. data/docs/install-binary-package.md +15 -11
  10. data/docs/install-full-client.md +18 -21
  11. data/docs/install-instant-client.md +45 -27
  12. data/docs/install-on-osx.md +31 -120
  13. data/docs/ldap-auth-and-function-interposition.md +123 -0
  14. data/docs/number-type-mapping.md +79 -0
  15. data/docs/platform-specific-issues.md +17 -50
  16. data/docs/report-installation-issue.md +3 -0
  17. data/docs/timeout-parameters.md +3 -0
  18. data/ext/oci8/apiwrap.c.tmpl +2 -5
  19. data/ext/oci8/apiwrap.rb +6 -1
  20. data/ext/oci8/apiwrap.yml +34 -22
  21. data/ext/oci8/attr.c +4 -2
  22. data/ext/oci8/bind.c +366 -6
  23. data/ext/oci8/connection_pool.c +3 -3
  24. data/ext/oci8/encoding.c +5 -5
  25. data/ext/oci8/env.c +8 -2
  26. data/ext/oci8/error.c +24 -16
  27. data/ext/oci8/extconf.rb +8 -4
  28. data/ext/oci8/hook_funcs.c +274 -61
  29. data/ext/oci8/lob.c +31 -75
  30. data/ext/oci8/metadata.c +2 -2
  31. data/ext/oci8/object.c +72 -27
  32. data/ext/oci8/oci8.c +45 -132
  33. data/ext/oci8/oci8.h +32 -88
  34. data/ext/oci8/oci8lib.c +178 -38
  35. data/ext/oci8/ocihandle.c +37 -37
  36. data/ext/oci8/ocinumber.c +23 -18
  37. data/ext/oci8/oraconf.rb +158 -339
  38. data/ext/oci8/oradate.c +19 -19
  39. data/ext/oci8/plthook.h +10 -0
  40. data/ext/oci8/plthook_elf.c +433 -268
  41. data/ext/oci8/plthook_osx.c +40 -9
  42. data/ext/oci8/plthook_win32.c +9 -0
  43. data/ext/oci8/stmt.c +52 -17
  44. data/ext/oci8/win32.c +4 -22
  45. data/lib/oci8/bindtype.rb +1 -15
  46. data/lib/oci8/check_load_error.rb +57 -10
  47. data/lib/oci8/cursor.rb +57 -25
  48. data/lib/oci8/metadata.rb +9 -1
  49. data/lib/oci8/object.rb +10 -0
  50. data/lib/oci8/oci8.rb +33 -28
  51. data/lib/oci8/oracle_version.rb +11 -1
  52. data/lib/oci8/properties.rb +22 -0
  53. data/lib/oci8/version.rb +1 -1
  54. data/lib/oci8.rb +48 -4
  55. data/lib/ruby-oci8.rb +0 -3
  56. data/pre-distclean.rb +1 -3
  57. data/ruby-oci8.gemspec +3 -8
  58. data/setup.rb +11 -2
  59. data/test/README.md +37 -0
  60. data/test/config.rb +1 -1
  61. data/test/setup_test_object.sql +21 -13
  62. data/test/setup_test_package.sql +59 -0
  63. data/test/test_all.rb +2 -0
  64. data/test/test_bind_boolean.rb +99 -0
  65. data/test/test_bind_integer.rb +47 -0
  66. data/test/test_break.rb +11 -9
  67. data/test/test_clob.rb +4 -16
  68. data/test/test_connstr.rb +29 -13
  69. data/test/test_datetime.rb +8 -3
  70. data/test/test_object.rb +27 -9
  71. data/test/test_oci8.rb +170 -46
  72. data/test/test_oranumber.rb +12 -6
  73. data/test/test_package_type.rb +15 -3
  74. data/test/test_properties.rb +17 -0
  75. metadata +40 -54
  76. data/docs/osx-install-dev-tools.png +0 -0
  77. data/test/README +0 -42
data/lib/oci8/oci8.rb CHANGED
@@ -113,42 +113,38 @@ class OCI8
113
113
  if dbname.is_a? OCI8::ConnectionPool
114
114
  @pool = dbname # to prevent GC from freeing the connection pool.
115
115
  dbname = dbname.send(:pool_name)
116
- attach_mode |= 0x0200 # OCI_CPOOL and OCI_LOGON2_CPOOL
116
+ attach_mode |= 0x0200 # OCI_CPOOL
117
117
  else
118
118
  tcp_connect_timeout = OCI8::properties[:tcp_connect_timeout]
119
119
  connect_timeout = OCI8::properties[:connect_timeout]
120
- if tcp_connect_timeout || connect_timeout
121
- dbname = to_connect_descriptor(dbname, tcp_connect_timeout, connect_timeout)
120
+ tcp_keepalive = OCI8::properties[:tcp_keepalive]
121
+ if tcp_connect_timeout || connect_timeout || tcp_keepalive
122
+ dbname = to_connect_descriptor(dbname, tcp_connect_timeout, connect_timeout, tcp_keepalive)
122
123
  end
123
124
  end
124
125
  if stmt_cache_size
125
126
  # enable statement caching
126
- attach_mode |= 0x0004 # OCI_STMT_CACHE and OCI_LOGON2_STMTCACHE
127
+ attach_mode |= 0x0004 # OCI_STMT_CACHE
127
128
  end
128
129
 
129
- if true
130
- # logon by the OCI function OCISessionBegin().
131
- allocate_handles()
132
- @session_handle.send(:attr_set_string, OCI_ATTR_USERNAME, username) if username
133
- @session_handle.send(:attr_set_string, OCI_ATTR_PASSWORD, password) if password
134
- if @@oracle_client_version >= ORAVER_11_1
135
- # Sets the driver name displayed in V$SESSION_CONNECT_INFO.CLIENT_DRIVER
136
- # if both the client and the server are Oracle 11g or upper.
137
- # Only the first 8 chracters "ruby-oci" are displayed when the Oracle
138
- # server version is lower than 12.0.1.2.
139
- # 424: OCI_ATTR_DRIVER_NAME
140
- @session_handle.send(:attr_set_string, 424, "ruby-oci8 : #{OCI8::VERSION}")
141
- end
142
- server_attach(dbname, attach_mode)
143
- if OCI8.oracle_client_version >= OCI8::ORAVER_11_1
144
- self.send_timeout = OCI8::properties[:send_timeout] if OCI8::properties[:send_timeout]
145
- self.recv_timeout = OCI8::properties[:recv_timeout] if OCI8::properties[:recv_timeout]
146
- end
147
- session_begin(cred ? cred : OCI_CRED_RDBMS, auth_mode)
148
- else
149
- # logon by the OCI function OCILogon2().
150
- logon2(username, password, dbname, attach_mode)
130
+ # logon by the OCI function OCISessionBegin().
131
+ allocate_handles()
132
+ @session_handle.send(:attr_set_string, OCI_ATTR_USERNAME, username) if username
133
+ @session_handle.send(:attr_set_string, OCI_ATTR_PASSWORD, password) if password
134
+ if @@oracle_client_version >= ORAVER_11_1
135
+ # Sets the driver name displayed in V$SESSION_CONNECT_INFO.CLIENT_DRIVER
136
+ # if both the client and the server are Oracle 11g or upper.
137
+ # Only the first 8 chracters "ruby-oci" are displayed when the Oracle
138
+ # server version is lower than 12.0.1.2.
139
+ # 424: OCI_ATTR_DRIVER_NAME
140
+ @session_handle.send(:attr_set_string, 424, "ruby-oci8 : #{OCI8::VERSION}")
151
141
  end
142
+ server_attach(dbname, attach_mode)
143
+ if OCI8.oracle_client_version >= OCI8::ORAVER_11_1
144
+ self.send_timeout = OCI8::properties[:send_timeout] if OCI8::properties[:send_timeout]
145
+ self.recv_timeout = OCI8::properties[:recv_timeout] if OCI8::properties[:recv_timeout]
146
+ end
147
+ session_begin(cred ? cred : OCI_CRED_RDBMS, auth_mode)
152
148
 
153
149
  if stmt_cache_size
154
150
  # set statement cache size
@@ -173,7 +169,6 @@ class OCI8
173
169
  # @private
174
170
  def parse_internal(sql)
175
171
  cursor = OCI8::Cursor.new(self, sql)
176
- cursor.prefetch_rows = @prefetch_rows if @prefetch_rows
177
172
  cursor
178
173
  end
179
174
 
@@ -309,6 +304,7 @@ class OCI8
309
304
  # @return [Array] an array of first row.
310
305
  def select_one(sql, *bindvars)
311
306
  cursor = self.parse(sql)
307
+ cursor.prefetch_rows = 1
312
308
  begin
313
309
  cursor.exec(*bindvars)
314
310
  row = cursor.fetch
@@ -344,6 +340,12 @@ class OCI8
344
340
 
345
341
  # Returns the Oracle server version.
346
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
+ #
347
349
  # @see OCI8.oracle_client_version
348
350
  # @return [OCI8::OracleVersion]
349
351
  def oracle_server_version
@@ -558,7 +560,7 @@ class OCI8
558
560
  # and add TRANSPORT_CONNECT_TIMEOUT or CONNECT_TIMEOUT.
559
561
  #
560
562
  # @private
561
- def to_connect_descriptor(database, tcp_connect_timeout, connect_timeout)
563
+ def to_connect_descriptor(database, tcp_connect_timeout, connect_timeout, tcp_keepalive)
562
564
  if @@easy_connect_naming_regex =~ database && ($1 || $2 || $4 || $5 || $6 || $7)
563
565
  connect_data = []
564
566
  connect_data << "(SERVICE_NAME=#$5)"
@@ -573,6 +575,9 @@ class OCI8
573
575
  if connect_timeout
574
576
  desc << "(CONNECT_TIMEOUT=#{connect_timeout})"
575
577
  end
578
+ if tcp_keepalive
579
+ desc << "(ENABLE=BROKEN)"
580
+ end
576
581
  "(DESCRIPTION=#{desc.join})"
577
582
  else
578
583
  database
@@ -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+.
@@ -17,6 +17,8 @@ class OCI8
17
17
  :connect_timeout => nil,
18
18
  :send_timeout => nil,
19
19
  :recv_timeout => nil,
20
+ :tcp_keepalive => false,
21
+ :tcp_keepalive_time => nil,
20
22
  }
21
23
 
22
24
  # @private
@@ -62,6 +64,14 @@ class OCI8
62
64
  val = val.to_i
63
65
  raise ArgumentError, "The property value for :#{name} must be nil or a positive integer." if val <= 0
64
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)
65
75
  end
66
76
  super(name, val)
67
77
  end
@@ -165,6 +175,18 @@ class OCI8
165
175
  #
166
176
  # *Since:* 2.2.2
167
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
+ #
168
190
  # @return [a customized Hash]
169
191
  # @since 2.0.5
170
192
  #
data/lib/oci8/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  class OCI8
2
- VERSION = "2.2.3"
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 CHANGED
@@ -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'
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,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
@@ -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
@@ -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.
@@ -61,6 +61,8 @@ create type rb_test_obj as object (
61
61
  obj_array_val rb_test_obj_elem_array,
62
62
  obj_ary_of_ary_val rb_test_obj_elem_ary_of_ary,
63
63
  date_val date,
64
+ timestamp_val timestamp(9),
65
+ timestamp_tz_val timestamp(9) with time zone,
64
66
  -- date_array_val rb_test_date_array,
65
67
 
66
68
  constructor function rb_test_obj(n number) return self as result,
@@ -72,19 +74,23 @@ create type rb_test_obj as object (
72
74
  member procedure member_proc(n in integer)
73
75
  )
74
76
  /
75
- create or replace type body rb_test_obj is
76
-
77
+ create type body rb_test_obj is
77
78
  constructor function rb_test_obj(n number) return self as result is
78
- function to_test_date(n number) return date is
79
- begin
80
- return to_date(to_char(1990 + n, 'FM0000') ||
81
- to_char(mod(round(n) * 5, 12) + 1, 'FM00') ||
82
- to_char(mod(round(n) * 7, 27) + 1, 'FM00') ||
83
- to_char(mod(round(n) * 9, 24), 'FM00') ||
84
- to_char(mod(round(n) * 11, 60), 'FM00') ||
85
- to_char(mod(round(n) * 13, 60), 'FM00'), 'yyyymmddhh24miss');
86
- end;
79
+ str varchar(28);
80
+ ts timestamp(9);
81
+ ts_tz timestamp(9) with time zone;
87
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');
88
94
  self.int_val := n;
89
95
  self.flt_val := n;
90
96
  self.num_val := n;
@@ -96,7 +102,9 @@ create or replace type body rb_test_obj is
96
102
  self.nclob_val := to_clob(n);
97
103
  self.blob_val := to_blob(utl_raw.cast_to_raw(to_char(n)));
98
104
  self.obj_val := rb_test_obj_elem(n, n + 1);
99
- self.date_val := to_test_date(n);
105
+ self.date_val := ts;
106
+ self.timestamp_val := ts;
107
+ self.timestamp_tz_val := ts_tz;
100
108
  if self.int_val != 1 then
101
109
  self.int_array_val := rb_test_int_array(n, n + 1, n + 2);
102
110
  self.flt_array_val := rb_test_flt_array(n, n + 1, n + 2);
@@ -120,7 +128,7 @@ create or replace type body rb_test_obj is
120
128
 
121
129
  static function test_object_version return integer is
122
130
  begin
123
- return 3;
131
+ return 4;
124
132
  end;
125
133
 
126
134
  static function class_func(n number) return rb_test_obj is
@@ -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
@@ -9,6 +9,7 @@ require "#{srcdir}/test_bind_array.rb"
9
9
  require "#{srcdir}/test_bind_string"
10
10
  require "#{srcdir}/test_bind_time"
11
11
  require "#{srcdir}/test_bind_raw"
12
+ require "#{srcdir}/test_bind_integer"
12
13
  if $test_clob
13
14
  require "#{srcdir}/test_clob"
14
15
  end
@@ -25,6 +26,7 @@ require "#{srcdir}/test_oracle_version"
25
26
  require "#{srcdir}/test_error"
26
27
  require "#{srcdir}/test_connection_pool"
27
28
  require "#{srcdir}/test_object"
29
+ require "#{srcdir}/test_properties.rb"
28
30
 
29
31
  if OCI8.respond_to? :encoding
30
32
  require "#{srcdir}/test_encoding"
@@ -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