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
@@ -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
|