jdbc-helper 0.1.2
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/LICENSE.txt +20 -0
- data/README.rdoc +114 -0
- data/lib/jdbc-helper.rb +21 -0
- data/lib/jdbc-helper/connection.rb +395 -0
- data/lib/jdbc-helper/connection/prepared_statement.rb +141 -0
- data/lib/jdbc-helper/connection/result_set_enumerator.rb +100 -0
- data/lib/jdbc-helper/connection/row.rb +110 -0
- data/lib/jdbc-helper/connection/statement_pool.rb +61 -0
- data/lib/jdbc-helper/connector.rb +6 -0
- data/lib/jdbc-helper/connector/mysql_connector.rb +28 -0
- data/lib/jdbc-helper/connector/oracle_connector.rb +29 -0
- data/lib/jdbc-helper/constants.rb +26 -0
- data/test/database.yml +13 -0
- data/test/helper.rb +17 -0
- data/test/test_jdbc-helper.rb +292 -0
- metadata +105 -0
@@ -0,0 +1,29 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# Junegunn Choi (junegunn.c@gmail.com)
|
3
|
+
|
4
|
+
module JDBCHelper
|
5
|
+
# Shortcut connector for Oracle
|
6
|
+
module OracleConnector
|
7
|
+
include Constants
|
8
|
+
include Constants::Connector
|
9
|
+
|
10
|
+
def self.connect(host, user, password, service_name, timeout = DEFAULT_LOGIN_TIMEOUT)
|
11
|
+
Connection.new(
|
12
|
+
:driver => JDBC_DRIVER[:oracle],
|
13
|
+
:url => "jdbc:oracle:thin:@#{host}/#{service_name}",
|
14
|
+
:user => user,
|
15
|
+
:password => password,
|
16
|
+
:timeout => timeout)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.connect_by_sid(host, user, password, sid, timeout = DEFAULT_LOGIN_TIMEOUT)
|
20
|
+
Connection.new(
|
21
|
+
:driver => JDBC_DRIVER[:oracle],
|
22
|
+
:url => "jdbc:oracle:thin:@#{host}:#{sid}",
|
23
|
+
:user => user,
|
24
|
+
:password => password,
|
25
|
+
:timeout => timeout)
|
26
|
+
end
|
27
|
+
end#OracleConnector
|
28
|
+
end#JDBCHelper
|
29
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# Junegunn Choi (junegunn.c@gmail.com)
|
3
|
+
|
4
|
+
module JDBCHelper
|
5
|
+
module Constants
|
6
|
+
# Default login timeout is set to 60 seconds
|
7
|
+
DEFAULT_LOGIN_TIMEOUT = 60
|
8
|
+
|
9
|
+
# Constants only for Connectors
|
10
|
+
module Connector
|
11
|
+
JDBC_DRIVER = {
|
12
|
+
:oracle => 'oracle.jdbc.driver.OracleDriver',
|
13
|
+
:mysql => 'com.mysql.jdbc.Driver'
|
14
|
+
}
|
15
|
+
|
16
|
+
DEFAULT_PARAMETERS = {
|
17
|
+
:mysql => {
|
18
|
+
'zeroDateTimeBehavior' => 'convertToNull',
|
19
|
+
'rewriteBatchedStatements' => 'true',
|
20
|
+
'useServerPrepStmts' => 'true',
|
21
|
+
'useCursorFetch' => 'true'
|
22
|
+
}
|
23
|
+
}
|
24
|
+
end#Connector
|
25
|
+
end#Constants
|
26
|
+
end#JDBCHelper
|
data/test/database.yml
ADDED
data/test/helper.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'test/unit'
|
11
|
+
|
12
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
13
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
14
|
+
require 'jdbc-helper'
|
15
|
+
|
16
|
+
class Test::Unit::TestCase
|
17
|
+
end
|
@@ -0,0 +1,292 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestJdbcHelper < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
require 'yaml'
|
6
|
+
@config = YAML.load File.read(File.dirname(__FILE__) + '/database.yml')
|
7
|
+
end
|
8
|
+
|
9
|
+
def teardown
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
TEST_TABLE = 'tmp_jdbc_helper_test'
|
14
|
+
|
15
|
+
def each_connection
|
16
|
+
@config.each do | db, conn_info |
|
17
|
+
conn = JDBCHelper::Connection.new(conn_info)
|
18
|
+
begin
|
19
|
+
yield conn
|
20
|
+
ensure
|
21
|
+
conn.close
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def get_one_two
|
27
|
+
"
|
28
|
+
select 1 one, 'two' two from dual
|
29
|
+
union all
|
30
|
+
select 1 one, 'two' two from dual
|
31
|
+
"
|
32
|
+
end
|
33
|
+
|
34
|
+
def check_one_two(rec)
|
35
|
+
assert_equal 2, rec.length
|
36
|
+
|
37
|
+
assert_equal 1, rec.one
|
38
|
+
assert_equal 1, rec[0]
|
39
|
+
assert_equal 1, rec['one']
|
40
|
+
|
41
|
+
assert_equal 'two', rec.two
|
42
|
+
assert_equal 'two', rec[1]
|
43
|
+
assert_equal 'two', rec['two']
|
44
|
+
|
45
|
+
assert_raise(NameError) { rec.three }
|
46
|
+
assert_raise(NameError) { rec['three'] }
|
47
|
+
assert_raise(RangeError) { rec[3] }
|
48
|
+
end
|
49
|
+
|
50
|
+
def reset_test_table conn
|
51
|
+
conn.update "drop table #{TEST_TABLE}" rescue nil
|
52
|
+
cnt = conn.update '
|
53
|
+
create table tmp_jdbc_helper_test (
|
54
|
+
a int primary key,
|
55
|
+
b varchar(100)
|
56
|
+
)'
|
57
|
+
assert_equal 0, cnt
|
58
|
+
end
|
59
|
+
|
60
|
+
# ---------------------------------------------------------------
|
61
|
+
|
62
|
+
def test_connect_and_close
|
63
|
+
@config.each do | db, conn_info |
|
64
|
+
4.times do | i |
|
65
|
+
# With or without timeout parameter
|
66
|
+
conn_info['timeout'] = 60 if i % 2 == 1
|
67
|
+
|
68
|
+
# Can connect with hash with symbol keys?
|
69
|
+
conn_info.keys.each do | str_key |
|
70
|
+
conn_info[str_key.to_sym] = conn_info.delete str_key
|
71
|
+
end if i % 2 == 0
|
72
|
+
|
73
|
+
conn = JDBCHelper::Connection.new(conn_info)
|
74
|
+
assert_equal(conn.closed?, false)
|
75
|
+
conn.close
|
76
|
+
assert_equal(conn.closed?, true)
|
77
|
+
[ :query, :update, :add_batch, :prepare ].each do | met |
|
78
|
+
assert_raise(RuntimeError) { conn.send met, "A" }
|
79
|
+
end
|
80
|
+
[ :execute_batch, :clear_batch ].each do | met |
|
81
|
+
assert_raise(RuntimeError) { conn.send met }
|
82
|
+
end
|
83
|
+
|
84
|
+
# initialize with execution block
|
85
|
+
conn = JDBCHelper::Connection.new(conn_info) do | c |
|
86
|
+
c.query('select 1 from dual')
|
87
|
+
assert_equal c.closed?, false
|
88
|
+
end
|
89
|
+
assert conn.closed?
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_query_enumerate
|
95
|
+
each_connection do | conn |
|
96
|
+
# Query without a block => Array
|
97
|
+
query_result = conn.query get_one_two
|
98
|
+
assert query_result.is_a? Array
|
99
|
+
assert_equal 2, query_result.length
|
100
|
+
check_one_two(query_result.first)
|
101
|
+
|
102
|
+
# Query with a block
|
103
|
+
count = 0
|
104
|
+
conn.query(get_one_two) do | row |
|
105
|
+
check_one_two row
|
106
|
+
count += 1
|
107
|
+
end
|
108
|
+
assert_equal 2, count
|
109
|
+
|
110
|
+
# Enumerate
|
111
|
+
enum = conn.enumerate(get_one_two)
|
112
|
+
assert enum.is_a? Enumerable
|
113
|
+
assert enum.closed? == false
|
114
|
+
a = enum.to_a
|
115
|
+
assert_equal 2, a.length
|
116
|
+
check_one_two a.first
|
117
|
+
assert enum.closed? == true
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def test_update_batch
|
122
|
+
each_connection do | conn |
|
123
|
+
reset_test_table conn
|
124
|
+
count = 100
|
125
|
+
|
126
|
+
iq = lambda do | i |
|
127
|
+
"insert into #{TEST_TABLE} values (#{i}, 'A')"
|
128
|
+
end
|
129
|
+
|
130
|
+
# update
|
131
|
+
assert_equal 1, conn.update(iq.call 0)
|
132
|
+
assert_equal 1, conn.prev_stat.success_count
|
133
|
+
|
134
|
+
# add_batch execute_batch
|
135
|
+
reset_test_table conn
|
136
|
+
|
137
|
+
count.times do | p |
|
138
|
+
conn.add_batch iq.call(p)
|
139
|
+
end
|
140
|
+
conn.execute_batch
|
141
|
+
assert_equal count, conn.query("select count(*) from #{TEST_TABLE}")[0][0]
|
142
|
+
|
143
|
+
# add_batch clear_batch
|
144
|
+
reset_test_table conn
|
145
|
+
|
146
|
+
count.times do | p |
|
147
|
+
conn.add_batch iq.call(p)
|
148
|
+
end
|
149
|
+
conn.clear_batch
|
150
|
+
assert_equal 0, conn.query("select count(*) from #{TEST_TABLE}")[0][0]
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def test_prepared_query_enumerate
|
155
|
+
each_connection do | conn |
|
156
|
+
sel = conn.prepare get_one_two
|
157
|
+
assert sel.closed? == false
|
158
|
+
|
159
|
+
# Query without a block => Array
|
160
|
+
query_result = sel.query
|
161
|
+
assert query_result.is_a? Array
|
162
|
+
assert_equal 2, query_result.length
|
163
|
+
check_one_two(query_result.first)
|
164
|
+
|
165
|
+
# Query with a block
|
166
|
+
count = 0
|
167
|
+
sel.query do | row |
|
168
|
+
check_one_two row
|
169
|
+
count += 1
|
170
|
+
end
|
171
|
+
assert_equal 2, count
|
172
|
+
|
173
|
+
# Enumerate
|
174
|
+
enum = sel.enumerate
|
175
|
+
assert enum.is_a? Enumerable
|
176
|
+
assert enum.closed? == false
|
177
|
+
a = enum.to_a
|
178
|
+
assert_equal 2, a.length
|
179
|
+
check_one_two a.first
|
180
|
+
assert enum.closed? == true
|
181
|
+
|
182
|
+
sel.close
|
183
|
+
assert sel.closed?
|
184
|
+
[ :query, :update, :add_batch, :execute_batch, :clear_batch ].each do | met |
|
185
|
+
assert_raise(RuntimeError) { sel.send met }
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def test_prepared_update_batch
|
191
|
+
each_connection do | conn |
|
192
|
+
reset_test_table conn
|
193
|
+
ins = conn.prepare "insert into #{TEST_TABLE} values (?, ?)"
|
194
|
+
count = 100
|
195
|
+
|
196
|
+
# update
|
197
|
+
assert ins.closed? == false
|
198
|
+
assert_equal 1, ins.update(0, 'A')
|
199
|
+
assert_equal 1, conn.prev_stat.success_count
|
200
|
+
ins.close
|
201
|
+
|
202
|
+
# add_batch execute_batch
|
203
|
+
reset_test_table conn
|
204
|
+
ins = conn.prepare "insert into #{TEST_TABLE} values (?, ?)"
|
205
|
+
|
206
|
+
count.times do | p |
|
207
|
+
ins.add_batch(p + 1, 'A')
|
208
|
+
end
|
209
|
+
ins.execute_batch
|
210
|
+
assert_equal count, conn.query("select count(*) from #{TEST_TABLE}")[0][0]
|
211
|
+
ins.close
|
212
|
+
|
213
|
+
# add_batch clear_batch
|
214
|
+
reset_test_table conn
|
215
|
+
ins = conn.prepare "insert into #{TEST_TABLE} values (?, ?)"
|
216
|
+
|
217
|
+
count.times do | p |
|
218
|
+
ins.add_batch(p + 1, 'A')
|
219
|
+
end
|
220
|
+
ins.clear_batch
|
221
|
+
assert_equal 0, conn.query("select count(*) from #{TEST_TABLE}")[0][0]
|
222
|
+
|
223
|
+
# close closed?
|
224
|
+
assert ins.closed? == false
|
225
|
+
ins.close
|
226
|
+
assert ins.closed?
|
227
|
+
[ :query, :update, :add_batch, :execute_batch, :clear_batch ].each do | met |
|
228
|
+
assert_raise(RuntimeError) { ins.send met }
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
def test_transaction
|
234
|
+
each_connection do | conn |
|
235
|
+
reset_test_table conn
|
236
|
+
count = 100
|
237
|
+
|
238
|
+
3.times do | i |
|
239
|
+
sum = 0
|
240
|
+
conn.update "delete from #{TEST_TABLE}"
|
241
|
+
conn.transaction do | tx |
|
242
|
+
count.times.each_slice(10) do | slice |
|
243
|
+
slice.each do | p |
|
244
|
+
conn.add_batch("insert into #{TEST_TABLE} values (#{p}, 'xxx')")
|
245
|
+
sum += p
|
246
|
+
end
|
247
|
+
conn.execute_batch
|
248
|
+
end
|
249
|
+
result = conn.query("select count(*), sum(a) from #{TEST_TABLE}").first
|
250
|
+
|
251
|
+
assert_equal count, result.first
|
252
|
+
assert_equal sum, result.last.to_i
|
253
|
+
|
254
|
+
case i
|
255
|
+
when 0 then tx.rollback
|
256
|
+
when 1 then tx.commit
|
257
|
+
else
|
258
|
+
nil # committed implicitly
|
259
|
+
end
|
260
|
+
|
261
|
+
flunk 'This should not be executed' if i < 2
|
262
|
+
end
|
263
|
+
|
264
|
+
assert_equal (i == 0 ? 0 : count),
|
265
|
+
conn.query("select count(*) from #{TEST_TABLE}").first.first
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
def test_connectors
|
271
|
+
@config.each do | db, conn_info |
|
272
|
+
if db == 'mysql'
|
273
|
+
host = conn_info['url'].match(%r{//(.*?)/})[1]
|
274
|
+
db = conn_info['url'].match(%r{/([^/?]*?)(\?.*)?$})[1]
|
275
|
+
conn = JDBCHelper::MySQLConnector.connect(host, conn_info['user'], conn_info['password'], db)
|
276
|
+
|
277
|
+
assert conn.closed? == false
|
278
|
+
conn.close
|
279
|
+
assert conn.closed?
|
280
|
+
elsif db == 'oracle'
|
281
|
+
host = conn_info['url'].match(%r{//(.*?)/})[1]
|
282
|
+
svc = conn_info['url'].match(%r{/([^/?]*?)(\?.*)?$})[1]
|
283
|
+
conn = JDBCHelper::OracleConnector.connect(host, conn_info['user'], conn_info['password'], svc)
|
284
|
+
|
285
|
+
assert conn.closed? == false
|
286
|
+
conn.close
|
287
|
+
assert conn.closed?
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
metadata
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jdbc-helper
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.1.2
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Junegunn Choi
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-04-01 00:00:00 +09:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: bundler
|
18
|
+
prerelease: false
|
19
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
|
+
none: false
|
21
|
+
requirements:
|
22
|
+
- - ~>
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 1.0.0
|
25
|
+
type: :development
|
26
|
+
version_requirements: *id001
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: jeweler
|
29
|
+
prerelease: false
|
30
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
31
|
+
none: false
|
32
|
+
requirements:
|
33
|
+
- - ~>
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: 1.5.2
|
36
|
+
type: :development
|
37
|
+
version_requirements: *id002
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: rcov
|
40
|
+
prerelease: false
|
41
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: "0"
|
47
|
+
type: :development
|
48
|
+
version_requirements: *id003
|
49
|
+
description: JDBCHelper::Connection object wraps around a JDBC connection and provides much nicer interface to crucial database operations from primitive selects and updates to more complex ones involving batch updates, prepared statements and transactions.
|
50
|
+
email: junegunn.c@gmail.com
|
51
|
+
executables: []
|
52
|
+
|
53
|
+
extensions: []
|
54
|
+
|
55
|
+
extra_rdoc_files:
|
56
|
+
- LICENSE.txt
|
57
|
+
- README.rdoc
|
58
|
+
files:
|
59
|
+
- lib/jdbc-helper.rb
|
60
|
+
- lib/jdbc-helper/connection.rb
|
61
|
+
- lib/jdbc-helper/connection/prepared_statement.rb
|
62
|
+
- lib/jdbc-helper/connection/result_set_enumerator.rb
|
63
|
+
- lib/jdbc-helper/connection/row.rb
|
64
|
+
- lib/jdbc-helper/connection/statement_pool.rb
|
65
|
+
- lib/jdbc-helper/connector.rb
|
66
|
+
- lib/jdbc-helper/connector/mysql_connector.rb
|
67
|
+
- lib/jdbc-helper/connector/oracle_connector.rb
|
68
|
+
- lib/jdbc-helper/constants.rb
|
69
|
+
- LICENSE.txt
|
70
|
+
- README.rdoc
|
71
|
+
- test/database.yml
|
72
|
+
- test/helper.rb
|
73
|
+
- test/test_jdbc-helper.rb
|
74
|
+
has_rdoc: true
|
75
|
+
homepage: http://github.com/junegunn/jdbc-helper
|
76
|
+
licenses:
|
77
|
+
- MIT
|
78
|
+
post_install_message:
|
79
|
+
rdoc_options: []
|
80
|
+
|
81
|
+
require_paths:
|
82
|
+
- lib
|
83
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
84
|
+
none: false
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: "0"
|
89
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: "0"
|
95
|
+
requirements: []
|
96
|
+
|
97
|
+
rubyforge_project:
|
98
|
+
rubygems_version: 1.5.1
|
99
|
+
signing_key:
|
100
|
+
specification_version: 3
|
101
|
+
summary: A JDBC helper for Ruby/Database developers
|
102
|
+
test_files:
|
103
|
+
- test/database.yml
|
104
|
+
- test/helper.rb
|
105
|
+
- test/test_jdbc-helper.rb
|