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.
@@ -1,11 +1,19 @@
1
1
  # encoding: UTF-8
2
2
  # Junegunn Choi (junegunn.c@gmail.com)
3
3
 
4
- require 'jdbc-helper/connection/statement_pool'
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
- return @pstmts[qstr] if @pstmts.has_key? qstr
180
+ PreparedStatement.send(:new, self, qstr,
181
+ measure_exec(:prepare) { @conn.prepare_statement(qstr) })
182
+ end
174
183
 
175
- pstmt = PreparedStatement.send(:new, self, @pstmts, qstr,
176
- measure_exec(:prepare) { @conn.prepare_statement(qstr) })
177
- @pstmts[qstr] = pstmt
178
- pstmt
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
- # @param [String] table_name Name of the table to be wrapped
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
@@ -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
- check(where_internal conds)
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 = make_where(data_hash.delete :where)
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 "select * from #{table}#{make_where conds}"
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}#{make_where conds}"
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}#{make_where conds}"
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
- test = expr.gsub(/'[^']*'/, '').gsub(/`[^`]*`/, '').gsub(/"[^"]*"/, '')
84
- raise ArgumentError.new("Expression cannot contain semi-colons: #{test}") if test.include?(';')
85
- raise ArgumentError.new("Expression cannot contain comments: #{test}") if test.match(%r{--|/\*|\*/})
86
- raise ArgumentError.new("Unclosed quotation mark: #{test}") if test.match(/['"`]/)
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 nil if conds.nil?
105
-
106
- case conds
107
- when String
108
- return nil if conds.strip.empty?
109
- conds
110
- when Hash
111
- return nil if conds.empty?
112
- conds.map { |k, v|
113
- "#{k} " +
114
- case v
115
- when NilClass
116
- "is null"
117
- when NotNilClass
118
- "is not null"
119
- when Fixnum, Bignum, Float, JDBCHelper::SQL::Expr
120
- "= #{v}"
121
- when Range
122
- ">= #{v.first} and #{k} <#{'=' unless v.exclude_end?} #{v.last}"
123
- when Array
124
- "in (" +
125
- v.map { |e|
126
- case e
127
- when String
128
- "'#{esc e}'"
129
- else
130
- e
131
- end }.join(', ') + ")"
132
- when String
133
- "= '#{esc v}'"
134
- else
135
- raise NotImplementedError.new("Unsupported class: #{v.class}")
136
- end
137
- }.join(' and ')
138
- else
139
- raise NotImplementedError.new("Parameter to where must be either Hash or String")
140
- end
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
@@ -16,7 +16,6 @@ module JavaSql # :nodoc:
16
16
  end
17
17
 
18
18
  require 'jdbc-helper/sql'
19
- require 'jdbc-helper/object_wrapper'
20
19
  require 'jdbc-helper/constants'
21
20
  require 'jdbc-helper/connection'
22
21
  require 'jdbc-helper/connector'
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: mysql
5
+ user: root
6
6
  password:
7
- database: test
8
7
 
9
- # oracle:
10
- # driver: com.mysql.jdbc.Driver
11
- # url: jdbc:oracle:thin:@localhost/test
12
- # user: test
13
- # password:
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
@@ -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, conn_info |
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
 
@@ -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 db == 'mysql'
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 db == 'oracle'
23
- host = conn_info['url'].match(%r{//(.*?)/})[1]
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