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.
- checksums.yaml +7 -0
- data/ChangeLog +427 -0
- data/NEWS +335 -42
- data/README.md +20 -9
- data/dist-files +9 -3
- data/docs/bind-array-to-in_cond.md +2 -2
- data/docs/conflicts-local-connections-and-processes.md +7 -4
- data/docs/hanging-after-inactivity.md +63 -0
- data/docs/install-binary-package.md +15 -11
- data/docs/install-full-client.md +18 -21
- data/docs/install-instant-client.md +45 -27
- data/docs/install-on-osx.md +31 -120
- data/docs/ldap-auth-and-function-interposition.md +123 -0
- data/docs/number-type-mapping.md +79 -0
- data/docs/platform-specific-issues.md +17 -50
- data/docs/report-installation-issue.md +3 -0
- data/docs/timeout-parameters.md +3 -0
- data/ext/oci8/apiwrap.c.tmpl +2 -5
- data/ext/oci8/apiwrap.rb +6 -1
- data/ext/oci8/apiwrap.yml +34 -22
- data/ext/oci8/attr.c +4 -2
- data/ext/oci8/bind.c +366 -6
- data/ext/oci8/connection_pool.c +3 -3
- data/ext/oci8/encoding.c +5 -5
- data/ext/oci8/env.c +8 -2
- data/ext/oci8/error.c +24 -16
- data/ext/oci8/extconf.rb +8 -4
- data/ext/oci8/hook_funcs.c +274 -61
- data/ext/oci8/lob.c +31 -75
- data/ext/oci8/metadata.c +2 -2
- data/ext/oci8/object.c +72 -27
- data/ext/oci8/oci8.c +45 -132
- data/ext/oci8/oci8.h +32 -88
- data/ext/oci8/oci8lib.c +178 -38
- data/ext/oci8/ocihandle.c +37 -37
- data/ext/oci8/ocinumber.c +23 -18
- data/ext/oci8/oraconf.rb +158 -339
- data/ext/oci8/oradate.c +19 -19
- data/ext/oci8/plthook.h +10 -0
- data/ext/oci8/plthook_elf.c +433 -268
- data/ext/oci8/plthook_osx.c +40 -9
- data/ext/oci8/plthook_win32.c +9 -0
- data/ext/oci8/stmt.c +52 -17
- data/ext/oci8/win32.c +4 -22
- data/lib/oci8/bindtype.rb +1 -15
- data/lib/oci8/check_load_error.rb +57 -10
- data/lib/oci8/cursor.rb +57 -25
- data/lib/oci8/metadata.rb +9 -1
- data/lib/oci8/object.rb +10 -0
- data/lib/oci8/oci8.rb +33 -28
- data/lib/oci8/oracle_version.rb +11 -1
- data/lib/oci8/properties.rb +22 -0
- data/lib/oci8/version.rb +1 -1
- data/lib/oci8.rb +48 -4
- data/lib/ruby-oci8.rb +0 -3
- data/pre-distclean.rb +1 -3
- data/ruby-oci8.gemspec +3 -8
- data/setup.rb +11 -2
- data/test/README.md +37 -0
- data/test/config.rb +1 -1
- data/test/setup_test_object.sql +21 -13
- data/test/setup_test_package.sql +59 -0
- data/test/test_all.rb +2 -0
- data/test/test_bind_boolean.rb +99 -0
- data/test/test_bind_integer.rb +47 -0
- data/test/test_break.rb +11 -9
- data/test/test_clob.rb +4 -16
- data/test/test_connstr.rb +29 -13
- data/test/test_datetime.rb +8 -3
- data/test/test_object.rb +27 -9
- data/test/test_oci8.rb +170 -46
- data/test/test_oranumber.rb +12 -6
- data/test/test_package_type.rb +15 -3
- data/test/test_properties.rb +17 -0
- metadata +40 -54
- data/docs/osx-install-dev-tools.png +0 -0
- 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
|
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
|
-
|
121
|
-
|
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
|
127
|
+
attach_mode |= 0x0004 # OCI_STMT_CACHE
|
127
128
|
end
|
128
129
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
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
|
data/lib/oci8/oracle_version.rb
CHANGED
@@ -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 =
|
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+.
|
data/lib/oci8/properties.rb
CHANGED
@@ -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
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 '
|
16
|
-
win32setenv =
|
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
|
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
data/pre-distclean.rb
CHANGED
@@ -1,6 +1,4 @@
|
|
1
|
-
rm_f "#{curr_objdir}/
|
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.
|
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
|
-
|
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'
|
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,
|
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
|
-
|
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.
|
data/test/setup_test_object.sql
CHANGED
@@ -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
|
76
|
-
|
77
|
+
create type body rb_test_obj is
|
77
78
|
constructor function rb_test_obj(n number) return self as result is
|
78
|
-
|
79
|
-
|
80
|
-
|
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 :=
|
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
|
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
|