jdbc-helper 0.5.1 → 0.6.0
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.
- data/README.markdown +251 -0
- data/lib/jdbc-helper.rb +1 -10
- data/lib/jdbc-helper/connection.rb +347 -351
- data/lib/jdbc-helper/connection/callable_statement.rb +56 -56
- data/lib/jdbc-helper/connection/parameterized_statement.rb +57 -46
- data/lib/jdbc-helper/connection/prepared_statement.rb +88 -88
- data/lib/jdbc-helper/connection/result_set_enumerator.rb +102 -91
- data/lib/jdbc-helper/connection/row.rb +106 -115
- data/lib/jdbc-helper/connection/statement_pool.rb +44 -44
- data/lib/jdbc-helper/connection/type_map.rb +41 -66
- data/lib/jdbc-helper/connector.rb +10 -10
- data/lib/jdbc-helper/connector/mysql_connector.rb +24 -24
- data/lib/jdbc-helper/connector/oracle_connector.rb +33 -32
- data/lib/jdbc-helper/constants.rb +20 -17
- data/lib/jdbc-helper/sql.rb +168 -175
- data/lib/jdbc-helper/wrapper/function_wrapper.rb +12 -12
- data/lib/jdbc-helper/wrapper/object_wrapper.rb +17 -17
- data/lib/jdbc-helper/wrapper/procedure_wrapper.rb +120 -123
- data/lib/jdbc-helper/wrapper/sequence_wrapper.rb +43 -43
- data/lib/jdbc-helper/wrapper/table_wrapper.rb +172 -169
- data/test/helper.rb +2 -10
- data/test/performance.rb +141 -0
- data/test/test_connection.rb +443 -389
- data/test/test_connectors.rb +47 -47
- data/test/test_object_wrapper.rb +541 -432
- data/test/test_sql.rb +143 -135
- metadata +119 -123
- data/README.rdoc +0 -223
- data/test/test_performance.rb +0 -138
data/test/helper.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'bundler'
|
3
|
-
require 'pry'
|
3
|
+
#require 'pry'
|
4
|
+
|
4
5
|
begin
|
5
6
|
Bundler.setup(:default, :development)
|
6
7
|
rescue Bundler::BundlerError => e
|
@@ -71,15 +72,6 @@ module JDBCHelperTestHelper
|
|
71
72
|
end
|
72
73
|
end
|
73
74
|
|
74
|
-
# This is crazy. But Oracle.
|
75
|
-
def assert_equal *args
|
76
|
-
if args.first.class == Fixnum
|
77
|
-
super(args[0].to_s, args[1].to_s)
|
78
|
-
else
|
79
|
-
super(*args)
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
75
|
def each_connection(&block)
|
84
76
|
config.each do | db, conn_info |
|
85
77
|
conn = JDBCHelper::Connection.new(conn_info.reject { |k,v| k == 'database'})
|
data/test/performance.rb
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'benchmark'
|
3
|
+
|
4
|
+
class TestPerformance < Test::Unit::TestCase
|
5
|
+
include JDBCHelperTestHelper
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@table = 'tmp_jdbc_helper'
|
9
|
+
@range = 'aaa'..'aaz'
|
10
|
+
@count = 10000 # Increase this for performance measurement
|
11
|
+
end
|
12
|
+
|
13
|
+
def teardown
|
14
|
+
each_connection do | conn |
|
15
|
+
drop_table conn
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# No assertion here.
|
20
|
+
def test_performance
|
21
|
+
each_connection do |conn, info|
|
22
|
+
# FIXME
|
23
|
+
next unless info['driver'] =~ /mysql/
|
24
|
+
|
25
|
+
reset conn
|
26
|
+
puts "Normal inserts: #{Benchmark.measure {
|
27
|
+
@count.times do |i|
|
28
|
+
conn.update "insert into #{@table} values (#{@range.map{rand @count}.join ','})"
|
29
|
+
end
|
30
|
+
}.real}"
|
31
|
+
|
32
|
+
puts "Normal inserts (batch & chuck-transactional): #{Benchmark.measure {
|
33
|
+
(0...@count).each_slice(50) do |slice|
|
34
|
+
conn.transaction do
|
35
|
+
slice.each do |i|
|
36
|
+
conn.add_batch "insert into #{@table} values (#{@range.map{rand @count}.join ','})"
|
37
|
+
end
|
38
|
+
conn.execute_batch
|
39
|
+
end
|
40
|
+
end
|
41
|
+
}.real}"
|
42
|
+
|
43
|
+
puts "Prepared inserts: #{Benchmark.measure {
|
44
|
+
pins = conn.prepare "insert into #{@table} values (#{@range.map{'?'}.join ','})"
|
45
|
+
@count.times do |i|
|
46
|
+
pins.update *(@range.map {rand @count})
|
47
|
+
end
|
48
|
+
pins.close
|
49
|
+
}.real}"
|
50
|
+
|
51
|
+
puts "Prepared inserts (batch & chuck-transactional): #{Benchmark.measure {
|
52
|
+
pins = conn.prepare "insert into #{@table} values (#{@range.map{'?'}.join ','})"
|
53
|
+
(0...@count).each_slice(50) do |slice|
|
54
|
+
conn.transaction do
|
55
|
+
slice.each do |i|
|
56
|
+
pins.add_batch *(@range.map {rand @count})
|
57
|
+
end
|
58
|
+
pins.execute_batch
|
59
|
+
end
|
60
|
+
end
|
61
|
+
pins.close
|
62
|
+
}.real}"
|
63
|
+
|
64
|
+
puts "Inserts with hash: #{Benchmark.measure {
|
65
|
+
table = conn.table(@table)
|
66
|
+
@count.times do |i|
|
67
|
+
table.insert @range.inject({}) { |hash, key| hash[key] = rand; hash }
|
68
|
+
end
|
69
|
+
}.real}"
|
70
|
+
|
71
|
+
puts "Inserts with hash (batch & chunk-transactional): #{Benchmark.measure {
|
72
|
+
table = conn.table(@table)
|
73
|
+
btable = table.batch
|
74
|
+
(0...@count).each_slice(50) do |slice|
|
75
|
+
conn.transaction do
|
76
|
+
slice.each do |i|
|
77
|
+
btable.insert @range.inject({}) { |hash, key| hash[key] = rand; hash }
|
78
|
+
end
|
79
|
+
conn.execute_batch
|
80
|
+
end
|
81
|
+
end
|
82
|
+
}.real}"
|
83
|
+
|
84
|
+
assert_equal @count * 6, conn.table(@table).count
|
85
|
+
|
86
|
+
conn.query("select * from #{@table}") do |row|
|
87
|
+
# ...
|
88
|
+
end
|
89
|
+
|
90
|
+
puts "Accessing records using dot notation: #{Benchmark.measure {
|
91
|
+
conn.query("select * from #{@table}") do |row|
|
92
|
+
@range.each do |r|
|
93
|
+
row.send r
|
94
|
+
end
|
95
|
+
end
|
96
|
+
}.real}"
|
97
|
+
|
98
|
+
puts "Accessing records using numeric indexes: #{Benchmark.measure {
|
99
|
+
conn.query("select * from #{@table}") do |row|
|
100
|
+
@range.each_with_index do |r,i|
|
101
|
+
row[i]
|
102
|
+
end
|
103
|
+
end
|
104
|
+
}.real}"
|
105
|
+
|
106
|
+
puts "Chaining enumerators with query: #{Benchmark.measure {
|
107
|
+
conn.query("select * from #{@table}").each_slice(50) do |slice|
|
108
|
+
slice.each do |row|
|
109
|
+
@range.each_with_index do |r,i|
|
110
|
+
row[i]
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
}.real}"
|
115
|
+
|
116
|
+
puts "Chaining enumerators with enumerate: #{Benchmark.measure {
|
117
|
+
conn.enumerate("select * from #{@table}").each_slice(50) do |slice|
|
118
|
+
slice.each do |row|
|
119
|
+
@range.each_with_index do |r,i|
|
120
|
+
row[i]
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
}.real}"
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def create_table conn
|
129
|
+
conn.update("create table #{@table} (#{@range.map { |e| "#{e} int" }.join(', ')})")
|
130
|
+
end
|
131
|
+
|
132
|
+
def drop_table conn
|
133
|
+
conn.update("drop table #{@table}") rescue nil
|
134
|
+
end
|
135
|
+
|
136
|
+
def reset conn
|
137
|
+
drop_table conn
|
138
|
+
create_table conn
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
data/test/test_connection.rb
CHANGED
@@ -1,279 +1,331 @@
|
|
1
1
|
require 'helper'
|
2
2
|
|
3
3
|
class TestConnection < Test::Unit::TestCase
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
4
|
+
include JDBCHelperTestHelper
|
5
|
+
|
6
|
+
def setup
|
7
|
+
end
|
8
|
+
|
9
|
+
def teardown
|
10
|
+
conn.update "drop table #{TEST_TABLE}" rescue nil
|
11
|
+
conn.update "drop procedure #{TEST_PROCEDURE}" rescue nil
|
12
|
+
end
|
13
|
+
|
14
|
+
TEST_TABLE = 'tmp_jdbc_helper_test'
|
15
|
+
TEST_PROCEDURE = 'tmp_jdbc_helper_test_proc'
|
16
|
+
|
17
|
+
def get_one_two
|
18
|
+
"
|
19
|
+
select 1 one, 'two' two from dual
|
20
|
+
union all
|
21
|
+
select 1 one, 'two' two from dual
|
22
|
+
"
|
23
|
+
end
|
24
|
+
|
25
|
+
def check_one_two(rec)
|
26
|
+
assert_equal 2, rec.length
|
27
|
+
|
28
|
+
assert_equal 1, rec.one
|
29
|
+
assert_equal 1, rec[0]
|
30
|
+
assert_equal 1, rec['one']
|
31
|
+
assert_equal 1, rec[:one]
|
32
|
+
assert_equal [1], rec[0...1]
|
33
|
+
assert_equal [1], rec[0, 1]
|
34
|
+
|
35
|
+
assert_equal 'two', rec.two
|
36
|
+
assert_equal 'two', rec[1]
|
37
|
+
assert_equal 'two', rec['two']
|
38
|
+
assert_equal ['two'], rec[1..-1]
|
39
|
+
assert_equal ['two'], rec[1, 1]
|
40
|
+
|
41
|
+
assert_equal [1, 'two'], rec[0..1]
|
42
|
+
assert_equal [1, 'two'], rec[0..-1]
|
43
|
+
assert_equal [1, 'two'], rec[0, 2]
|
44
|
+
|
45
|
+
# FIXME: Exponent field
|
46
|
+
assert rec.join('--') =~ /--two$/
|
47
|
+
|
48
|
+
assert_raise(NoMethodError) { rec.three }
|
49
|
+
assert_raise(NameError) { rec['three'] }
|
50
|
+
assert_raise(NameError) { rec[:three] }
|
51
|
+
assert_raise(RangeError) { rec[3] }
|
52
|
+
end
|
53
|
+
|
54
|
+
def reset_test_table conn
|
55
|
+
conn.update "drop table #{TEST_TABLE}" rescue nil
|
56
|
+
cnt = conn.update "
|
57
|
+
create table #{TEST_TABLE} (
|
58
|
+
a int primary key,
|
59
|
+
b varchar(100)
|
60
|
+
)"
|
61
|
+
assert_equal 0, cnt
|
62
|
+
end
|
63
|
+
|
64
|
+
def reset_test_table_ts conn
|
65
|
+
conn.update "drop table #{TEST_TABLE}" rescue nil
|
66
|
+
cnt = conn.update "
|
67
|
+
create table #{TEST_TABLE} (
|
68
|
+
a timestamp
|
69
|
+
)"
|
70
|
+
assert_equal 0, cnt
|
71
|
+
end
|
72
|
+
|
73
|
+
# ---------------------------------------------------------------
|
74
|
+
|
75
|
+
def test_invalid_driver
|
76
|
+
assert_raise(NameError) {
|
77
|
+
JDBCHelper::Connection.new(:driver => 'xxx', :url => 'localhost')
|
78
|
+
}
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_connect_clone_and_close
|
82
|
+
config.each do | db, conn_info_org |
|
83
|
+
4.times do | i |
|
84
|
+
conn_info = conn_info_org.reject { |k,v| k == 'database' }
|
85
|
+
|
86
|
+
# With or without timeout parameter
|
87
|
+
conn_info['timeout'] = 60 if i % 2 == 1
|
88
|
+
|
89
|
+
# Can connect with hash with symbol keys?
|
90
|
+
conn_info.keys.each do | str_key |
|
91
|
+
conn_info[str_key.to_sym] = conn_info.delete str_key
|
92
|
+
end if i % 2 == 0
|
93
|
+
|
94
|
+
# Integers will be converted to String
|
95
|
+
#conn_info['defaultRowPrefetch'] = 1000
|
96
|
+
|
97
|
+
conn = JDBCHelper::Connection.new(conn_info)
|
98
|
+
assert_equal(conn.closed?, false)
|
99
|
+
assert_equal(conn.driver, conn_info[:driver] || conn_info['driver'])
|
100
|
+
assert_equal(conn.url, conn_info[:url] || conn_info['url'])
|
91
101
|
|
92
102
|
conn.fetch_size = 100
|
93
103
|
assert_equal 100, conn.fetch_size
|
94
104
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
105
|
+
conn.close
|
106
|
+
assert_equal(conn.closed?, true)
|
107
|
+
[ :query, :update, :add_batch, :prepare ].each do | met |
|
108
|
+
assert_raise(RuntimeError) { conn.send met, "A" }
|
109
|
+
end
|
110
|
+
[ :execute_batch, :clear_batch ].each do | met |
|
111
|
+
assert_raise(RuntimeError) { conn.send met }
|
112
|
+
end
|
103
113
|
|
104
114
|
new_conn = conn.clone
|
105
115
|
assert new_conn.java_obj != conn.java_obj
|
106
|
-
|
116
|
+
assert new_conn.closed? == false
|
107
117
|
assert_equal 100, new_conn.fetch_size
|
108
118
|
new_conn.close
|
109
119
|
|
110
|
-
|
111
|
-
|
120
|
+
# initialize with execution block
|
121
|
+
conn = JDBCHelper::Connection.new(conn_info) do | c |
|
112
122
|
c2 = c.clone
|
113
123
|
assert c2.java_obj != c.java_obj
|
114
124
|
|
115
|
-
|
116
|
-
|
117
|
-
|
125
|
+
c.query('select 1 from dual')
|
126
|
+
c2.query('select 1 from dual')
|
127
|
+
assert_equal c.closed?, false
|
118
128
|
|
119
129
|
c2.close
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
130
|
+
assert c2.closed?
|
131
|
+
end
|
132
|
+
assert conn.closed?
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def test_fetch_size
|
138
|
+
each_connection do | conn |
|
139
|
+
assert_nil conn.fetch_size
|
140
|
+
conn.fetch_size = 10
|
141
|
+
assert_equal 10, conn.fetch_size
|
142
|
+
conn.set_fetch_size 20
|
143
|
+
assert_equal 20, conn.fetch_size
|
144
|
+
|
145
|
+
# No way to confirm whether if this is really working as it's supposed to be.
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def test_query_enumerate
|
150
|
+
each_connection do | conn |
|
151
|
+
# Query without a block => Array
|
152
|
+
query_result = conn.query get_one_two
|
153
|
+
assert query_result.is_a? Array
|
154
|
+
assert_equal 2, query_result.length
|
155
|
+
check_one_two(query_result.first)
|
156
|
+
assert_equal query_result.first, query_result.last
|
157
|
+
|
158
|
+
# Query with a block
|
159
|
+
count = 0
|
160
|
+
conn.query(get_one_two) do | row |
|
161
|
+
check_one_two row
|
162
|
+
count += 1
|
163
|
+
end
|
164
|
+
assert_equal 2, count
|
165
|
+
|
166
|
+
# Enumerate
|
167
|
+
enum = conn.enumerate(get_one_two)
|
168
|
+
assert enum.is_a? Enumerable
|
169
|
+
assert enum.closed? == false
|
170
|
+
a = enum.to_a
|
171
|
+
assert_equal 2, a.length
|
172
|
+
check_one_two a.first
|
173
|
+
assert enum.closed? == true
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def test_enumerate_errors
|
178
|
+
each_connection do |conn|
|
179
|
+
# On error, Statement object must be returned to the StatementPool
|
180
|
+
(JDBCHelper::Constants::MAX_STATEMENT_NESTING_LEVEL * 2).times do |i|
|
181
|
+
conn.enumerate('xxx') rescue nil
|
182
|
+
end
|
183
|
+
assert_equal 'OK', conn.query("select 'OK' from dual")[0][0]
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def test_deep_nesting
|
188
|
+
nest = lambda { |str, lev|
|
189
|
+
if lev > 0
|
190
|
+
"conn.query('select 1 from dual') do |r#{lev}|
|
191
|
+
#{nest.call str, lev - 1}
|
192
|
+
end"
|
193
|
+
else
|
194
|
+
str
|
195
|
+
end
|
196
|
+
}
|
197
|
+
(1..(JDBCHelper::Constants::MAX_STATEMENT_NESTING_LEVEL + 1)).each do |level|
|
198
|
+
each_connection do |conn|
|
199
|
+
str = nest.call('assert true', level)
|
200
|
+
if level > JDBCHelper::Constants::MAX_STATEMENT_NESTING_LEVEL
|
201
|
+
assert_raise(RuntimeError) { eval str }
|
202
|
+
else
|
203
|
+
eval str
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
def test_update_batch
|
210
|
+
each_connection do | conn |
|
211
|
+
reset_test_table conn
|
212
|
+
count = 100
|
213
|
+
|
214
|
+
iq = lambda do | i |
|
215
|
+
"insert into #{TEST_TABLE} values (#{i}, 'A')"
|
216
|
+
end
|
174
217
|
ins1 = conn.prepare "insert into #{TEST_TABLE} values (? + #{count}, 'B')"
|
175
218
|
ins2 = conn.prepare "insert into #{TEST_TABLE} values (? + #{count * 2}, 'C')"
|
176
219
|
|
177
|
-
|
178
|
-
|
179
|
-
|
220
|
+
# update
|
221
|
+
assert_equal 1, conn.update(iq.call 0)
|
222
|
+
assert_equal 1, conn.prev_stat.success_count
|
180
223
|
|
181
|
-
|
182
|
-
|
224
|
+
# add_batch execute_batch
|
225
|
+
reset_test_table conn
|
183
226
|
|
184
|
-
|
185
|
-
|
227
|
+
count.times do | p |
|
228
|
+
conn.add_batch iq.call(p)
|
186
229
|
ins1.add_batch p
|
187
230
|
ins2.add_batch p
|
188
|
-
|
189
|
-
|
190
|
-
|
231
|
+
end
|
232
|
+
conn.execute_batch
|
233
|
+
assert_equal count * 3, conn.table(TEST_TABLE).count
|
191
234
|
|
192
|
-
|
193
|
-
|
235
|
+
# add_batch clear_batch
|
236
|
+
reset_test_table conn
|
194
237
|
|
195
|
-
|
196
|
-
|
238
|
+
count.times do | p |
|
239
|
+
conn.add_batch iq.call(p)
|
197
240
|
ins1.add_batch p
|
198
241
|
ins2.add_batch p
|
199
|
-
|
200
|
-
|
242
|
+
end
|
243
|
+
conn.clear_batch
|
201
244
|
# Already cleared, no effect
|
202
245
|
ins1.execute_batch
|
203
246
|
ins2.execute_batch
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
247
|
+
assert_equal 0, conn.table(TEST_TABLE).count
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
def test_prepared_query_enumerate
|
252
|
+
each_connection do | conn |
|
253
|
+
2.times do |iter|
|
254
|
+
sel = conn.prepare get_one_two
|
255
|
+
assert sel.closed? == false
|
256
|
+
assert_equal conn.prepared_statements.first, sel
|
257
|
+
|
258
|
+
# Fetch size
|
259
|
+
if iter == 0
|
260
|
+
assert_nil conn.fetch_size
|
261
|
+
assert_nil sel.fetch_size
|
262
|
+
end
|
263
|
+
conn.fetch_size = 100
|
264
|
+
sel.fetch_size = 10
|
265
|
+
assert_equal 100, conn.fetch_size
|
266
|
+
assert_equal 10, sel.fetch_size
|
267
|
+
sel.set_fetch_size 20
|
268
|
+
assert_equal 100, conn.fetch_size
|
269
|
+
assert_equal 20, sel.fetch_size
|
270
|
+
|
271
|
+
# Query without a block => Array
|
272
|
+
query_result = sel.query
|
273
|
+
assert query_result.is_a? Array
|
274
|
+
assert_equal 2, query_result.length
|
275
|
+
check_one_two(query_result.first)
|
276
|
+
|
277
|
+
# Query with a block
|
278
|
+
count = 0
|
279
|
+
sel.query do | row |
|
280
|
+
check_one_two row
|
281
|
+
count += 1
|
282
|
+
end
|
283
|
+
assert_equal 2, count
|
284
|
+
|
285
|
+
# Enumerate
|
286
|
+
enum = sel.enumerate
|
287
|
+
assert enum.is_a? Enumerable
|
288
|
+
assert enum.closed? == false
|
289
|
+
a = enum.to_a
|
290
|
+
assert_equal 2, a.length
|
291
|
+
check_one_two a.first
|
292
|
+
assert enum.closed? == true
|
293
|
+
|
294
|
+
if iter == 0
|
295
|
+
sel.close
|
296
|
+
else
|
297
|
+
sel.java_obj.close
|
298
|
+
end
|
299
|
+
|
300
|
+
assert sel.closed?
|
301
|
+
[ :query, :update, :add_batch, :execute_batch, :clear_batch ].each do | met |
|
302
|
+
assert_raise(RuntimeError) { sel.send met }
|
303
|
+
end
|
304
|
+
end#times
|
305
|
+
end#each_connection
|
306
|
+
end
|
307
|
+
|
308
|
+
def test_prepared_update_batch
|
309
|
+
each_connection do | conn |
|
310
|
+
reset_test_table conn
|
311
|
+
ins = conn.prepare "insert into #{TEST_TABLE} values (?, ?)"
|
312
|
+
assert_equal 2, ins.parameter_count
|
261
313
|
assert_equal conn.prepared_statements.first, ins
|
262
314
|
|
263
|
-
|
315
|
+
count = 100
|
264
316
|
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
317
|
+
# update
|
318
|
+
assert ins.closed? == false
|
319
|
+
assert_equal 1, ins.update(0, 'A')
|
320
|
+
assert_equal 1, conn.prev_stat.success_count
|
321
|
+
ins.close
|
270
322
|
assert_equal 0, conn.prepared_statements.length
|
271
323
|
|
272
|
-
|
324
|
+
# add_batch execute_batch
|
273
325
|
2.times do |iter|
|
274
326
|
reset_test_table conn
|
275
327
|
ins = conn.prepare "insert into #{TEST_TABLE} values (?, ?)"
|
276
|
-
assert_equal conn.prepared_statements.first, ins
|
328
|
+
assert_equal conn.prepared_statements.first, ins if iter == 0
|
277
329
|
|
278
330
|
count.times do | p |
|
279
331
|
ins.add_batch(p + 1, 'A')
|
@@ -283,15 +335,16 @@ class TestConnection < Test::Unit::TestCase
|
|
283
335
|
else
|
284
336
|
conn.execute_batch
|
285
337
|
end
|
286
|
-
assert_equal count, conn.
|
338
|
+
assert_equal count, conn.table(TEST_TABLE).count
|
287
339
|
ins.close
|
288
|
-
|
340
|
+
# 1 for count
|
341
|
+
assert_equal 1, conn.prepared_statements.length
|
289
342
|
end
|
290
343
|
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
assert_equal conn.prepared_statements.
|
344
|
+
# add_batch clear_batch
|
345
|
+
reset_test_table conn
|
346
|
+
ins = conn.prepare "insert into #{TEST_TABLE} values (?, ?)"
|
347
|
+
assert_equal conn.prepared_statements.last, ins # count is first
|
295
348
|
|
296
349
|
# clear_batch
|
297
350
|
2.times do |iter|
|
@@ -303,154 +356,155 @@ class TestConnection < Test::Unit::TestCase
|
|
303
356
|
else
|
304
357
|
conn.clear_batch
|
305
358
|
end
|
306
|
-
assert_equal 0, conn.
|
359
|
+
assert_equal 0, conn.table(TEST_TABLE).count
|
307
360
|
end
|
308
361
|
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
362
|
+
# close closed?
|
363
|
+
assert ins.closed? == false
|
364
|
+
ins.close
|
365
|
+
# 1 for count
|
366
|
+
assert_equal 1, conn.prepared_statements.length
|
367
|
+
assert ins.closed?
|
368
|
+
[ :query, :update, :add_batch, :execute_batch, :clear_batch ].each do | met |
|
369
|
+
assert_raise(RuntimeError) { ins.send met }
|
370
|
+
end
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
374
|
+
def test_transaction
|
375
|
+
each_connection do | conn |
|
376
|
+
reset_test_table conn
|
377
|
+
count = 100
|
378
|
+
|
379
|
+
3.times do | i |
|
380
|
+
sum = 0
|
381
|
+
conn.update "delete from #{TEST_TABLE}"
|
382
|
+
conn.transaction do | tx |
|
383
|
+
count.times.each_slice(10) do | slice |
|
384
|
+
slice.each do | p |
|
385
|
+
conn.add_batch("insert into #{TEST_TABLE} values (#{p}, 'xxx')")
|
386
|
+
sum += p
|
387
|
+
end
|
388
|
+
conn.execute_batch
|
389
|
+
end
|
390
|
+
result = conn.query("select count(*), sum(a) from #{TEST_TABLE}").first
|
391
|
+
|
392
|
+
assert_equal count, result.first
|
393
|
+
assert_equal sum, result.last
|
394
|
+
|
395
|
+
case i
|
396
|
+
when 0 then tx.rollback
|
397
|
+
when 1 then tx.commit
|
398
|
+
else
|
399
|
+
nil # committed implicitly
|
400
|
+
end
|
401
|
+
|
402
|
+
flunk 'This should not be executed' if i < 2
|
403
|
+
end
|
404
|
+
|
405
|
+
assert_equal (i == 0 ? 0 : count),
|
406
|
+
conn.table(TEST_TABLE).count
|
407
|
+
end
|
408
|
+
end
|
409
|
+
end
|
410
|
+
|
411
|
+
def test_setter_timestamp
|
412
|
+
each_connection do | conn |
|
413
|
+
# Java timestamp
|
414
|
+
reset_test_table_ts conn
|
415
|
+
ts = java.sql.Timestamp.new(Time.now.to_i * 1000)
|
416
|
+
conn.prepare("insert into #{TEST_TABLE} values (?)").update(ts)
|
417
|
+
assert_equal ts, conn.query("select * from #{TEST_TABLE}")[0][0]
|
418
|
+
|
419
|
+
# Ruby time
|
420
|
+
reset_test_table_ts conn
|
421
|
+
ts = Time.now
|
422
|
+
conn.prepare("insert into #{TEST_TABLE} values (?)").update(ts)
|
423
|
+
got = conn.query("select * from #{TEST_TABLE}")[0][0]
|
424
|
+
assert [ts.to_i * 1000, (ts.to_f * 1000).to_i].include?(got.getTime)
|
425
|
+
end
|
426
|
+
end
|
427
|
+
|
428
|
+
# Conditional testing is bad, but
|
429
|
+
# Oracle and MySQL behave differently.
|
430
|
+
def test_callable_statement
|
431
|
+
each_connection do | conn |
|
432
|
+
# Creating test procedure (Defined in JDBCHelperTestHelper)
|
433
|
+
create_test_procedure conn, TEST_PROCEDURE
|
434
|
+
|
435
|
+
# Array parameter
|
436
|
+
cstmt_ord = conn.prepare_call "{call #{TEST_PROCEDURE}(?, ?, ?, ?, ?, ?, ?)}"
|
437
|
+
result = cstmt_ord.call('hello', 10, [100, Fixnum], [Time.now, Time], nil, Float, String)
|
438
|
+
assert_instance_of Hash, result
|
439
|
+
assert_equal 1000, result[3]
|
440
|
+
assert_equal 'hello', result[7]
|
441
|
+
|
442
|
+
# Hash parameter
|
443
|
+
cstmt_name = conn.prepare_call(case @type
|
444
|
+
when :oracle
|
445
|
+
"{call #{TEST_PROCEDURE}(:i1, :i2, :io1, :io2, :n1, :o1, :o2)}"
|
446
|
+
else
|
447
|
+
"{call #{TEST_PROCEDURE}(?, ?, ?, ?, ?, ?, ?)}"
|
448
|
+
end)
|
449
|
+
result = cstmt_name.call(
|
450
|
+
:i1 => 'hello', :i2 => 10,
|
451
|
+
:io1 => [100, Fixnum], 'io2' => [Time.now, Time],
|
452
|
+
:n1 => nil,
|
453
|
+
:o1 => Float, 'o2' => String)
|
454
|
+
assert_instance_of Hash, result
|
455
|
+
assert_equal 1000, result[:io1]
|
456
|
+
assert_equal 'hello', result['o2']
|
457
|
+
|
458
|
+
# Invalid parameters
|
459
|
+
#assert_raise(NativeException) { cstmt_ord.call 1 }
|
460
|
+
assert_raise(ArgumentError) { cstmt_ord.call({}, {}) }
|
461
|
+
assert_raise(NativeException) { cstmt_name.call 1 }
|
462
|
+
assert_raise(ArgumentError) { cstmt_name.call({}, {}) }
|
463
|
+
|
464
|
+
# Close
|
465
|
+
[ cstmt_ord, cstmt_name ].each do | cstmt |
|
466
|
+
assert_equal false, cstmt.closed?
|
467
|
+
cstmt.close
|
468
|
+
assert_equal true, cstmt.closed?
|
469
|
+
assert_raise(RuntimeError) { cstmt.call }
|
470
|
+
end
|
471
|
+
|
472
|
+
# Data truncated for column 'io1' at row 2. WHY?
|
473
|
+
# http://www.herongyang.com/JDBC/MySQL-CallableStatement-INOUT-Parameters.html
|
474
|
+
if @type != :mysql
|
475
|
+
cstmt_ord = conn.prepare_call "{call #{TEST_PROCEDURE}('howdy', ?, ?, ?, ?, ?, ?)}"
|
476
|
+
cstmt_name = conn.prepare_call(case @type
|
477
|
+
when :oracle
|
478
|
+
"{call #{TEST_PROCEDURE}('howdy', :i2, :io1, :io2, :n1, :o1, :o2)}"
|
479
|
+
else
|
480
|
+
"{call #{TEST_PROCEDURE}('howdy', ?, ?, ?, ?, ?, ?)}"
|
481
|
+
end)
|
482
|
+
# Hash parameter
|
483
|
+
result = cstmt_name.call(
|
484
|
+
#:i1 => 'hello',
|
485
|
+
:i2 => 10,
|
486
|
+
:io1 => [100, Fixnum], 'io2' => [Time.now, Time],
|
487
|
+
:n1 => nil,
|
488
|
+
:o1 => Float, 'o2' => String)
|
489
|
+
assert_instance_of Hash, result
|
490
|
+
assert_equal 1000, result[:io1]
|
491
|
+
assert_equal 'howdy', result['o2']
|
492
|
+
|
493
|
+
# Array parameter
|
494
|
+
result = cstmt_ord.call(10, [100, Fixnum], [Time.now, Time], nil, Float, String)
|
495
|
+
assert_instance_of Hash, result
|
496
|
+
assert_equal 1000, result[2]
|
497
|
+
assert_equal 'howdy', result[6]
|
498
|
+
|
499
|
+
# Close
|
500
|
+
[ cstmt_ord, cstmt_name ].each do | cstmt |
|
501
|
+
assert_equal false, cstmt.closed?
|
502
|
+
cstmt.close
|
503
|
+
assert_equal true, cstmt.closed?
|
504
|
+
assert_raise(RuntimeError) { cstmt.call }
|
505
|
+
end
|
506
|
+
end
|
507
|
+
end
|
508
|
+
end
|
455
509
|
end
|
456
510
|
|