jdbc-helper 0.5.1 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -5,69 +5,69 @@ module JDBCHelper
|
|
5
5
|
class Connection
|
6
6
|
# Interface to Java CallableStatment
|
7
7
|
class CallableStatement < ParameterizedStatement
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
8
|
+
# Array or Hash (for named parameters)
|
9
|
+
# - IN parameter: value
|
10
|
+
# - OUT parameter: class
|
11
|
+
# - INOUT parameter: [value, class]
|
12
|
+
# (Although class can be inferred from the value,
|
13
|
+
# we still need a way to figure out if it's INOUT parameter)
|
14
|
+
def call *params
|
15
|
+
check_closed
|
16
16
|
|
17
|
-
|
18
|
-
|
17
|
+
out_params = set_params(params)
|
18
|
+
measure_exec(:call) { @java_obj.execute }
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
20
|
+
result = {}
|
21
|
+
out_params.each do |idx, jtype|
|
22
|
+
getter = JDBCHelper::Connection::GETTER_MAP.fetch(jtype, :get_string)
|
23
|
+
value = @java_obj.send(getter, idx.is_a?(Symbol) ? idx.to_s : idx)
|
24
|
+
result[idx] = @java_obj.was_null ? nil : value
|
25
|
+
end
|
26
|
+
result
|
27
|
+
end
|
28
28
|
|
29
29
|
private
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
30
|
+
def set_params(params) # :nodoc:
|
31
|
+
hash_params =
|
32
|
+
if params.first.kind_of? Hash
|
33
|
+
raise ArgumentError.new("More than one Hash given") if params.length > 1
|
34
|
+
params.first
|
35
|
+
else
|
36
|
+
params.each_with_index.inject({}) { |hash, pair|
|
37
|
+
hash[pair.last + 1] = pair.first
|
38
|
+
hash
|
39
|
+
}
|
40
|
+
end
|
41
41
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
42
|
+
out_params = {}
|
43
|
+
hash_params.each do | idx, value |
|
44
|
+
# Symbols need to be transformed into string
|
45
|
+
idx_ = idx.is_a?(Symbol) ? idx.to_s : idx
|
46
|
+
case value
|
47
|
+
# OUT parameter
|
48
|
+
when Class
|
49
|
+
jtype = JDBCHelper::Connection::RUBY_SQL_TYPE_MAP[value] || java.sql.Types::VARCHAR
|
50
|
+
@java_obj.registerOutParameter(idx_, jtype)
|
51
|
+
out_params[idx] = jtype
|
52
52
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
53
|
+
# INOUT parameter
|
54
|
+
when Array
|
55
|
+
set_param(idx_, value.first)
|
56
|
+
jtype = JDBCHelper::Connection::RUBY_SQL_TYPE_MAP[value.last] || java.sql.Types::VARCHAR
|
57
|
+
@java_obj.registerOutParameter(idx_, jtype)
|
58
|
+
out_params[idx] = jtype
|
59
|
+
|
60
|
+
# IN parameter
|
61
|
+
else
|
62
|
+
set_param(idx_, value)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
out_params
|
66
|
+
end
|
67
67
|
|
68
|
-
|
69
|
-
|
70
|
-
|
68
|
+
def initialize(*args)
|
69
|
+
super(*args)
|
70
|
+
end
|
71
71
|
end#CallableStatment
|
72
72
|
end#Connection
|
73
73
|
end#JDBCHelper
|
@@ -6,60 +6,71 @@ class Connection
|
|
6
6
|
# Base class for CallableStatement and PreparedStatment
|
7
7
|
# @abstract
|
8
8
|
class ParameterizedStatement
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
# SQL string
|
10
|
+
# @return [String]
|
11
|
+
attr_reader :sql
|
12
12
|
|
13
|
-
|
14
|
-
|
13
|
+
# Underlying Java object
|
14
|
+
attr_reader :java_obj
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
16
|
+
# @param [JDBCHelper::Connection] conn
|
17
|
+
# @param [String] cstmt_str
|
18
|
+
def initialize(conn, sql, obj)
|
19
|
+
@conn = conn
|
20
|
+
@sql = sql
|
21
|
+
@java_obj = obj
|
22
|
+
end
|
23
23
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
24
|
+
def set_param(idx, param)
|
25
|
+
case param
|
26
|
+
when NilClass
|
27
|
+
@java_obj.setNull idx, java.sql.Types::NULL
|
28
|
+
when Fixnum
|
29
|
+
@java_obj.setLong idx, param
|
30
|
+
when Bignum
|
31
|
+
@java_obj.setString idx, param.to_s # Safer
|
32
|
+
when BigDecimal
|
33
|
+
@java_obj.setBigDecimal idx, param.to_java
|
34
|
+
when String
|
35
|
+
@java_obj.setString idx, param
|
36
|
+
when Float
|
37
|
+
@java_obj.setDouble idx, param
|
38
|
+
when Time
|
39
|
+
@java_obj.setTimestamp idx, java.sql.Timestamp.new((param.to_f * 1000).to_i)
|
40
|
+
when java.sql.Date
|
41
|
+
@java_obj.setDate idx, param
|
42
|
+
when java.sql.Time
|
43
|
+
@java_obj.setTime idx, param
|
44
|
+
when java.sql.Timestamp
|
45
|
+
@java_obj.setTimestamp idx, param
|
46
|
+
when java.sql.Blob
|
47
|
+
@java_obj.setBinaryStream idx, param.getBinaryStream#, param.length
|
48
|
+
when java.io.InputStream
|
49
|
+
@java_obj.setBinaryStream idx, param
|
50
|
+
else
|
51
|
+
@java_obj.setString idx, param.to_s
|
52
|
+
end
|
53
|
+
end
|
37
54
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
55
|
+
# @return [NilClass]
|
56
|
+
def close
|
57
|
+
@java_obj.close
|
58
|
+
@java_obj = nil
|
59
|
+
end
|
43
60
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
end
|
49
|
-
|
50
|
-
# @return [Boolean]
|
51
|
-
def closed?
|
52
|
-
@java_obj.nil?
|
53
|
-
end
|
61
|
+
# @return [Boolean]
|
62
|
+
def closed?
|
63
|
+
@java_obj.nil? || @java_obj.isClosed
|
64
|
+
end
|
54
65
|
|
55
66
|
private
|
56
|
-
|
57
|
-
|
58
|
-
|
67
|
+
def measure_exec(type, &blk) # :nodoc:
|
68
|
+
@conn.send(:measure_exec, type, &blk)
|
69
|
+
end
|
59
70
|
|
60
|
-
|
61
|
-
|
62
|
-
|
71
|
+
def check_closed
|
72
|
+
raise RuntimeError.new("Object already closed") if closed?
|
73
|
+
end
|
63
74
|
|
64
75
|
end#ParameterizedStatement
|
65
76
|
end#Connection
|
@@ -12,96 +12,96 @@ class Connection
|
|
12
12
|
# rows = pstmt.query(10, 20)
|
13
13
|
# enum = pstmt.enumerate(10, 20)
|
14
14
|
class PreparedStatement < ParameterizedStatement
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
15
|
+
# Returns the number of parameters required
|
16
|
+
# @return [Fixnum]
|
17
|
+
def parameter_count
|
18
|
+
@pmd ||= @java_obj.get_parameter_meta_data
|
19
|
+
@pmd.get_parameter_count
|
20
|
+
end
|
21
|
+
|
22
|
+
# @return [NilClass]
|
23
|
+
def close
|
24
24
|
@conn.send(:close_pstmt, self)
|
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
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
25
|
+
@java_obj.close
|
26
|
+
@java_obj = nil
|
27
|
+
end
|
28
|
+
|
29
|
+
# @return [Fixnum]
|
30
|
+
def update(*params)
|
31
|
+
check_closed
|
32
|
+
|
33
|
+
set_params(params)
|
34
|
+
measure_exec(:p_update) { @java_obj.execute_update }
|
35
|
+
end
|
36
|
+
|
37
|
+
# @return [Array] Returns an Array if block is not given
|
38
|
+
def query(*params, &blk)
|
39
|
+
check_closed
|
40
|
+
|
41
|
+
set_params(params)
|
42
|
+
# sorry, ignoring privacy
|
43
|
+
@conn.send(:process_and_close_rset,
|
44
|
+
measure_exec(:p_query) { @java_obj.execute_query }, &blk)
|
45
|
+
end
|
46
|
+
|
47
|
+
# @return [JDBCHelper::Connection::ResultSetEnumerator]
|
48
|
+
def enumerate(*params, &blk)
|
49
|
+
check_closed
|
50
|
+
|
51
|
+
return query(*params, &blk) if block_given?
|
52
|
+
|
53
|
+
set_params(params)
|
54
|
+
ResultSetEnumerator.new(measure_exec(:p_query) { @java_obj.execute_query })
|
55
|
+
end
|
56
|
+
|
57
|
+
# Adds to the batch
|
58
|
+
# @return [NilClass]
|
59
|
+
def add_batch(*params)
|
60
|
+
check_closed
|
61
|
+
|
62
|
+
set_params(params)
|
63
|
+
@java_obj.add_batch
|
64
|
+
end
|
65
|
+
# Executes the batch
|
66
|
+
def execute_batch
|
67
|
+
check_closed
|
68
|
+
|
69
|
+
measure_exec(:p_execute_batch) {
|
70
|
+
@java_obj.executeBatch
|
71
|
+
}
|
72
|
+
end
|
73
|
+
# Clears the batch
|
74
|
+
# @return [NilClass]
|
75
|
+
def clear_batch
|
76
|
+
check_closed
|
77
|
+
|
78
|
+
@java_obj.clear_batch
|
79
|
+
end
|
80
|
+
|
81
|
+
# Gives the JDBC driver a hint of the number of rows to fetch from the database by a single interaction.
|
82
|
+
# This is only a hint. It may no effect at all.
|
83
|
+
# @return [NilClass]
|
84
|
+
def set_fetch_size(fsz)
|
85
|
+
check_closed
|
86
|
+
|
87
|
+
@fetch_size = fsz
|
88
|
+
@java_obj.set_fetch_size fsz
|
89
|
+
end
|
90
|
+
alias fetch_size= set_fetch_size
|
91
|
+
|
92
|
+
# Returns the fetch size of the prepared statement. If not set, nil is returned.
|
93
|
+
# @return [Fixnum]
|
94
|
+
attr_reader :fetch_size
|
95
95
|
private
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
96
|
+
def set_params(params) # :nodoc:
|
97
|
+
params.each_with_index do | param, idx |
|
98
|
+
set_param(idx + 1, param)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def initialize(*args)
|
103
|
+
super(*args)
|
104
|
+
end
|
105
105
|
end#PreparedStatment
|
106
106
|
end#Connection
|
107
107
|
end#JDBCHelper
|
@@ -1,115 +1,126 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
# Junegunn Choi (junegunn.c@gmail.com)
|
3
3
|
|
4
|
+
require 'bigdecimal'
|
5
|
+
|
4
6
|
module JDBCHelper
|
5
7
|
class Connection
|
6
8
|
# Class for enumerating query results.
|
7
9
|
# Automatically closed after used. When not used, you must close it explicitly by calling "close".
|
8
10
|
class ResultSetEnumerator
|
9
|
-
|
11
|
+
include Enumerable
|
10
12
|
|
11
|
-
|
12
|
-
|
13
|
+
def each
|
14
|
+
return if closed?
|
13
15
|
|
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
|
-
|
16
|
+
count = -1
|
17
|
+
begin
|
18
|
+
while @rset.next
|
19
|
+
idx = 0
|
20
|
+
# Oracle returns numbers in NUMERIC type, which can be of any precision.
|
21
|
+
# So, we retrieve the numbers in String type not to lose their precision.
|
22
|
+
# This can be quite annoying when you're just working with integers,
|
23
|
+
# so I tried the following code to automatically convert integer string into integer
|
24
|
+
# when it's obvious. However, the performance drop is untolerable.
|
25
|
+
# Thus, commented out.
|
26
|
+
#
|
27
|
+
# if v && @cols_meta[i-1] == java.sql.Types::NUMERIC && v !~ /[\.e]/i
|
28
|
+
# v.to_i
|
29
|
+
# else
|
30
|
+
# v
|
31
|
+
# end
|
32
|
+
yield Connection::Row.new(
|
33
|
+
@col_labels,
|
34
|
+
@col_labels_d,
|
35
|
+
@getters.map { |gt|
|
36
|
+
case gt
|
37
|
+
when :getBigNum
|
38
|
+
v = @rset.getBigDecimal idx+=1
|
39
|
+
@rset.was_null ? nil : BigDecimal.new(v.toPlainString).to_i
|
40
|
+
when :getBigDecimal
|
41
|
+
v = @rset.getBigDecimal idx+=1
|
42
|
+
@rset.was_null ? nil : BigDecimal.new(v.toPlainString)
|
43
|
+
else
|
44
|
+
v = @rset.send gt, idx+=1
|
45
|
+
@rset.was_null ? nil : v
|
46
|
+
end
|
47
|
+
},
|
48
|
+
count += 1)
|
49
|
+
end
|
50
|
+
ensure
|
51
|
+
close
|
52
|
+
end
|
53
|
+
end
|
43
54
|
|
44
|
-
|
45
|
-
|
55
|
+
def close
|
56
|
+
return if closed?
|
46
57
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
58
|
+
@rset.close
|
59
|
+
@close_callback.call if @close_callback
|
60
|
+
@closed = true
|
61
|
+
end
|
51
62
|
|
52
|
-
|
53
|
-
|
54
|
-
|
63
|
+
def closed?
|
64
|
+
@closed
|
65
|
+
end
|
55
66
|
|
56
67
|
private
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
68
|
+
def initialize(rset, &close_callback) # :nodoc:
|
69
|
+
unless rset.respond_to? :get_meta_data
|
70
|
+
rset.close if rset
|
71
|
+
@closed = true
|
72
|
+
return
|
73
|
+
end
|
63
74
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
75
|
+
@close_callback = close_callback
|
76
|
+
@rset = rset
|
77
|
+
@rsmd = @rset.get_meta_data
|
78
|
+
@num_col = @rsmd.get_column_count
|
79
|
+
@getters = []
|
80
|
+
@col_labels = []
|
81
|
+
@col_labels_d = []
|
82
|
+
(1..@num_col).each do | i |
|
83
|
+
type = @rsmd.get_column_type(i)
|
73
84
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
85
|
+
@getters <<
|
86
|
+
case type
|
87
|
+
when java.sql.Types::NUMERIC, java.sql.Types::DECIMAL
|
88
|
+
precision = @rsmd.get_precision(i)
|
89
|
+
scale = @rsmd.get_scale(i)
|
79
90
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
91
|
+
if precision > 0 && scale >= 0
|
92
|
+
# Numbers with fractional parts
|
93
|
+
if scale > 0
|
94
|
+
if precision <= 15
|
95
|
+
:getDouble
|
96
|
+
else
|
97
|
+
:getBigDecimal
|
98
|
+
end
|
99
|
+
# Numbers without fractional parts
|
100
|
+
else
|
101
|
+
if precision <= 9
|
102
|
+
:getInt
|
103
|
+
elsif precision <= 18
|
104
|
+
:getLong
|
105
|
+
else
|
106
|
+
:getBigNum
|
107
|
+
end
|
108
|
+
end
|
109
|
+
# No guarantee
|
110
|
+
else
|
111
|
+
:getBigDecimal
|
112
|
+
end
|
113
|
+
else
|
114
|
+
JDBCHelper::Connection::GETTER_MAP.fetch(type, :get_string)
|
115
|
+
end
|
105
116
|
|
106
|
-
|
107
|
-
|
117
|
+
@col_labels << @rsmd.get_column_label(i)
|
118
|
+
@col_labels_d << @col_labels.last.downcase
|
108
119
|
|
109
|
-
|
120
|
+
end
|
110
121
|
|
111
|
-
|
112
|
-
|
122
|
+
@closed = false
|
123
|
+
end
|
113
124
|
end#ResultSetEnumerator
|
114
125
|
end#Connection
|
115
126
|
end#JDBCHelper
|