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
@@ -4,34 +4,34 @@
|
|
4
4
|
module JDBCHelper
|
5
5
|
# Shortcut connector for MySQL
|
6
6
|
class MySQLConnector < Connector
|
7
|
-
|
8
|
-
|
7
|
+
include Constants
|
8
|
+
include Constants::Connector
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
10
|
+
# @param [String] host
|
11
|
+
# @param [String] user
|
12
|
+
# @param [String] password
|
13
|
+
# @param [String] db
|
14
|
+
# @param [Fixnum] timeout
|
15
|
+
# @param [Hash] extra_params
|
16
|
+
# @return [JDBCHelper::Connection]
|
17
|
+
def self.connect(host, user, password, db,
|
18
|
+
timeout = DEFAULT_LOGIN_TIMEOUT,
|
19
|
+
extra_params = DEFAULT_PARAMETERS[:mysql], &block)
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
if extra_params && extra_params.is_a?(Hash) == false
|
22
|
+
raise ArgumentError.new('extra_params must be a hash')
|
23
|
+
end
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
25
|
+
conn = Connection.new(
|
26
|
+
(extra_params || {}).merge(
|
27
|
+
:driver => JDBC_DRIVER[:mysql],
|
28
|
+
:url => "jdbc:mysql://#{host}/#{db}",
|
29
|
+
:user => user,
|
30
|
+
:password => password,
|
31
|
+
:timeout => timeout))
|
32
32
|
|
33
|
-
|
34
|
-
|
33
|
+
block_given? ? ensure_close(conn, &block) : conn
|
34
|
+
end
|
35
35
|
end#MySQLConnector
|
36
36
|
end#JDBCHelper
|
37
37
|
|
@@ -4,42 +4,43 @@
|
|
4
4
|
module JDBCHelper
|
5
5
|
# Shortcut connector for Oracle
|
6
6
|
class OracleConnector < Connector
|
7
|
-
|
8
|
-
|
7
|
+
include Constants
|
8
|
+
include Constants::Connector
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
10
|
+
# @param [String] host
|
11
|
+
# @param [String] user
|
12
|
+
# @param [String] password
|
13
|
+
# @param [String] service_name
|
14
|
+
# @param [Fixnum] timeout
|
15
|
+
# @return [JDBCHelper::Connection]
|
16
|
+
def self.connect(host, user, password, service_name, timeout = DEFAULT_LOGIN_TIMEOUT, &block)
|
17
|
+
conn = Connection.new(
|
18
|
+
:driver => JDBC_DRIVER[:oracle],
|
19
|
+
:url => "jdbc:oracle:thin:@#{host}/#{service_name}",
|
20
|
+
:user => user,
|
21
|
+
:password => password,
|
22
|
+
:timeout => timeout)
|
23
23
|
|
24
|
-
|
25
|
-
|
24
|
+
block_given? ? ensure_close(conn, &block) : conn
|
25
|
+
end
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
27
|
+
# @param [String] host
|
28
|
+
# @param [String] user
|
29
|
+
# @param [String] password
|
30
|
+
# @param [String] sid
|
31
|
+
# @param [Fixnum] timeout
|
32
|
+
# @return [JDBCHelper::Connection]
|
33
|
+
# @deprecated
|
34
|
+
def self.connect_by_sid(host, user, password, sid, timeout = DEFAULT_LOGIN_TIMEOUT, &block)
|
35
|
+
conn = Connection.new(
|
36
|
+
:driver => JDBC_DRIVER[:oracle],
|
37
|
+
:url => "jdbc:oracle:thin:@#{host}:#{sid}",
|
38
|
+
:user => user,
|
39
|
+
:password => password,
|
40
|
+
:timeout => timeout)
|
40
41
|
|
41
|
-
|
42
|
-
|
42
|
+
block_given? ? ensure_close(conn, &block) : conn
|
43
|
+
end
|
43
44
|
end#OracleConnector
|
44
45
|
end#JDBCHelper
|
45
46
|
|
@@ -3,24 +3,27 @@
|
|
3
3
|
|
4
4
|
module JDBCHelper
|
5
5
|
module Constants
|
6
|
-
|
7
|
-
|
6
|
+
# Default login timeout is set to 60 seconds
|
7
|
+
DEFAULT_LOGIN_TIMEOUT = 60
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
JDBC_DRIVER = {
|
12
|
-
:oracle => 'oracle.jdbc.driver.OracleDriver',
|
13
|
-
:mysql => 'com.mysql.jdbc.Driver'
|
14
|
-
}
|
9
|
+
# Maximum nesting level for Statements
|
10
|
+
MAX_STATEMENT_NESTING_LEVEL = 20
|
15
11
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
12
|
+
# Constants only for Connectors
|
13
|
+
module Connector
|
14
|
+
JDBC_DRIVER = {
|
15
|
+
:oracle => 'oracle.jdbc.driver.OracleDriver',
|
16
|
+
:mysql => 'com.mysql.jdbc.Driver'
|
17
|
+
}
|
18
|
+
|
19
|
+
DEFAULT_PARAMETERS = {
|
20
|
+
:mysql => {
|
21
|
+
'zeroDateTimeBehavior' => 'convertToNull',
|
22
|
+
'rewriteBatchedStatements' => 'true',
|
23
|
+
'useServerPrepStmts' => 'true',
|
24
|
+
'useCursorFetch' => 'true'
|
25
|
+
}
|
26
|
+
}
|
27
|
+
end#Connector
|
25
28
|
end#Constants
|
26
29
|
end#JDBCHelper
|
data/lib/jdbc-helper/sql.rb
CHANGED
@@ -7,199 +7,192 @@ module JDBCHelper
|
|
7
7
|
# @param [String] SQL snippet
|
8
8
|
# @return [JDBCHelper::SQL]
|
9
9
|
def self.sql str
|
10
|
-
|
10
|
+
JDBCHelper::SQL.new str
|
11
11
|
end
|
12
12
|
class << self
|
13
|
-
|
13
|
+
alias_method :SQL, :sql
|
14
14
|
end
|
15
15
|
|
16
16
|
# Class representing an SQL snippet. Also has many SQL generator class methods.
|
17
17
|
class SQL
|
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
|
-
|
18
|
+
# Returns NotNilClass singleton object
|
19
|
+
# @return [JDBCHelper::SQL::NotNilClass]
|
20
|
+
def self.not_nil
|
21
|
+
NotNilClass.singleton
|
22
|
+
end
|
23
|
+
class << self
|
24
|
+
alias not_null not_nil
|
25
|
+
end
|
26
|
+
|
27
|
+
# Formats the given data so that it can be injected into SQL
|
28
|
+
def self.value data
|
29
|
+
case data
|
30
|
+
when NilClass
|
31
|
+
'null'
|
32
|
+
when Fixnum, Bignum, Float
|
33
|
+
data
|
34
|
+
when BigDecimal
|
35
|
+
data.to_s("F")
|
36
|
+
when JDBCHelper::SQL
|
37
|
+
data.to_s
|
38
|
+
when String
|
39
|
+
"'#{esc data}'"
|
40
|
+
else
|
41
|
+
raise NotImplementedError.new("Unsupported datatype: #{data.class}")
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Generates SQL where cluase with the given conditions.
|
46
|
+
# Parameter can be either Hash of String.
|
47
|
+
def self.where *conds
|
48
|
+
where_clause = where_internal conds
|
49
|
+
where_clause.empty? ? where_clause : check(where_clause)
|
50
|
+
end
|
49
51
|
|
50
52
|
def self.where_prepared *conds
|
51
53
|
end
|
52
54
|
|
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
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
55
|
+
# Generates SQL order by cluase with the given conditions.
|
56
|
+
def self.order *criteria
|
57
|
+
str = criteria.map(&:to_s).reject(&:empty?).join(', ')
|
58
|
+
str.empty? ? str : check('order by ' + str)
|
59
|
+
end
|
60
|
+
|
61
|
+
# SQL Helpers
|
62
|
+
# ===========
|
63
|
+
|
64
|
+
# Generates insert SQL with hash
|
65
|
+
def self.insert table, data_hash
|
66
|
+
insert_internal 'insert', table, data_hash
|
67
|
+
end
|
68
|
+
|
69
|
+
# Generates insert ignore SQL (Non-standard syntax)
|
70
|
+
def self.insert_ignore table, data_hash
|
71
|
+
insert_internal 'insert ignore', table, data_hash
|
72
|
+
end
|
73
|
+
|
74
|
+
# Generates replace SQL (Non-standard syntax)
|
75
|
+
def self.replace table, data_hash
|
76
|
+
insert_internal 'replace', table, data_hash
|
77
|
+
end
|
78
|
+
|
79
|
+
# Generates update SQL with hash.
|
80
|
+
# :where element of the given hash is taken out to generate where clause.
|
81
|
+
def self.update table, data_hash, where
|
82
|
+
where_clause = where_internal where
|
83
|
+
updates = data_hash.map { |k, v| "#{k} = #{value v}" }.join(', ')
|
84
|
+
check "update #{table} set #{updates} #{where_clause}".strip
|
85
|
+
end
|
86
|
+
|
87
|
+
# Generates select SQL with the given conditions
|
88
|
+
def self.select table, opts = {}
|
89
|
+
opts = opts.reject { |k, v| v.nil? }
|
90
|
+
check [
|
91
|
+
"select #{opts.fetch(:select, ['*']).join(', ')} from #{table}",
|
92
|
+
where_internal(opts.fetch(:where, {})),
|
93
|
+
order(opts.fetch(:order, []).join(', '))
|
94
|
+
].reject(&:empty?).join(' ')
|
95
|
+
end
|
96
|
+
|
97
|
+
# Generates count SQL with the given conditions
|
98
|
+
def self.count table, conds = nil
|
99
|
+
check "select count(*) from #{table} #{where_internal conds}".strip
|
100
|
+
end
|
101
|
+
|
102
|
+
# Generates delete SQL with the given conditions
|
103
|
+
def self.delete table, conds = nil
|
104
|
+
check "delete from #{table} #{where_internal conds}".strip
|
105
|
+
end
|
106
|
+
|
107
|
+
# FIXME: Naive protection for SQL Injection
|
108
|
+
# TODO: check caching?
|
109
|
+
def self.check expr, is_name = false
|
110
|
+
return nil if expr.nil?
|
111
|
+
|
112
|
+
tag = is_name ? 'Object name' : 'Expression'
|
113
|
+
test = expr.gsub(/'[^']*'/, '').gsub(/`[^`]*`/, '').gsub(/"[^"]*"/, '').strip
|
114
|
+
raise ArgumentError.new("#{tag} cannot contain (unquoted) semi-colons: #{expr}") if test.include?(';')
|
115
|
+
raise ArgumentError.new("#{tag} cannot contain (unquoted) comments: #{expr}") if test.match(%r{--|/\*|\*/})
|
116
|
+
raise ArgumentError.new("Unclosed quotation mark: #{expr}") if test.match(/['"`]/)
|
117
|
+
raise ArgumentError.new("#{tag} is blank") if test.empty?
|
118
|
+
|
119
|
+
if is_name
|
120
|
+
raise ArgumentError.new(
|
121
|
+
"#{tag} cannot contain (unquoted) parentheses: #{expr}") if test.match(%r{\(|\)})
|
122
|
+
end
|
123
|
+
|
124
|
+
return expr
|
125
|
+
end
|
126
|
+
|
127
|
+
def to_s
|
128
|
+
@expr
|
129
|
+
end
|
128
130
|
|
129
131
|
def == other
|
130
132
|
self.to_s == other.to_s
|
131
133
|
end
|
132
|
-
|
134
|
+
|
133
135
|
def eql? other
|
134
136
|
self.class == other.class && self.to_s == other.to_s
|
135
137
|
end
|
136
|
-
|
138
|
+
|
137
139
|
protected
|
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
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
# Class to represent "(IS) NOT NULL" expression in SQL
|
196
|
-
class NotNilClass
|
197
|
-
# Returns the singleton object of NotNilClass
|
198
|
-
# @return [NotNilClass]
|
199
|
-
def self.singleton
|
200
|
-
@@singleton ||= NotNilClass.new
|
201
|
-
end
|
202
|
-
end
|
140
|
+
def self.esc str
|
141
|
+
str.gsub("'", "''")
|
142
|
+
end
|
143
|
+
|
144
|
+
# No check
|
145
|
+
def self.where_internal conds
|
146
|
+
conds = [conds] unless conds.is_a? Array
|
147
|
+
where_clause = conds.compact.map { |cond| where_unit cond }.reject(&:empty?).join(' and ')
|
148
|
+
where_clause.empty? ? '' : 'where ' + where_clause
|
149
|
+
end
|
150
|
+
|
151
|
+
def self.where_unit conds
|
152
|
+
case conds
|
153
|
+
when String
|
154
|
+
conds = conds.strip
|
155
|
+
conds.empty? ? '' : "(#{conds})"
|
156
|
+
when Hash
|
157
|
+
conds.map { |k, v|
|
158
|
+
"#{k} " +
|
159
|
+
case v
|
160
|
+
when NilClass
|
161
|
+
"is null"
|
162
|
+
when NotNilClass
|
163
|
+
"is not null"
|
164
|
+
when Fixnum, Bignum, Float, JDBCHelper::SQL, String
|
165
|
+
"= #{value v}"
|
166
|
+
when Range
|
167
|
+
">= #{v.first} and #{k} <#{'=' unless v.exclude_end?} #{v.last}"
|
168
|
+
when Array
|
169
|
+
"in (#{ v.map { |e| value(e) }.join(', ') })"
|
170
|
+
else
|
171
|
+
raise NotImplementedError.new("Unsupported class: #{v.class}")
|
172
|
+
end
|
173
|
+
}.join(' and ')
|
174
|
+
else
|
175
|
+
raise NotImplementedError.new("Parameter to where must be either Hash or String")
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def self.insert_internal cmd, table, data_hash
|
180
|
+
cols = data_hash.keys
|
181
|
+
check "#{cmd} into #{table} (#{cols.join ', '}) values (#{cols.map{|c|value data_hash[c]}.join ', '})"
|
182
|
+
end
|
183
|
+
|
184
|
+
def initialize str
|
185
|
+
@expr = JDBCHelper::SQL.check str
|
186
|
+
end
|
187
|
+
|
188
|
+
# Class to represent "(IS) NOT NULL" expression in SQL
|
189
|
+
class NotNilClass
|
190
|
+
# Returns the singleton object of NotNilClass
|
191
|
+
# @return [NotNilClass]
|
192
|
+
def self.singleton
|
193
|
+
@@singleton ||= NotNilClass.new
|
194
|
+
end
|
195
|
+
end
|
203
196
|
end#SQL
|
204
197
|
end#JDBCHelper
|
205
198
|
|