ruby-oci8 2.2.3 → 2.2.12
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'oci8'
|
2
|
+
require File.dirname(__FILE__) + '/config'
|
3
|
+
|
4
|
+
class TestBindInteger < Minitest::Test
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@conn = get_oci8_connection
|
8
|
+
end
|
9
|
+
|
10
|
+
POSITIVE_INTS = [
|
11
|
+
100,
|
12
|
+
2**30,
|
13
|
+
2**31,
|
14
|
+
2**32,
|
15
|
+
2**33,
|
16
|
+
2**62,
|
17
|
+
2**63,
|
18
|
+
2**64,
|
19
|
+
('9' * 38).to_i
|
20
|
+
]
|
21
|
+
|
22
|
+
def bind_and_get(input_value, output_type)
|
23
|
+
cursor = @conn.parse("BEGIN :out := :in; END;")
|
24
|
+
cursor.bind_param(:out, output_type)
|
25
|
+
cursor.bind_param(:in, input_value)
|
26
|
+
cursor.exec
|
27
|
+
result = cursor[:out]
|
28
|
+
cursor.close
|
29
|
+
result
|
30
|
+
end
|
31
|
+
|
32
|
+
(POSITIVE_INTS + [0] + POSITIVE_INTS.map(&:-@)).each do |num|
|
33
|
+
define_method("test_bind_param_with_input_of '#{num}'") do
|
34
|
+
assert_equal(OraNumber.new(num.to_s), bind_and_get(num, OraNumber))
|
35
|
+
end
|
36
|
+
|
37
|
+
define_method("test_bind_param_with_output_of '#{num}'") do
|
38
|
+
result = bind_and_get(OraNumber.new(num.to_s), Integer)
|
39
|
+
assert_equal(num, result)
|
40
|
+
assert_kind_of(Integer, result)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def teardown
|
45
|
+
@conn.logoff
|
46
|
+
end
|
47
|
+
end
|
data/test/test_break.rb
CHANGED
@@ -7,10 +7,12 @@ class TestBreak < Minitest::Test
|
|
7
7
|
|
8
8
|
def setup
|
9
9
|
@conn = get_oci8_connection
|
10
|
+
Thread.report_on_exception, @original_report_on_exception = false, Thread.report_on_exception if Thread.respond_to?(:report_on_exception)
|
10
11
|
end
|
11
12
|
|
12
13
|
def teardown
|
13
14
|
@conn.logoff
|
15
|
+
Thread.report_on_exception = @original_report_on_exception if Thread.respond_to?(:report_on_exception)
|
14
16
|
end
|
15
17
|
|
16
18
|
def report(str)
|
@@ -20,9 +22,8 @@ class TestBreak < Minitest::Test
|
|
20
22
|
@@server_is_runing_on_windows = nil
|
21
23
|
def server_is_runing_on_windows?
|
22
24
|
if @@server_is_runing_on_windows.nil?
|
23
|
-
|
24
|
-
|
25
|
-
@@server_is_runing_on_windows = true if row[0].include? 'Windows'
|
25
|
+
@conn.exec('select dbms_utility.port_string from dual') do |row|
|
26
|
+
@@server_is_runing_on_windows = row[0].include? '/WIN'
|
26
27
|
end
|
27
28
|
end
|
28
29
|
@@server_is_runing_on_windows
|
@@ -61,7 +62,7 @@ class TestBreak < Minitest::Test
|
|
61
62
|
expect = []
|
62
63
|
expect[PLSQL_DONE] = TIME_IN_PLSQL
|
63
64
|
expect[OCIBREAK] = "Invalid status"
|
64
|
-
if defined? Rubinius and Rubinius::VERSION >= "2.0"
|
65
|
+
if (defined? Rubinius and Rubinius::VERSION >= "2.0") || (defined? RUBY_ENGINE and RUBY_ENGINE == "truffleruby")
|
65
66
|
# Rubinius 2.0.0.
|
66
67
|
# DBMS_LOCK.SLEEP blocks ruby threads which try to call C-API.
|
67
68
|
expect[SEND_BREAK] = TIME_TO_BREAK
|
@@ -98,6 +99,11 @@ class TestBreak < Minitest::Test
|
|
98
99
|
def test_timeout
|
99
100
|
@conn.non_blocking = true
|
100
101
|
start_time = Time.now
|
102
|
+
if server_is_runing_on_windows?
|
103
|
+
end_time = start_time + 5
|
104
|
+
else
|
105
|
+
end_time = start_time + 1
|
106
|
+
end
|
101
107
|
|
102
108
|
if defined? Rubinius and Rubinius::VERSION < "2.0"
|
103
109
|
# Rubinius 1.2.4
|
@@ -111,12 +117,8 @@ class TestBreak < Minitest::Test
|
|
111
117
|
@conn.exec("BEGIN DBMS_LOCK.SLEEP(5); END;")
|
112
118
|
end
|
113
119
|
end
|
114
|
-
if server_is_runing_on_windows?
|
115
|
-
end_time = start_time + 5
|
116
|
-
else
|
117
|
-
end_time = start_time + 1
|
118
|
-
end
|
119
120
|
assert_in_delta(Time.now, end_time, 1)
|
121
|
+
sleep(0.01) # for truffleruby. Is truffleruby too fast?
|
120
122
|
@conn.exec("BEGIN NULL; END;")
|
121
123
|
assert_in_delta(Time.now, end_time, 1)
|
122
124
|
end
|
data/test/test_clob.rb
CHANGED
@@ -24,22 +24,6 @@ class TestCLob < Minitest::Test
|
|
24
24
|
lob.close
|
25
25
|
end
|
26
26
|
|
27
|
-
def test_insert_with_flush
|
28
|
-
filename = File.basename($lobfile)
|
29
|
-
@conn.exec("DELETE FROM test_table WHERE filename = :1", filename)
|
30
|
-
@conn.exec("INSERT INTO test_table(filename, content) VALUES (:1, EMPTY_CLOB())", filename)
|
31
|
-
cursor = @conn.exec("SELECT content FROM test_table WHERE filename = :1 FOR UPDATE", filename)
|
32
|
-
lob = cursor.fetch[0]
|
33
|
-
lob.sync = false
|
34
|
-
open($lobfile) do |f|
|
35
|
-
while s = f.read(1000)
|
36
|
-
lob.write(s)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
lob.flush
|
40
|
-
lob.close
|
41
|
-
end
|
42
|
-
|
43
27
|
def test_insert_symbol
|
44
28
|
filename = 'test_symbol'
|
45
29
|
value = :foo_bar
|
@@ -76,7 +60,11 @@ class TestCLob < Minitest::Test
|
|
76
60
|
|
77
61
|
# https://github.com/kubo/ruby-oci8/issues/20
|
78
62
|
def test_github_issue_20
|
63
|
+
# Skip this test if FULLTEST isn't set because it takes 4 minutes in my Linux box.
|
64
|
+
return if ENV['FULLTEST']
|
65
|
+
|
79
66
|
lob1 = OCI8::CLOB.new(@conn, ' ' * (1024 * 1024))
|
67
|
+
lob1.read(1) # to suppress `warning: assigned but unused variable - lob1`
|
80
68
|
begin
|
81
69
|
lob2 = OCI8::CLOB.new(@conn, ' ' * (128 * 1024 * 1024))
|
82
70
|
rescue OCIError
|
data/test/test_connstr.rb
CHANGED
@@ -80,9 +80,9 @@ class TestConnStr < Minitest::Test
|
|
80
80
|
DESC_TEST_CASE =
|
81
81
|
[
|
82
82
|
# Cannot distinguish net service names from easy connect strings in this case.
|
83
|
-
["sales-server", nil, nil, "sales-server"],
|
83
|
+
["sales-server", nil, nil, false, "sales-server"],
|
84
84
|
# Easy Connect string with host.
|
85
|
-
["//sales-server", nil, nil, <<EOS],
|
85
|
+
["//sales-server", nil, nil, false, <<EOS],
|
86
86
|
(DESCRIPTION=
|
87
87
|
(CONNECT_DATA=
|
88
88
|
(SERVICE_NAME=))
|
@@ -92,7 +92,7 @@ class TestConnStr < Minitest::Test
|
|
92
92
|
(PORT=1521)))
|
93
93
|
EOS
|
94
94
|
# Easy Connect string with host and port.
|
95
|
-
["sales-server:3456", nil, nil, <<EOS],
|
95
|
+
["sales-server:3456", nil, nil, false, <<EOS],
|
96
96
|
(DESCRIPTION=
|
97
97
|
(CONNECT_DATA=
|
98
98
|
(SERVICE_NAME=))
|
@@ -102,7 +102,7 @@ EOS
|
|
102
102
|
(PORT=3456)))
|
103
103
|
EOS
|
104
104
|
# The host name is sales-server and the service name is sales.
|
105
|
-
["sales-server/sales", nil, nil, <<EOS],
|
105
|
+
["sales-server/sales", nil, nil, false, <<EOS],
|
106
106
|
(DESCRIPTION=
|
107
107
|
(CONNECT_DATA=
|
108
108
|
(SERVICE_NAME=sales))
|
@@ -112,7 +112,7 @@ EOS
|
|
112
112
|
(PORT=1521)))
|
113
113
|
EOS
|
114
114
|
# Easy Connect string with IPv6 address.
|
115
|
-
["[2001:0db8:0:0::200C:417A]:80/sales", nil, nil, <<EOS],
|
115
|
+
["[2001:0db8:0:0::200C:417A]:80/sales", nil, nil, false, <<EOS],
|
116
116
|
(DESCRIPTION=
|
117
117
|
(CONNECT_DATA=
|
118
118
|
(SERVICE_NAME=sales))
|
@@ -122,7 +122,7 @@ EOS
|
|
122
122
|
(PORT=80)))
|
123
123
|
EOS
|
124
124
|
# Easy Connect string with IPv6 host address.
|
125
|
-
["sales-server:80/sales", nil, nil, <<EOS],
|
125
|
+
["sales-server:80/sales", nil, nil, false, <<EOS],
|
126
126
|
(DESCRIPTION=
|
127
127
|
(CONNECT_DATA=
|
128
128
|
(SERVICE_NAME=sales))
|
@@ -132,7 +132,7 @@ EOS
|
|
132
132
|
(PORT=80)))
|
133
133
|
EOS
|
134
134
|
# Easy Connect string with host, service name, and server.
|
135
|
-
["sales-server/sales:dedicated/inst1", nil, nil, <<EOS],
|
135
|
+
["sales-server/sales:dedicated/inst1", nil, nil, false, <<EOS],
|
136
136
|
(DESCRIPTION=
|
137
137
|
(CONNECT_DATA=
|
138
138
|
(SERVICE_NAME=sales)
|
@@ -143,7 +143,7 @@ EOS
|
|
143
143
|
(HOST=sales-server)
|
144
144
|
(PORT=1521)))
|
145
145
|
EOS
|
146
|
-
["sales-server//inst1", nil, nil, <<EOS],
|
146
|
+
["sales-server//inst1", nil, nil, false, <<EOS],
|
147
147
|
(DESCRIPTION=
|
148
148
|
(CONNECT_DATA=
|
149
149
|
(SERVICE_NAME=)
|
@@ -154,7 +154,7 @@ EOS
|
|
154
154
|
(PORT=1521)))
|
155
155
|
EOS
|
156
156
|
#
|
157
|
-
["sales-server/sales", 20, nil, <<EOS],
|
157
|
+
["sales-server/sales", 20, nil, false, <<EOS],
|
158
158
|
(DESCRIPTION=
|
159
159
|
(CONNECT_DATA=
|
160
160
|
(SERVICE_NAME=sales))
|
@@ -165,7 +165,7 @@ EOS
|
|
165
165
|
(TRANSPORT_CONNECT_TIMEOUT=20))
|
166
166
|
EOS
|
167
167
|
#
|
168
|
-
["sales-server/sales", nil, 30, <<EOS],
|
168
|
+
["sales-server/sales", nil, 30, false, <<EOS],
|
169
169
|
(DESCRIPTION=
|
170
170
|
(CONNECT_DATA=
|
171
171
|
(SERVICE_NAME=sales))
|
@@ -176,7 +176,7 @@ EOS
|
|
176
176
|
(CONNECT_TIMEOUT=30))
|
177
177
|
EOS
|
178
178
|
#
|
179
|
-
["sales-server/sales", 20, 30, <<EOS],
|
179
|
+
["sales-server/sales", 20, 30, false, <<EOS],
|
180
180
|
(DESCRIPTION=
|
181
181
|
(CONNECT_DATA=
|
182
182
|
(SERVICE_NAME=sales))
|
@@ -186,6 +186,21 @@ EOS
|
|
186
186
|
(PORT=1521))
|
187
187
|
(TRANSPORT_CONNECT_TIMEOUT=20)
|
188
188
|
(CONNECT_TIMEOUT=30))
|
189
|
+
EOS
|
190
|
+
["sales-server/sales", 20, 30, true, <<EOS],
|
191
|
+
(DESCRIPTION=
|
192
|
+
(CONNECT_DATA=
|
193
|
+
(SERVICE_NAME=sales)
|
194
|
+
)
|
195
|
+
(ADDRESS=
|
196
|
+
(PROTOCOL=TCP)
|
197
|
+
(HOST=sales-server)
|
198
|
+
(PORT=1521)
|
199
|
+
)
|
200
|
+
(TRANSPORT_CONNECT_TIMEOUT=20)
|
201
|
+
(CONNECT_TIMEOUT=30)
|
202
|
+
(ENABLE=BROKEN)
|
203
|
+
)
|
189
204
|
EOS
|
190
205
|
]
|
191
206
|
|
@@ -195,9 +210,10 @@ EOS
|
|
195
210
|
easy_connect_string = test_case[0]
|
196
211
|
tcp_connnect_timeout= test_case[1]
|
197
212
|
outbound_connnect_timeout = test_case[2]
|
198
|
-
|
213
|
+
tcp_keepalive = test_case[3]
|
214
|
+
expected_result = test_case[4].gsub(/\s/, '')
|
199
215
|
# use instance_eval to call a private method to_connect_descriptor
|
200
|
-
result = obj.instance_eval { to_connect_descriptor(easy_connect_string, tcp_connnect_timeout, outbound_connnect_timeout) }
|
216
|
+
result = obj.instance_eval { to_connect_descriptor(easy_connect_string, tcp_connnect_timeout, outbound_connnect_timeout, tcp_keepalive) }
|
201
217
|
assert_equal(expected_result, result, easy_connect_string)
|
202
218
|
end
|
203
219
|
end
|
data/test/test_datetime.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'oci8'
|
2
2
|
require File.dirname(__FILE__) + '/config'
|
3
|
-
require 'scanf'
|
4
3
|
|
5
4
|
class TestDateTime < Minitest::Test
|
6
5
|
|
@@ -28,6 +27,12 @@ class TestDateTime < Minitest::Test
|
|
28
27
|
convert_to_datetime($1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, $6.to_i, subsec, $8)
|
29
28
|
end
|
30
29
|
|
30
|
+
# 'YYYY-MM-DD HH24:MI:SS' or 'YYYY-MM-DD HH24:MI:SS.FF6' to array
|
31
|
+
def string_to_array(str)
|
32
|
+
/(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)(?:\.(\d+))?/ =~ str
|
33
|
+
[$1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, $6.to_i, $7 ? $7.to_i / 1000 : 0]
|
34
|
+
end
|
35
|
+
|
31
36
|
def setup
|
32
37
|
@conn = get_oci8_connection
|
33
38
|
end
|
@@ -43,7 +48,7 @@ class TestDateTime < Minitest::Test
|
|
43
48
|
@conn.exec(<<-EOS) do |row|
|
44
49
|
SELECT TO_DATE('#{date}', 'YYYY-MM-DD HH24:MI:SS') FROM dual
|
45
50
|
EOS
|
46
|
-
assert_equal(Time.local(*date
|
51
|
+
assert_equal(Time.local(*string_to_array(date)), row[0])
|
47
52
|
end
|
48
53
|
end
|
49
54
|
end
|
@@ -94,7 +99,7 @@ EOS
|
|
94
99
|
@conn.exec(<<-EOS) do |row|
|
95
100
|
SELECT TO_TIMESTAMP('#{date}', 'YYYY-MM-DD HH24:MI:SS.FF') FROM dual
|
96
101
|
EOS
|
97
|
-
assert_equal(Time.local(*date
|
102
|
+
assert_equal(Time.local(*string_to_array(date)), row[0])
|
98
103
|
end
|
99
104
|
end
|
100
105
|
end
|
data/test/test_object.rb
CHANGED
@@ -22,7 +22,7 @@ begin
|
|
22
22
|
|
23
23
|
begin
|
24
24
|
version = RbTestObj.test_object_version(conn)
|
25
|
-
error_message = "Invalid test object version" if version !=
|
25
|
+
error_message = "Invalid test object version" if version != 4
|
26
26
|
rescue NoMethodError
|
27
27
|
raise unless $!.to_s.include?('test_object_version')
|
28
28
|
error_message = "rb_test_obj.test_object_version is not declared."
|
@@ -100,7 +100,8 @@ class TestObj1 < Minitest::Test
|
|
100
100
|
attr_reader :obj_array_val
|
101
101
|
attr_reader :obj_ary_of_ary_val
|
102
102
|
attr_reader :date_val
|
103
|
-
|
103
|
+
attr_reader :timestamp_val
|
104
|
+
attr_reader :timestamp_tz_val
|
104
105
|
|
105
106
|
attr_accessor :assertions
|
106
107
|
|
@@ -109,16 +110,28 @@ class TestObj1 < Minitest::Test
|
|
109
110
|
@assertions = 0
|
110
111
|
end
|
111
112
|
|
112
|
-
def
|
113
|
+
def to_test_datetime(n, type)
|
113
114
|
year = (1990 + n).round
|
114
115
|
month = (n.round * 5) % 12 + 1
|
115
116
|
mday = (n.round * 7) % 27 + 1
|
116
117
|
hour = (n.round * 9) % 24
|
117
118
|
minute = (n.round * 11) % 60
|
118
119
|
sec = (n.round * 13) % 60
|
119
|
-
|
120
|
+
nsec = if type == :date
|
121
|
+
0
|
122
|
+
else
|
123
|
+
((n.round * 333_333_333) % 1_000_000_000).to_r / 1_000_000_000
|
124
|
+
end
|
125
|
+
tz = if type == :timestamp_tz
|
126
|
+
tzh = (n.round * 15) % 24 - 11
|
127
|
+
tzm = (n.round * 17) % 60
|
128
|
+
format('%+03d:%02d', tzh, tzm)
|
129
|
+
else
|
130
|
+
nil
|
131
|
+
end
|
132
|
+
convert_to_time(year, month, mday, hour, minute, sec, nsec, tz)
|
120
133
|
end
|
121
|
-
private :
|
134
|
+
private :to_test_datetime
|
122
135
|
|
123
136
|
def next
|
124
137
|
@n += 1.2
|
@@ -135,7 +148,9 @@ class TestObj1 < Minitest::Test
|
|
135
148
|
@nclob_val = @str_val
|
136
149
|
@blob_val = @str_val
|
137
150
|
@obj_val = ExpectedValObjElem.new(@int_val, @int_val + 1)
|
138
|
-
@date_val =
|
151
|
+
@date_val = to_test_datetime(@n, :date)
|
152
|
+
@timestamp_val = to_test_datetime(@n, :timestamp)
|
153
|
+
@timestamp_tz_val = to_test_datetime(@n, :timestamp_tz)
|
139
154
|
if @int_val == 1
|
140
155
|
@int_array_val = nil
|
141
156
|
@flt_array_val = nil
|
@@ -199,7 +214,8 @@ class TestObj1 < Minitest::Test
|
|
199
214
|
obj_array_val = val[18]
|
200
215
|
obj_ary_of_ary_val = val[19]
|
201
216
|
date_val = val[20]
|
202
|
-
|
217
|
+
timestamp_val = val[21]
|
218
|
+
timestamp_tz_val = val[22]
|
203
219
|
else
|
204
220
|
assert_instance_of(RbTestObj, val)
|
205
221
|
int_val = val.int_val
|
@@ -223,7 +239,8 @@ class TestObj1 < Minitest::Test
|
|
223
239
|
obj_array_val = val.obj_array_val
|
224
240
|
obj_ary_of_ary_val = val.obj_ary_of_ary_val
|
225
241
|
date_val = val.date_val
|
226
|
-
|
242
|
+
timestamp_val = val.timestamp_val
|
243
|
+
timestamp_tz_val = val.timestamp_tz_val
|
227
244
|
end
|
228
245
|
|
229
246
|
assert_equal(@int_val, int_val)
|
@@ -267,7 +284,8 @@ class TestObj1 < Minitest::Test
|
|
267
284
|
assert_nil(obj_ary_of_ary_val)
|
268
285
|
end
|
269
286
|
assert_equal(@date_val, date_val)
|
270
|
-
|
287
|
+
assert_equal(@timestamp_val, timestamp_val)
|
288
|
+
assert_equal(@timestamp_tz_val, timestamp_tz_val)
|
271
289
|
end
|
272
290
|
|
273
291
|
def assert_array_in_delta(exp, val)
|
data/test/test_oci8.rb
CHANGED
@@ -25,54 +25,142 @@ EOS
|
|
25
25
|
drop_table('test_rename_table')
|
26
26
|
end
|
27
27
|
|
28
|
-
#
|
29
|
-
#
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
28
|
+
# Set `OCI8::BindType::Base.initial_chunk_size = 5` to
|
29
|
+
# use the following test data.
|
30
|
+
LONG_TEST_DATA = [
|
31
|
+
# initial chunk size: 5 (total buffer size: 5)
|
32
|
+
'a' * 4, 'b' * 5, 'c' * 6, 'd' * 5, 'e' * 4,
|
33
|
+
# second chunk size: 10 (total buffer size: 15)
|
34
|
+
'f' * 14, 'g' * 15, 'h' * 16, 'i' * 15, 'j' * 14,
|
35
|
+
# third chunk size: 20 (total buffer size: 35)
|
36
|
+
'k' * 34, 'l' * 35, 'm' * 36, 'n' * 35, 'o' * 34,
|
37
|
+
# use data around initial chunk size again
|
38
|
+
'p' * 4, 'q' * 5, 'r' * 6, 's' * 5, 't' * 4,
|
39
|
+
# special data
|
40
|
+
'', nil,
|
41
|
+
]
|
42
|
+
|
43
|
+
def test_long_type
|
44
|
+
clob_bind_type = OCI8::BindType::Mapping[:clob]
|
45
|
+
blob_bind_type = OCI8::BindType::Mapping[:blob]
|
46
|
+
initial_cunk_size = OCI8::BindType::Base.initial_chunk_size
|
47
|
+
begin
|
48
|
+
OCI8::BindType::Base.initial_chunk_size = 5
|
49
|
+
@conn.prefetch_rows = LONG_TEST_DATA.size / 3
|
50
|
+
drop_table('test_table')
|
51
|
+
ascii_enc = Encoding.find('US-ASCII')
|
52
|
+
0.upto(1) do |i|
|
53
|
+
if i == 0
|
54
|
+
@conn.exec("CREATE TABLE test_table (id number(38), long_column long, clob_column clob)")
|
55
|
+
cursor = @conn.parse('insert into test_table values (:1, :2, :3)')
|
56
|
+
cursor.bind_param(1, nil, Integer)
|
57
|
+
cursor.bind_param(2, nil, :long)
|
58
|
+
cursor.bind_param(3, nil, :clob)
|
59
|
+
lob = OCI8::CLOB.new(@conn, '')
|
60
|
+
enc = Encoding.default_internal || OCI8.encoding
|
61
|
+
else
|
62
|
+
@conn.exec("CREATE TABLE test_table (id number(38), long_raw_column long raw, blob_column blob)")
|
63
|
+
cursor = @conn.parse('insert into test_table values (:1, :2, :3)')
|
64
|
+
cursor.bind_param(1, nil, Integer)
|
65
|
+
cursor.bind_param(2, nil, :long_raw)
|
66
|
+
cursor.bind_param(3, nil, :blob)
|
67
|
+
lob = OCI8::BLOB.new(@conn, '')
|
68
|
+
enc = Encoding.find('ASCII-8BIT')
|
69
|
+
end
|
70
|
+
|
71
|
+
LONG_TEST_DATA.each_with_index do |data, index|
|
72
|
+
cursor[1] = index
|
73
|
+
cursor[2] = data
|
74
|
+
if data.nil?
|
75
|
+
cursor[3] = nil
|
76
|
+
else
|
77
|
+
lob.rewind
|
78
|
+
lob.write(data)
|
79
|
+
lob.size = data.size
|
80
|
+
cursor[3] = lob
|
81
|
+
end
|
82
|
+
cursor.exec
|
83
|
+
end
|
84
|
+
cursor.close
|
85
|
+
|
86
|
+
cursor = @conn.parse('SELECT * from test_table order by id')
|
87
|
+
cursor.exec
|
88
|
+
LONG_TEST_DATA.each_with_index do |data, index|
|
89
|
+
row = cursor.fetch
|
90
|
+
assert_equal(index, row[0])
|
91
|
+
if data.nil?
|
92
|
+
assert_nil(row[1])
|
93
|
+
assert_nil(row[2])
|
94
|
+
elsif data.empty?
|
95
|
+
# '' is inserted to the long or long raw column as null.
|
96
|
+
assert_nil(row[1])
|
97
|
+
# '' is inserted to the clob or blob column as an empty clob.
|
98
|
+
# It is fetched as '' when the data is read using a LOB locator.
|
99
|
+
assert_equal(data, clob_data = row[2].read)
|
100
|
+
assert_equal(ascii_enc, clob_data.encoding)
|
101
|
+
else
|
102
|
+
assert_equal(data, row[1])
|
103
|
+
assert_equal(data, clob_data = row[2].read)
|
104
|
+
assert_equal(enc, row[1].encoding)
|
105
|
+
assert_equal(enc, clob_data.encoding)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
assert_nil(cursor.fetch)
|
109
|
+
cursor.close
|
110
|
+
|
111
|
+
begin
|
112
|
+
OCI8::BindType::Mapping[:clob] = OCI8::BindType::Long
|
113
|
+
OCI8::BindType::Mapping[:blob] = OCI8::BindType::LongRaw
|
114
|
+
cursor = @conn.parse('SELECT * from test_table order by id')
|
115
|
+
cursor.exec
|
116
|
+
LONG_TEST_DATA.each_with_index do |data, index|
|
117
|
+
row = cursor.fetch
|
118
|
+
assert_equal(index, row[0])
|
119
|
+
if data.nil?
|
120
|
+
assert_nil(row[1])
|
121
|
+
assert_nil(row[2])
|
122
|
+
elsif data.empty?
|
123
|
+
# '' is inserted to the long or long raw column as null.
|
124
|
+
assert_nil(row[1])
|
125
|
+
# '' is inserted to the clob or blob column as an empty clob.
|
126
|
+
# However it is fetched as nil.
|
127
|
+
assert_nil(row[2])
|
128
|
+
else
|
129
|
+
assert_equal(data, row[1])
|
130
|
+
assert_equal(data, row[2])
|
131
|
+
assert_equal(enc, row[1].encoding)
|
132
|
+
assert_equal(enc, row[2].encoding)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
assert_nil(cursor.fetch)
|
136
|
+
cursor.close
|
137
|
+
ensure
|
138
|
+
OCI8::BindType::Mapping[:clob] = clob_bind_type
|
139
|
+
OCI8::BindType::Mapping[:blob] = blob_bind_type
|
140
|
+
end
|
141
|
+
drop_table('test_table')
|
142
|
+
end
|
143
|
+
ensure
|
144
|
+
OCI8::BindType::Base.initial_chunk_size = initial_cunk_size
|
51
145
|
end
|
52
146
|
drop_table('test_table')
|
53
147
|
end
|
54
148
|
|
55
|
-
def
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
assert_equal(test_data1, cursor.fetch[0])
|
71
|
-
assert_equal(test_data2, cursor.fetch[0])
|
72
|
-
assert_nil(cursor.fetch[0])
|
73
|
-
assert_equal(test_data4, cursor.fetch[0])
|
74
|
-
cursor.close
|
75
|
-
drop_table('test_table')
|
149
|
+
def test_bind_long_data
|
150
|
+
initial_cunk_size = OCI8::BindType::Base.initial_chunk_size
|
151
|
+
begin
|
152
|
+
OCI8::BindType::Base.initial_chunk_size = 5
|
153
|
+
cursor = @conn.parse("begin :1 := '<' || :2 || '>'; end;")
|
154
|
+
cursor.bind_param(1, nil, :long)
|
155
|
+
cursor.bind_param(2, nil, :long)
|
156
|
+
(LONG_TEST_DATA + ['z' * 4000]).each do |data|
|
157
|
+
cursor[2] = data
|
158
|
+
cursor.exec
|
159
|
+
assert_equal("<#{data}>", cursor[1])
|
160
|
+
end
|
161
|
+
ensure
|
162
|
+
OCI8::BindType::Base.initial_chunk_size = initial_cunk_size
|
163
|
+
end
|
76
164
|
end
|
77
165
|
|
78
166
|
def test_select
|
@@ -216,8 +304,8 @@ EOS
|
|
216
304
|
assert_nil(rv[4])
|
217
305
|
assert_nil(rv[5])
|
218
306
|
else
|
219
|
-
dttm = DateTime.civil(2000 + i, 8, 3, 23, 59, 59, Time.now.utc_offset.to_r/86400)
|
220
307
|
tm = Time.local(2000 + i, 8, 3, 23, 59, 59)
|
308
|
+
dttm = DateTime.civil(2000 + i, 8, 3, 23, 59, 59, tm.utc_offset.to_r/86400)
|
221
309
|
dt = Date.civil(2000 + i, 8, 3)
|
222
310
|
assert_equal(tm, rv[3])
|
223
311
|
assert_equal(dttm, rv[4])
|
@@ -451,6 +539,7 @@ EOS
|
|
451
539
|
assert_nil(@conn.last_error)
|
452
540
|
@conn.last_error = 'dummy'
|
453
541
|
cursor = @conn.parse('select col1, max(col2) from (select 1 as col1, null as col2 from dual) group by col1')
|
542
|
+
cursor.prefetch_rows = 1
|
454
543
|
assert_nil(@conn.last_error)
|
455
544
|
|
456
545
|
# When an OCI function returns OCI_SUCCESS_WITH_INFO, OCI8#last_error is set.
|
@@ -492,9 +581,44 @@ EOS
|
|
492
581
|
else
|
493
582
|
raise "Unknown column size #{column_size}"
|
494
583
|
end
|
495
|
-
driver_name = cursor.fetch[0]
|
584
|
+
driver_name = cursor.fetch[0].strip
|
496
585
|
cursor.close
|
497
586
|
assert_equal(expected_value, driver_name)
|
498
587
|
end
|
499
588
|
end
|
589
|
+
|
590
|
+
def test_server_version
|
591
|
+
cursor = @conn.exec("select * from product_component_version where product like 'Oracle Database %'")
|
592
|
+
row = cursor.fetch_hash
|
593
|
+
cursor.close
|
594
|
+
ver = if OCI8::oracle_client_version >= OCI8::ORAVER_18
|
595
|
+
row['VERSION_FULL'] || row['VERSION']
|
596
|
+
else
|
597
|
+
# OCI8#oracle_server_version could not get infomation corresponding
|
598
|
+
# to VERSION_FULL when the Oracle client version is below 18.1.
|
599
|
+
row['VERSION']
|
600
|
+
end
|
601
|
+
assert_equal(ver, @conn.oracle_server_version.to_s)
|
602
|
+
end
|
603
|
+
|
604
|
+
def test_array_fetch
|
605
|
+
drop_table('test_table')
|
606
|
+
@conn.exec("CREATE TABLE test_table (id number, val clob)")
|
607
|
+
cursor = @conn.parse("INSERT INTO test_table VALUES (:1, :2)")
|
608
|
+
1.upto(10) do |i|
|
609
|
+
cursor.exec(i, ('a'.ord + i).chr * i)
|
610
|
+
end
|
611
|
+
cursor.close
|
612
|
+
cursor = @conn.parse("select * from test_table where id <= :1 order by id")
|
613
|
+
cursor.prefetch_rows = 4
|
614
|
+
[1, 6, 2, 7, 3, 8, 4, 9, 5, 10].each do |i|
|
615
|
+
cursor.exec(i)
|
616
|
+
1.upto(i) do |j|
|
617
|
+
row = cursor.fetch
|
618
|
+
assert_equal(j, row[0])
|
619
|
+
assert_equal(('a'.ord + j).chr * j, row[1].read)
|
620
|
+
end
|
621
|
+
assert_nil(cursor.fetch)
|
622
|
+
end
|
623
|
+
end
|
500
624
|
end # TestOCI8
|