jdbc-helper 0.2.1 → 0.3.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.rdoc +80 -19
- data/lib/jdbc-helper/connection/callable_statement.rb +75 -0
- data/lib/jdbc-helper/connection/parameterized_statement.rb +64 -0
- data/lib/jdbc-helper/connection/prepared_statement.rb +13 -75
- data/lib/jdbc-helper/connection/result_set_enumerator.rb +24 -38
- data/lib/jdbc-helper/connection/row.rb +2 -2
- data/lib/jdbc-helper/connection/type_map.rb +72 -0
- data/lib/jdbc-helper/connection.rb +38 -9
- data/lib/jdbc-helper/sql.rb +67 -55
- data/lib/jdbc-helper/wrapper/function_wrapper.rb +26 -0
- data/lib/jdbc-helper/wrapper/object_wrapper.rb +32 -0
- data/lib/jdbc-helper/wrapper/procedure_wrapper.rb +28 -0
- data/lib/jdbc-helper/{object_wrapper.rb → wrapper/table_wrapper.rb} +5 -29
- data/lib/jdbc-helper.rb +0 -1
- data/test/database.yml +6 -8
- data/test/helper.rb +46 -0
- data/test/test_connection.rb +83 -6
- data/test/test_connectors.rb +3 -3
- data/test/test_object_wrapper.rb +53 -9
- data/test/test_performance.rb +21 -1
- data/test/test_sql.rb +29 -15
- metadata +20 -3
@@ -1,11 +1,19 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
# Junegunn Choi (junegunn.c@gmail.com)
|
3
3
|
|
4
|
-
require 'jdbc-helper/connection/
|
4
|
+
require 'jdbc-helper/connection/type_map'
|
5
|
+
require 'jdbc-helper/connection/parameterized_statement'
|
5
6
|
require 'jdbc-helper/connection/prepared_statement'
|
7
|
+
require 'jdbc-helper/connection/callable_statement'
|
8
|
+
require 'jdbc-helper/connection/statement_pool'
|
6
9
|
require 'jdbc-helper/connection/result_set_enumerator'
|
7
10
|
require 'jdbc-helper/connection/row'
|
8
11
|
|
12
|
+
require 'jdbc-helper/wrapper/object_wrapper'
|
13
|
+
require 'jdbc-helper/wrapper/table_wrapper'
|
14
|
+
require 'jdbc-helper/wrapper/function_wrapper'
|
15
|
+
require 'jdbc-helper/wrapper/procedure_wrapper'
|
16
|
+
|
9
17
|
module JDBCHelper
|
10
18
|
# Encapsulates JDBC database connection.
|
11
19
|
# Lets you easily execute SQL statements and access their results.
|
@@ -150,7 +158,6 @@ class Connection
|
|
150
158
|
|
151
159
|
@conn = JavaSql::DriverManager.get_connection(args[:url], props)
|
152
160
|
@spool = StatementPool.send :new, self
|
153
|
-
@pstmts = {}
|
154
161
|
@bstmt = nil
|
155
162
|
|
156
163
|
@stats = Hash.new { | h, k | h[k] = Stat.new(k, 0, 0, 0) }
|
@@ -170,12 +177,17 @@ class Connection
|
|
170
177
|
def prepare(qstr)
|
171
178
|
check_closed
|
172
179
|
|
173
|
-
|
180
|
+
PreparedStatement.send(:new, self, qstr,
|
181
|
+
measure_exec(:prepare) { @conn.prepare_statement(qstr) })
|
182
|
+
end
|
174
183
|
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
184
|
+
# Creates a callable statement.
|
185
|
+
# @param [String] qstr SQL string
|
186
|
+
def prepare_call(qstr)
|
187
|
+
check_closed
|
188
|
+
|
189
|
+
CallableStatement.send(:new, self, qstr,
|
190
|
+
measure_exec(:prepare_call) { @conn.prepare_call qstr })
|
179
191
|
end
|
180
192
|
|
181
193
|
# Executes the given code block as a transaction. Returns true if the transaction is committed.
|
@@ -321,7 +333,6 @@ class Connection
|
|
321
333
|
# @return [NilClass]
|
322
334
|
def close
|
323
335
|
return if closed?
|
324
|
-
@pstmts.each { | q, pstmt | pstmt.close }
|
325
336
|
@spool.close
|
326
337
|
@conn.close
|
327
338
|
@conn = @spool = nil
|
@@ -333,12 +344,30 @@ class Connection
|
|
333
344
|
@conn.nil?
|
334
345
|
end
|
335
346
|
|
336
|
-
#
|
347
|
+
# Returns a table wrapper for the given table name
|
348
|
+
# @since 0.2.0
|
349
|
+
# @param [String/Symbol] table_name Name of the table to be wrapped
|
337
350
|
# @return [JDBCHelper::TableWrapper]
|
338
351
|
def table table_name
|
339
352
|
JDBCHelper::TableWrapper.new self, table_name
|
340
353
|
end
|
341
354
|
|
355
|
+
# Returns a function wrapper for the given function name
|
356
|
+
# @since 0.2.2
|
357
|
+
# @param [String/Symbol] func_name Name of the function to be wrapped
|
358
|
+
# @return [JDBCHelper::FunctionWrapper]
|
359
|
+
def function func_name
|
360
|
+
JDBCHelper::FunctionWrapper.new self, func_name
|
361
|
+
end
|
362
|
+
|
363
|
+
# Returns a procedure wrapper for the given procedure name
|
364
|
+
# @since 0.3.0
|
365
|
+
# @param [String/Symbol] proc_name Name of the procedure to be wrapped
|
366
|
+
# @return [JDBCHelper::ProcedureWrapper]
|
367
|
+
def procedure proc_name
|
368
|
+
JDBCHelper::ProcedureWrapper.new self, proc_name
|
369
|
+
end
|
370
|
+
|
342
371
|
# Statistics
|
343
372
|
class Stat
|
344
373
|
attr_accessor :type, :elapsed, :success_count, :fail_count
|
data/lib/jdbc-helper/sql.rb
CHANGED
@@ -32,7 +32,14 @@ module SQL
|
|
32
32
|
# Generates SQL where cluase with the given conditions.
|
33
33
|
# Parameter can be either Hash of String.
|
34
34
|
def self.where conds
|
35
|
-
|
35
|
+
where_clause = where_internal conds
|
36
|
+
where_clause.empty? ? where_clause : check(where_clause)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Generates SQL order by cluase with the given conditions.
|
40
|
+
def self.order_by *criteria
|
41
|
+
str = criteria.map(&:to_s).reject(&:empty?).join(', ')
|
42
|
+
str.empty? ? str : check('order by ' + str)
|
36
43
|
end
|
37
44
|
|
38
45
|
# SQL Helpers
|
@@ -56,34 +63,45 @@ module SQL
|
|
56
63
|
# Generates update SQL with hash.
|
57
64
|
# :where element of the given hash is taken out to generate where clause.
|
58
65
|
def self.update table, data_hash
|
59
|
-
where_clause =
|
66
|
+
where_clause = where_internal(data_hash.delete :where)
|
60
67
|
updates = data_hash.map { |k, v| "#{k} = #{value v}" }.join(', ')
|
61
|
-
check "update #{table} set #{updates}#{where_clause}"
|
68
|
+
check "update #{table} set #{updates} #{where_clause}".strip
|
62
69
|
end
|
63
70
|
|
64
71
|
# Generates select * SQL with the given conditions
|
65
|
-
def self.select table, conds = nil
|
66
|
-
check
|
72
|
+
def self.select table, conds = nil, orders = nil
|
73
|
+
check [
|
74
|
+
"select * from #{table}",
|
75
|
+
where_internal(conds),
|
76
|
+
order_by(orders)
|
77
|
+
].reject(&:empty?).join(' ')
|
67
78
|
end
|
68
79
|
|
69
80
|
# Generates count SQL with the given conditions
|
70
81
|
def self.count table, conds = nil
|
71
|
-
check "select count(*) from #{table}#{
|
82
|
+
check "select count(*) from #{table} #{where_internal conds}".strip
|
72
83
|
end
|
73
84
|
|
74
85
|
# Generates delete SQL with the given conditions
|
75
86
|
def self.delete table, conds = nil
|
76
|
-
check "delete from #{table}#{
|
87
|
+
check "delete from #{table} #{where_internal conds}".strip
|
77
88
|
end
|
78
89
|
|
79
90
|
# FIXME: Naive protection for SQL Injection
|
80
|
-
def self.check expr
|
91
|
+
def self.check expr, is_name = false
|
81
92
|
return nil if expr.nil?
|
82
93
|
|
83
|
-
|
84
|
-
|
85
|
-
raise ArgumentError.new("
|
86
|
-
raise ArgumentError.new("
|
94
|
+
tag = is_name ? 'Object name' : 'Expression'
|
95
|
+
test = expr.gsub(/'[^']*'/, '').gsub(/`[^`]*`/, '').gsub(/"[^"]*"/, '').strip
|
96
|
+
raise ArgumentError.new("#{tag} cannot contain (unquoted) semi-colons: #{expr}") if test.include?(';')
|
97
|
+
raise ArgumentError.new("#{tag} cannot contain (unquoted) comments: #{expr}") if test.match(%r{--|/\*|\*/})
|
98
|
+
raise ArgumentError.new("Unclosed quotation mark: #{expr}") if test.match(/['"`]/)
|
99
|
+
raise ArgumentError.new("#{tag} is blank") if test.empty?
|
100
|
+
|
101
|
+
if is_name
|
102
|
+
raise ArgumentError.new(
|
103
|
+
"#{tag} cannot contain (unquoted) parentheses: #{expr}") if test.match(%r{\(|\)})
|
104
|
+
end
|
87
105
|
|
88
106
|
return expr
|
89
107
|
end
|
@@ -93,51 +111,45 @@ private
|
|
93
111
|
str.gsub("'", "''")
|
94
112
|
end
|
95
113
|
|
96
|
-
def self.make_where conds
|
97
|
-
str = where_internal conds
|
98
|
-
str = ' where ' + str if str
|
99
|
-
str
|
100
|
-
end
|
101
|
-
|
102
114
|
# No check
|
103
115
|
def self.where_internal conds
|
104
|
-
return
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
116
|
+
return '' if conds.nil?
|
117
|
+
|
118
|
+
where =
|
119
|
+
case conds
|
120
|
+
when String
|
121
|
+
conds.strip
|
122
|
+
when Hash
|
123
|
+
conds.map { |k, v|
|
124
|
+
"#{k} " +
|
125
|
+
case v
|
126
|
+
when NilClass
|
127
|
+
"is null"
|
128
|
+
when NotNilClass
|
129
|
+
"is not null"
|
130
|
+
when Fixnum, Bignum, Float, JDBCHelper::SQL::Expr
|
131
|
+
"= #{v}"
|
132
|
+
when Range
|
133
|
+
">= #{v.first} and #{k} <#{'=' unless v.exclude_end?} #{v.last}"
|
134
|
+
when Array
|
135
|
+
"in (" +
|
136
|
+
v.map { |e|
|
137
|
+
case e
|
138
|
+
when String
|
139
|
+
"'#{esc e}'"
|
140
|
+
else
|
141
|
+
e
|
142
|
+
end }.join(', ') + ")"
|
143
|
+
when String
|
144
|
+
"= '#{esc v}'"
|
145
|
+
else
|
146
|
+
raise NotImplementedError.new("Unsupported class: #{v.class}")
|
147
|
+
end
|
148
|
+
}.join(' and ')
|
149
|
+
else
|
150
|
+
raise NotImplementedError.new("Parameter to where must be either Hash or String")
|
151
|
+
end
|
152
|
+
where.empty? ? '' : 'where ' + where
|
141
153
|
end
|
142
154
|
|
143
155
|
def self.insert_internal cmd, table, data_hash
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# Junegunn Choi (junegunn.c@gmail.com)
|
3
|
+
|
4
|
+
module JDBCHelper
|
5
|
+
# A wrapper object representing a database function.
|
6
|
+
# @since 0.2.2
|
7
|
+
# @example Usage
|
8
|
+
# conn.function(:coalesce).call(nil, nil, 'king')
|
9
|
+
class FunctionWrapper < ObjectWrapper
|
10
|
+
# Returns the name of the function
|
11
|
+
# @return [String]
|
12
|
+
alias to_s name
|
13
|
+
|
14
|
+
# Returns the result of the function call with the given parameters
|
15
|
+
def call(*args)
|
16
|
+
pstmt = @connection.prepare("select #{name}(#{args.map{'?'}.join ','}) from dual")
|
17
|
+
begin
|
18
|
+
pstmt.query(*args)[0][0]
|
19
|
+
ensure
|
20
|
+
pstmt.close
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end#FunctionWrapper
|
24
|
+
end#JDBCHelper
|
25
|
+
|
26
|
+
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# Junegunn Choi (junegunn.c@gmail.com)
|
3
|
+
|
4
|
+
module JDBCHelper
|
5
|
+
# Abstract base class for wrappers for various database objects.
|
6
|
+
# @abstract
|
7
|
+
# @since 0.2.0
|
8
|
+
# @todo Procedure wrapper with input & output params
|
9
|
+
class ObjectWrapper
|
10
|
+
# Underlying JDBCHelper::Connection object
|
11
|
+
# @return [JDBCHelper::Connection]
|
12
|
+
attr_reader :connection
|
13
|
+
|
14
|
+
# Object name (or expression)
|
15
|
+
# @return [String]
|
16
|
+
attr_reader :name
|
17
|
+
|
18
|
+
# Base constructor.
|
19
|
+
# @param [JDBCHelper::Connection] conn JDBCHelper::Connection object
|
20
|
+
# @param [String/Symbol] name Name of the object to be wrapped
|
21
|
+
def initialize(conn, name)
|
22
|
+
raise Exception.new(
|
23
|
+
"JDBCHelper::ObjectWrapper is an abstract class") if
|
24
|
+
self.instance_of? ObjectWrapper
|
25
|
+
|
26
|
+
@connection = conn
|
27
|
+
@name = name.to_s
|
28
|
+
JDBCHelper::SQL.check @name, true
|
29
|
+
end
|
30
|
+
end#ObjectWrapper
|
31
|
+
end#JDBCHelper
|
32
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# Junegunn Choi (junegunn.c@gmail.com)
|
3
|
+
|
4
|
+
module JDBCHelper
|
5
|
+
# A wrapper object representing a database procedure.
|
6
|
+
# @since 0.3.0
|
7
|
+
# @example Usage
|
8
|
+
# conn.function(:coalesce).call(nil, nil, 'king')
|
9
|
+
class ProcedureWrapper < ObjectWrapper
|
10
|
+
# Returns the name of the procedure
|
11
|
+
# @return [String]
|
12
|
+
alias to_s name
|
13
|
+
|
14
|
+
# Executes the procedure and returns the values of INOUT & OUT parameters in Hash
|
15
|
+
# @return [Hash]
|
16
|
+
def call(*args)
|
17
|
+
param_count = args.first.kind_of?(Hash) ? args.first.keys.length : args.length
|
18
|
+
|
19
|
+
cstmt = @connection.prepare_call "{call #{name}(#{Array.new(param_count){'?'}.join ', '})}"
|
20
|
+
begin
|
21
|
+
cstmt.call *args
|
22
|
+
ensure
|
23
|
+
cstmt.close
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end#ProcedureWrapper
|
27
|
+
end#JDBCHelper
|
28
|
+
|
@@ -2,33 +2,6 @@
|
|
2
2
|
# Junegunn Choi (junegunn.c@gmail.com)
|
3
3
|
|
4
4
|
module JDBCHelper
|
5
|
-
# Abstract base class for wrappers for various database objects.
|
6
|
-
# @abstract
|
7
|
-
# @since 0.2.0
|
8
|
-
# @todo Need to add more subclasses (such as for functions and procedures)
|
9
|
-
class ObjectWrapper
|
10
|
-
# Underlying JDBCHelper::Connection object
|
11
|
-
# @return [JDBCHelper::Connection]
|
12
|
-
attr_reader :connection
|
13
|
-
|
14
|
-
# Object name (or expression)
|
15
|
-
# @return [String]
|
16
|
-
attr_reader :name
|
17
|
-
|
18
|
-
# Base constructor.
|
19
|
-
# @param [JDBCHelper::Connection] conn JDBCHelper::Connection object
|
20
|
-
# @param [String] name Name of the object to be wrapped
|
21
|
-
def initialize(conn, name)
|
22
|
-
raise Exception.new(
|
23
|
-
"JDBCHelper::ObjectWrapper is an abstract class") if
|
24
|
-
self.instance_of? ObjectWrapper
|
25
|
-
|
26
|
-
@connection = conn
|
27
|
-
@name = name.to_s
|
28
|
-
JDBCHelper::SQL.check @name
|
29
|
-
end
|
30
|
-
end#ObjectWrapper
|
31
|
-
|
32
5
|
# A wrapper object representing a database table. Allows you to perform table operations easily.
|
33
6
|
# @since 0.2.0
|
34
7
|
# @example Usage
|
@@ -47,10 +20,14 @@ end#ObjectWrapper
|
|
47
20
|
# conn.table('test.data').truncate_table!
|
48
21
|
# conn.table('test.data').drop_table!
|
49
22
|
class TableWrapper < ObjectWrapper
|
23
|
+
# Returns the name of the table
|
24
|
+
# @return [String]
|
25
|
+
alias to_s name
|
26
|
+
|
50
27
|
# Retrieves the count of the table
|
51
28
|
# @return [Fixnum] Count of the records.
|
52
29
|
def count(where = nil)
|
53
|
-
@connection.query(JDBCHelper::SQL.count name, where)[0][0]
|
30
|
+
@connection.query(JDBCHelper::SQL.count name, where)[0][0].to_i
|
54
31
|
end
|
55
32
|
|
56
33
|
# Sees if the table is empty
|
@@ -121,6 +98,5 @@ class TableWrapper < ObjectWrapper
|
|
121
98
|
@connection.update(JDBCHelper::SQL.check "drop table #{name}")
|
122
99
|
end
|
123
100
|
end#TableWrapper
|
124
|
-
|
125
101
|
end#JDBCHelper
|
126
102
|
|
data/lib/jdbc-helper.rb
CHANGED
data/test/database.yml
CHANGED
@@ -2,14 +2,12 @@
|
|
2
2
|
mysql:
|
3
3
|
driver: com.mysql.jdbc.Driver
|
4
4
|
url: jdbc:mysql://localhost/test
|
5
|
-
user:
|
5
|
+
user: root
|
6
6
|
password:
|
7
|
-
database: test
|
8
7
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
# database: test
|
8
|
+
oracle:
|
9
|
+
driver: oracle.jdbc.driver.OracleDriver
|
10
|
+
url: jdbc:oracle:thin:@localhost/test
|
11
|
+
user: user
|
12
|
+
password: password
|
15
13
|
|
data/test/helper.rb
CHANGED
@@ -22,9 +22,55 @@ module JDBCHelperTestHelper
|
|
22
22
|
@db_config ||= YAML.load File.read(File.dirname(__FILE__) + '/database.yml')
|
23
23
|
end
|
24
24
|
|
25
|
+
def create_test_procedure conn, name
|
26
|
+
case @type
|
27
|
+
when :mysql
|
28
|
+
conn.update "drop procedure #{name}" rescue nil
|
29
|
+
conn.update("
|
30
|
+
create procedure #{name}
|
31
|
+
(IN i1 varchar(100), IN i2 int,
|
32
|
+
INOUT io1 int, INOUT io2 timestamp,
|
33
|
+
OUT o1 float, OUT o2 varchar(100))
|
34
|
+
select io1 * 10, 0.1, i1 into io1, o1, o2 from dual")
|
35
|
+
when :oracle
|
36
|
+
conn.update "drop procedure #{name}" rescue nil
|
37
|
+
conn.update "
|
38
|
+
create or replace
|
39
|
+
procedure #{name}
|
40
|
+
(i1 in varchar2, i2 in int,
|
41
|
+
io1 in out int, io2 in out date,
|
42
|
+
o1 out float, o2 out varchar2) as
|
43
|
+
begin
|
44
|
+
select io1 * 10, 0.1, i1 into io1, o1, o2 from dual;
|
45
|
+
end;"
|
46
|
+
else
|
47
|
+
raise NotImplementedError.new "Procedure test not implemented for #{@type}"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# This is crazy. But Oracle.
|
52
|
+
def assert_equal *args
|
53
|
+
if args.first.class == Fixnum
|
54
|
+
super(args[0].to_s, args[1].to_s)
|
55
|
+
else
|
56
|
+
super(*args)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
25
60
|
def each_connection(&block)
|
26
61
|
config.each do | db, conn_info |
|
27
62
|
conn = JDBCHelper::Connection.new(conn_info)
|
63
|
+
# Just for quick and dirty testing
|
64
|
+
@type = case conn_info['driver'] || conn_info[:driver]
|
65
|
+
when /mysql/i
|
66
|
+
:mysql
|
67
|
+
when /oracle/i
|
68
|
+
:oracle
|
69
|
+
else
|
70
|
+
p conn_info
|
71
|
+
:unknown
|
72
|
+
end
|
73
|
+
|
28
74
|
begin
|
29
75
|
if block.arity == 1
|
30
76
|
yield conn
|
data/test/test_connection.rb
CHANGED
@@ -7,9 +7,12 @@ class TestConnection < Test::Unit::TestCase
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def teardown
|
10
|
+
conn.update "drop table #{TEST_TABLE}" rescue nil
|
11
|
+
conn.update "drop procedure #{TEST_PROCEDURE}" rescue nil
|
10
12
|
end
|
11
13
|
|
12
14
|
TEST_TABLE = 'tmp_jdbc_helper_test'
|
15
|
+
TEST_PROCEDURE = 'tmp_jdbc_helper_test_proc'
|
13
16
|
|
14
17
|
def get_one_two
|
15
18
|
"
|
@@ -26,8 +29,8 @@ class TestConnection < Test::Unit::TestCase
|
|
26
29
|
assert_equal 1, rec[0]
|
27
30
|
assert_equal 1, rec['one']
|
28
31
|
assert_equal 1, rec[:one]
|
29
|
-
assert_equal [1], rec[0...1]
|
30
|
-
assert_equal [1], rec[0, 1]
|
32
|
+
assert_equal ['1'], rec[0...1].map(&:to_s)
|
33
|
+
assert_equal ['1'], rec[0, 1].map(&:to_s)
|
31
34
|
|
32
35
|
assert_equal 'two', rec.two
|
33
36
|
assert_equal 'two', rec[1]
|
@@ -35,9 +38,9 @@ class TestConnection < Test::Unit::TestCase
|
|
35
38
|
assert_equal ['two'], rec[1..-1]
|
36
39
|
assert_equal ['two'], rec[1, 1]
|
37
40
|
|
38
|
-
assert_equal [1, 'two'], rec[0..1]
|
39
|
-
assert_equal [1, 'two'], rec[0..-1]
|
40
|
-
assert_equal [1, 'two'], rec[0, 2]
|
41
|
+
assert_equal ['1', 'two'], rec[0..1].map(&:to_s)
|
42
|
+
assert_equal ['1', 'two'], rec[0..-1].map(&:to_s)
|
43
|
+
assert_equal ['1', 'two'], rec[0, 2].map(&:to_s)
|
41
44
|
|
42
45
|
assert_raise(NoMethodError) { rec.three }
|
43
46
|
assert_raise(NameError) { rec['three'] }
|
@@ -66,8 +69,10 @@ class TestConnection < Test::Unit::TestCase
|
|
66
69
|
# ---------------------------------------------------------------
|
67
70
|
|
68
71
|
def test_connect_and_close
|
69
|
-
config.each do | db,
|
72
|
+
config.each do | db, conn_info_org |
|
70
73
|
4.times do | i |
|
74
|
+
conn_info = conn_info_org.dup
|
75
|
+
|
71
76
|
# With or without timeout parameter
|
72
77
|
conn_info['timeout'] = 60 if i % 2 == 1
|
73
78
|
|
@@ -197,6 +202,8 @@ class TestConnection < Test::Unit::TestCase
|
|
197
202
|
each_connection do | conn |
|
198
203
|
reset_test_table conn
|
199
204
|
ins = conn.prepare "insert into #{TEST_TABLE} values (?, ?)"
|
205
|
+
assert_equal 2, ins.parameter_count
|
206
|
+
|
200
207
|
count = 100
|
201
208
|
|
202
209
|
# update
|
@@ -289,5 +296,75 @@ class TestConnection < Test::Unit::TestCase
|
|
289
296
|
assert_equal ts.to_i * 1000, got.getTime
|
290
297
|
end
|
291
298
|
end
|
299
|
+
|
300
|
+
# Conditional testing is bad, but
|
301
|
+
# Oracle and MySQL behave differently.
|
302
|
+
def test_callable_statement
|
303
|
+
each_connection do | conn |
|
304
|
+
# Creating test procedure (Defined in JDBCHelperTestHelper)
|
305
|
+
create_test_procedure conn, TEST_PROCEDURE
|
306
|
+
|
307
|
+
# Array parameter
|
308
|
+
cstmt_ord = conn.prepare_call "{call #{TEST_PROCEDURE}(?, ?, ?, ?, ?, ?)}"
|
309
|
+
result = cstmt_ord.call('hello', 10, [100, Fixnum], [Time.now, Time], Float, String)
|
310
|
+
assert_instance_of Hash, result
|
311
|
+
assert_equal 1000, result[3]
|
312
|
+
assert_equal 'hello', result[6]
|
313
|
+
|
314
|
+
# Hash parameter
|
315
|
+
cstmt_name = conn.prepare_call(case @type
|
316
|
+
when :oracle
|
317
|
+
"{call #{TEST_PROCEDURE}(:i1, :i2, :io1, :io2, :o1, :o2)}"
|
318
|
+
else
|
319
|
+
"{call #{TEST_PROCEDURE}(?, ?, ?, ?, ?, ?)}"
|
320
|
+
end)
|
321
|
+
result = cstmt_name.call(
|
322
|
+
:i1 => 'hello', :i2 => 10,
|
323
|
+
:io1 => [100, Fixnum], 'io2' => [Time.now, Time],
|
324
|
+
:o1 => Float, 'o2' => String)
|
325
|
+
assert_instance_of Hash, result
|
326
|
+
assert_equal 1000, result[:io1]
|
327
|
+
assert_equal 'hello', result['o2']
|
328
|
+
|
329
|
+
# Invalid parameters
|
330
|
+
#assert_raise(NativeException) { cstmt_ord.call 1 }
|
331
|
+
assert_raise(ArgumentError) { cstmt_ord.call({}, {}) }
|
332
|
+
assert_raise(NativeException) { cstmt_name.call 1 }
|
333
|
+
assert_raise(ArgumentError) { cstmt_name.call({}, {}) }
|
334
|
+
|
335
|
+
# Close
|
336
|
+
[ cstmt_ord, cstmt_name ].each do | cstmt |
|
337
|
+
assert_equal false, cstmt.closed?
|
338
|
+
cstmt.close
|
339
|
+
assert_equal true, cstmt.closed?
|
340
|
+
assert_raise(RuntimeError) { cstmt.call }
|
341
|
+
end
|
342
|
+
|
343
|
+
# pend('mysql raises data truncation error') do
|
344
|
+
if @type != :mysql
|
345
|
+
cstmt_ord = conn.prepare_call "{call #{TEST_PROCEDURE}(?, 10, ?, ?, ?, ?)}"
|
346
|
+
cstmt_name = conn.prepare_call(case @type
|
347
|
+
when :oracle
|
348
|
+
"{call #{TEST_PROCEDURE}(:i1, 10, :io1, :io2, :o1, :o2)}"
|
349
|
+
else
|
350
|
+
"{call #{TEST_PROCEDURE}(?, 10, ?, ?, ?, ?)}"
|
351
|
+
end)
|
352
|
+
# Hash parameter
|
353
|
+
result = cstmt_name.call(
|
354
|
+
:i1 => 'hello',# :i2 => 10,
|
355
|
+
:io1 => [100, Fixnum], 'io2' => [Time.now, Time],
|
356
|
+
:o1 => Float, 'o2' => String)
|
357
|
+
assert_instance_of Hash, result
|
358
|
+
assert_equal 1000, result[:io1]
|
359
|
+
assert_equal 'hello', result['o2']
|
360
|
+
|
361
|
+
# Array parameter
|
362
|
+
result = cstmt_ord.call('hello', [100, Fixnum], [Time.now, Time], Float, String)
|
363
|
+
assert_instance_of Hash, result
|
364
|
+
assert_equal 1000, result[2]
|
365
|
+
assert_equal 'hello', result[5]
|
366
|
+
end
|
367
|
+
end
|
368
|
+
end
|
292
369
|
end
|
293
370
|
|
data/test/test_connectors.rb
CHANGED
@@ -11,7 +11,7 @@ class TestConnectors < Test::Unit::TestCase
|
|
11
11
|
|
12
12
|
def test_connectors
|
13
13
|
config.each do | db, conn_info |
|
14
|
-
if
|
14
|
+
if conn_info['driver'] =~ /mysql/
|
15
15
|
host = conn_info['url'].match(%r{//(.*?)/})[1]
|
16
16
|
db = conn_info['url'].match(%r{/([^/?]*?)(\?.*)?$})[1]
|
17
17
|
conn = JDBCHelper::MySQLConnector.connect(host, conn_info['user'], conn_info['password'], db)
|
@@ -19,8 +19,8 @@ class TestConnectors < Test::Unit::TestCase
|
|
19
19
|
assert conn.closed? == false
|
20
20
|
conn.close
|
21
21
|
assert conn.closed?
|
22
|
-
elsif
|
23
|
-
host = conn_info['url'].match(%r{
|
22
|
+
elsif conn_info['driver'] =~ /oracle/
|
23
|
+
host = conn_info['url'].match(%r{@(.*?)/})[1]
|
24
24
|
svc = conn_info['url'].match(%r{/([^/?]*?)(\?.*)?$})[1]
|
25
25
|
conn = JDBCHelper::OracleConnector.connect(host, conn_info['user'], conn_info['password'], svc)
|
26
26
|
|