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