activerecord-jdbc-adapter 5.0.pre1 → 50.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord-jdbc-adapter might be problematic. Click here for more details.

Files changed (66) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -2
  3. data/.travis.yml +15 -416
  4. data/Gemfile +35 -37
  5. data/README.md +23 -118
  6. data/RUNNING_TESTS.md +31 -26
  7. data/Rakefile +2 -3
  8. data/lib/arjdbc/abstract/connection_management.rb +21 -0
  9. data/lib/arjdbc/abstract/core.rb +62 -0
  10. data/lib/arjdbc/abstract/database_statements.rb +46 -0
  11. data/lib/arjdbc/abstract/statement_cache.rb +58 -0
  12. data/lib/arjdbc/abstract/transaction_support.rb +86 -0
  13. data/lib/arjdbc/derby/adapter.rb +6 -1
  14. data/lib/arjdbc/discover.rb +0 -7
  15. data/lib/arjdbc/firebird/adapter.rb +2 -2
  16. data/lib/arjdbc/jdbc.rb +2 -2
  17. data/lib/arjdbc/jdbc/adapter.rb +10 -252
  18. data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
  19. data/lib/arjdbc/jdbc/connection.rb +6 -0
  20. data/lib/arjdbc/mysql/adapter.rb +82 -946
  21. data/lib/arjdbc/mysql/connection_methods.rb +4 -2
  22. data/lib/arjdbc/postgresql/adapter.rb +270 -970
  23. data/lib/arjdbc/postgresql/base/array_decoder.rb +26 -0
  24. data/lib/arjdbc/postgresql/base/array_encoder.rb +25 -0
  25. data/lib/arjdbc/postgresql/base/pgconn.rb +8 -5
  26. data/lib/arjdbc/postgresql/column.rb +10 -599
  27. data/lib/arjdbc/postgresql/connection_methods.rb +9 -0
  28. data/lib/arjdbc/postgresql/name.rb +24 -0
  29. data/lib/arjdbc/postgresql/oid_types.rb +28 -109
  30. data/lib/arjdbc/sqlite3/adapter.rb +18 -42
  31. data/lib/arjdbc/tasks/database_tasks.rb +1 -3
  32. data/lib/arjdbc/tasks/db2_database_tasks.rb +2 -2
  33. data/lib/arjdbc/version.rb +1 -1
  34. data/pom.xml +3 -3
  35. data/rakelib/02-test.rake +0 -12
  36. data/rakelib/compile.rake +1 -1
  37. data/rakelib/db.rake +7 -5
  38. data/rakelib/rails.rake +67 -64
  39. data/src/java/arjdbc/firebird/FirebirdRubyJdbcConnection.java +1 -17
  40. data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +518 -1260
  41. data/src/java/arjdbc/mysql/MySQLModule.java +3 -3
  42. data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +53 -134
  43. data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +214 -240
  44. data/src/java/arjdbc/sqlite3/SQLite3Module.java +0 -20
  45. data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +85 -10
  46. metadata +16 -29
  47. data/Appraisals +0 -41
  48. data/lib/active_record/connection_adapters/oracle_adapter.rb +0 -1
  49. data/lib/arjdbc/common_jdbc_methods.rb +0 -89
  50. data/lib/arjdbc/mysql/bulk_change_table.rb +0 -150
  51. data/lib/arjdbc/mysql/column.rb +0 -162
  52. data/lib/arjdbc/mysql/explain_support.rb +0 -82
  53. data/lib/arjdbc/mysql/schema_creation.rb +0 -58
  54. data/lib/arjdbc/oracle.rb +0 -4
  55. data/lib/arjdbc/oracle/adapter.rb +0 -952
  56. data/lib/arjdbc/oracle/column.rb +0 -126
  57. data/lib/arjdbc/oracle/connection_methods.rb +0 -21
  58. data/lib/arjdbc/postgresql/base/oid.rb +0 -412
  59. data/lib/arjdbc/postgresql/base/schema_definitions.rb +0 -131
  60. data/lib/arjdbc/postgresql/explain_support.rb +0 -53
  61. data/lib/arjdbc/postgresql/oid/bytea.rb +0 -2
  62. data/lib/arjdbc/postgresql/schema_creation.rb +0 -60
  63. data/lib/arjdbc/tasks/oracle/enhanced_structure_dump.rb +0 -297
  64. data/lib/arjdbc/tasks/oracle_database_tasks.rb +0 -65
  65. data/src/java/arjdbc/oracle/OracleModule.java +0 -75
  66. data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +0 -465
@@ -1,77 +1,80 @@
1
- namespace :rails do
2
-
3
- task :test do
4
- raise "need a DRIVER e.g. DRIVER=mysql" unless driver = ENV['DRIVER'] || ENV['ADAPTER']
5
- raise "need location of RAILS source code e.g. RAILS=../rails" unless rails_dir = ENV['RAILS']
6
- rails_dir = File.join(rails_dir, '..') if rails_dir =~ /activerecord$/
7
- activerecord_dir = File.join(rails_dir, 'activerecord') # rails/activerecord
1
+ DEFAULT_RAILS_DIR = File.join('..', 'rails')
2
+ DEFAULT_ADAPTERS = %w(MySQL SQLite3 Postgres)
8
3
 
9
- ar_jdbc_dir = File.expand_path('..', File.dirname(__FILE__))
10
-
11
- ruby_lib = [
12
- "#{ar_jdbc_dir}/lib",
13
- "#{ar_jdbc_dir}/test/rails",
14
- "#{ar_jdbc_dir}/jdbc-#{_driver(driver)}/lib",
15
- "#{ar_jdbc_dir}/activerecord-jdbc#{_adapter(driver)}-adapter/lib"
16
- ]
17
- ruby_lib << File.expand_path('activesupport/lib', rails_dir)
18
- ruby_lib << File.expand_path('activemodel/lib', rails_dir)
19
- ruby_lib << File.expand_path(File.join(activerecord_dir, 'lib'))
20
- requires = _requires(driver) || []
4
+ namespace :rails do
5
+ namespace :test do
6
+ task :all do
7
+ driver = ENV['DRIVER'] || ENV['ADAPTER']
8
+ raise "need a DRIVER (DRIVER=mysql)" unless driver
9
+ rails_dir = _rails_dir
10
+ ENV['ARCONFIG'] = File.join(_ar_jdbc_dir, 'test', 'rails', 'config.yml')
21
11
 
22
- Dir.chdir(activerecord_dir) do
23
- ruby = FileUtils::RUBY
24
- rubylib = ruby_lib.join(':') # i_lib = "-I#{rubylib}"
25
- r_requires = requires.map { |feat| "-r#{feat}" }.join(' ')
26
- sh "#{ruby} -S rake RUBYLIB=#{rubylib} RUBYOPT=\"#{r_requires}\" #{_target(driver)}"
12
+ Dir.chdir(File.join(rails_dir, 'activerecord')) do
13
+ sh FileUtils::RUBY, '-S', 'rake',
14
+ "RUBYLIB=#{_ruby_lib(rails_dir, driver)}",
15
+ _target(driver)
16
+ end
27
17
  end
28
- end
29
-
30
- %w(MySQL SQLite3 Postgres).each do |adapter|
31
- desc "Run Rails' ActiveRecord tests with #{adapter} (JDBC)"
32
- task "test_#{adapter.downcase}" do
33
- ENV['ADAPTER'] = adapter; Rake::Task['rails:test'].invoke
18
+
19
+ DEFAULT_ADAPTERS.each do |adapter|
20
+ desc "Run Rails ActiveRecord tests with #{adapter} (JDBC)"
21
+ task adapter.downcase do
22
+ ENV['ADAPTER'] = adapter
23
+ Rake::Task['rails:test:all'].invoke
24
+ end
25
+
26
+ namespace adapter.downcase do
27
+ desc "Runs Rails ActiveRecord base_test.rb with #{adapter}"
28
+ task "base_test" do
29
+ ENV['TEST'] ||= "test/cases/base_test.rb"
30
+ ENV['ADAPTER'] = adapter
31
+ Rake::Task['rails:test:all'].invoke
32
+ end
33
+ end
34
34
  end
35
- end
36
-
37
- private
38
-
39
- def _adapter(name)
40
- case name
41
- when /postgres/i
42
- 'postgresql'
43
- else
44
- name.downcase
35
+
36
+ private
37
+
38
+ def _ar_jdbc_dir
39
+ @ar_jdbc_dir ||= File.expand_path('..', File.dirname(__FILE__))
45
40
  end
46
- end
47
41
 
48
- def _driver(name)
49
- case name
50
- when /postgres/i
51
- 'postgres'
52
- else
53
- name.downcase
42
+ def _rails_dir
43
+ rails_dir = ENV['RAILS'] || DEFAULT_RAILS_DIR
44
+ unless File.directory? rails_dir
45
+ raise "can't find RAILS source '#{rails_dir}' (maybe set ENV['RAILS'])"
46
+ end
47
+ rails_dir = File.join(rails_dir, '..') if rails_dir =~ /activerecord$/
48
+ rails_dir
54
49
  end
55
- end
56
50
 
57
- def _target(name)
58
- case name
59
- when /postgres/i
60
- 'test_jdbcpostgresql'
61
- else
62
- "test_jdbc#{name.downcase}"
51
+ def _ruby_lib(rails_dir, driver)
52
+ ar_jdbc_dir = _ar_jdbc_dir
53
+
54
+ if driver =~ /postgres/i
55
+ adapter, driver = 'postgresql', 'postgres'
56
+ else
57
+ adapter = driver.downcase
58
+ driver = adapter
59
+ end
60
+
61
+ [File.join(ar_jdbc_dir, 'lib'),
62
+ File.join(ar_jdbc_dir, 'test', 'rails'),
63
+ File.join(ar_jdbc_dir, "jdbc-#{driver}", 'lib'),
64
+ File.join(ar_jdbc_dir, "activerecord-jdbc#{adapter}-adapter", 'lib'),
65
+ File.expand_path('activesupport/lib', rails_dir),
66
+ File.expand_path('activemodel/lib', rails_dir),
67
+ File.expand_path('activerecord/lib', rails_dir)
68
+ ].join(':')
63
69
  end
64
- end
65
70
 
66
- def _requires(name)
67
- requires = []
68
- requires << 'ubygems'
69
- requires << 'active_support/json' # avoid uninitialized constant BasicsTest::JSON
70
- case name
71
- when /mysql/i
72
- requires << 'mysql' # -rmysql - so Rails tests do not complain about Mysql
71
+ def _target(name)
72
+ case name
73
+ when /postgres/i
74
+ 'test_postgresql'
75
+ else
76
+ "test_jdbc#{name.downcase}"
77
+ end
73
78
  end
74
- requires
75
79
  end
76
-
77
80
  end
@@ -70,27 +70,11 @@ public class FirebirdRubyJdbcConnection extends RubyJdbcConnection {
70
70
  return RubyString.newUnicodeString(runtime, value);
71
71
  }
72
72
 
73
- @Override // booleans are emulated can not setNull(index, Types.BOOLEAN)
74
- protected void setBooleanParameter(final ThreadContext context,
75
- final Connection connection, final PreparedStatement statement,
76
- final int index, final Object value,
77
- final IRubyObject column, final int type) throws SQLException {
78
- if ( value instanceof IRubyObject ) {
79
- setBooleanParameter(context, connection, statement, index, (IRubyObject) value, column, type);
80
- }
81
- else {
82
- if ( value == null ) statement.setNull(index, Types.CHAR);
83
- else {
84
- statement.setBoolean(index, ((Boolean) value).booleanValue());
85
- }
86
- }
87
- }
88
-
89
73
  @Override // booleans are emulated can not setNull(index, Types.BOOLEAN)
90
74
  protected void setBooleanParameter(final ThreadContext context,
91
75
  final Connection connection, final PreparedStatement statement,
92
76
  final int index, final IRubyObject value,
93
- final IRubyObject column, final int type) throws SQLException {
77
+ final IRubyObject attribute, final int type) throws SQLException {
94
78
  if ( value.isNil() ) statement.setNull(index, Types.CHAR);
95
79
  else {
96
80
  statement.setBoolean(index, value.isTrue());
@@ -25,7 +25,6 @@
25
25
  ***** END LICENSE BLOCK *****/
26
26
  package arjdbc.jdbc;
27
27
 
28
- import java.io.ByteArrayInputStream;
29
28
  import java.io.IOException;
30
29
  import java.io.InputStream;
31
30
  import java.io.InputStreamReader;
@@ -80,15 +79,17 @@ import org.jruby.RubySymbol;
80
79
  import org.jruby.RubyTime;
81
80
  import org.jruby.anno.JRubyMethod;
82
81
  import org.jruby.exceptions.RaiseException;
82
+ import org.jruby.ext.bigdecimal.RubyBigDecimal;
83
83
  import org.jruby.javasupport.JavaEmbedUtils;
84
84
  import org.jruby.javasupport.JavaUtil;
85
- import org.jruby.runtime.Arity;
86
85
  import org.jruby.runtime.Block;
86
+ import org.jruby.runtime.Helpers;
87
87
  import org.jruby.runtime.ObjectAllocator;
88
88
  import org.jruby.runtime.ThreadContext;
89
89
  import org.jruby.runtime.backtrace.RubyStackTraceElement;
90
90
  import org.jruby.runtime.builtin.IRubyObject;
91
91
  import org.jruby.util.ByteList;
92
+ import org.jruby.util.TypeConverter;
92
93
 
93
94
  /**
94
95
  * Most of our ActiveRecord::ConnectionAdapters::JdbcConnection implementation.
@@ -121,6 +122,10 @@ public class RubyJdbcConnection extends RubyObject {
121
122
  return getConnectionAdapters(runtime).getClass("JdbcConnection");
122
123
  }
123
124
 
125
+ protected static RubyModule ActiveRecord(ThreadContext context) {
126
+ return context.runtime.getModule("ActiveRecord");
127
+ }
128
+
124
129
  /**
125
130
  * @param runtime
126
131
  * @return <code>ActiveRecord::ConnectionAdapters</code>
@@ -129,22 +134,6 @@ public class RubyJdbcConnection extends RubyObject {
129
134
  return (RubyModule) runtime.getModule("ActiveRecord").getConstant("ConnectionAdapters");
130
135
  }
131
136
 
132
- /**
133
- * @param runtime
134
- * @return <code>ActiveRecord::Result</code>
135
- */
136
- static RubyClass getResult(final Ruby runtime) {
137
- return runtime.getModule("ActiveRecord").getClass("Result");
138
- }
139
-
140
- /**
141
- * @param runtime
142
- * @return <code>ActiveRecord::Base</code>
143
- */
144
- protected static RubyClass getBase(final Ruby runtime) {
145
- return runtime.getModule("ActiveRecord").getClass("Base");
146
- }
147
-
148
137
  /**
149
138
  * @param runtime
150
139
  * @return <code>ActiveRecord::ConnectionAdapters::IndexDefinition</code>
@@ -170,42 +159,6 @@ public class RubyJdbcConnection extends RubyObject {
170
159
  return runtime.getModule("ActiveRecord").getClass("JDBCError");
171
160
  }
172
161
 
173
- /**
174
- * @param runtime
175
- * @return <code>ActiveRecord::ConnectionNotEstablished</code>
176
- */
177
- protected static RubyClass getConnectionNotEstablished(final Ruby runtime) {
178
- return runtime.getModule("ActiveRecord").getClass("ConnectionNotEstablished");
179
- }
180
-
181
- /**
182
- * NOTE: Only available since AR-4.0
183
- * @param runtime
184
- * @return <code>ActiveRecord::TransactionIsolationError</code>
185
- */
186
- protected static RubyClass getTransactionIsolationError(final Ruby runtime) {
187
- return (RubyClass) runtime.getModule("ActiveRecord").getConstant("TransactionIsolationError");
188
- }
189
-
190
- /**
191
- * @param runtime
192
- * @return <code>ActiveRecord::ConnectionAdapters::JdbcTypeConverter</code>
193
- */
194
- private static RubyClass getJdbcTypeConverter(final Ruby runtime) {
195
- return getConnectionAdapters(runtime).getClass("JdbcTypeConverter");
196
- }
197
-
198
- /*
199
- def transaction_isolation_levels
200
- {
201
- read_uncommitted: "READ UNCOMMITTED",
202
- read_committed: "READ COMMITTED",
203
- repeatable_read: "REPEATABLE READ",
204
- serializable: "SERIALIZABLE"
205
- }
206
- end
207
- */
208
-
209
162
  public static int mapTransactionIsolationLevel(IRubyObject isolation) {
210
163
  if ( ! ( isolation instanceof RubySymbol ) ) {
211
164
  isolation = isolation.asString().callMethod("intern");
@@ -244,37 +197,57 @@ public class RubyJdbcConnection extends RubyObject {
244
197
  });
245
198
  }
246
199
 
247
- @JRubyMethod(name = {"begin", "transaction"}, optional = 1) // optional isolation argument for AR-4.0
248
- public IRubyObject begin(final ThreadContext context, final IRubyObject[] args) {
249
- final IRubyObject isolation = args.length > 0 ? args[0] : null;
200
+ @JRubyMethod(name = {"begin", "transaction"}, required = 1) // optional isolation argument for AR-4.0
201
+ public IRubyObject begin(final ThreadContext context, final IRubyObject isolation) {
250
202
  try { // handleException == false so we can handle setTXIsolation
251
203
  return withConnection(context, false, new Callable<IRubyObject>() {
252
204
  public IRubyObject call(final Connection connection) throws SQLException {
253
- connection.setAutoCommit(false);
205
+ return beginTransaction(context, connection, isolation.isNil() ? null : isolation);
206
+ }
207
+ });
208
+ } catch (SQLException e) {
209
+ return handleException(context, e);
210
+ }
211
+ }
254
212
 
255
- if ( isolation != null && ! isolation.isNil() ) {
256
- final int level = mapTransactionIsolationLevel(isolation);
257
- try {
258
- connection.setTransactionIsolation(level);
259
- }
260
- catch (SQLException e) {
261
- RubyClass txError = getTransactionIsolationError(context.getRuntime());
262
- if ( txError != null ) throw wrapException(context, txError, e);
263
- throw e; // let it roll - will be wrapped into a JDBCError (non 4.0)
264
- }
265
- }
266
- return context.getRuntime().getNil();
213
+ @JRubyMethod(name = {"begin", "transaction"}) // optional isolation argument for AR-4.0
214
+ public IRubyObject begin(final ThreadContext context) {
215
+ try { // handleException == false so we can handle setTXIsolation
216
+ return withConnection(context, false, new Callable<IRubyObject>() {
217
+ public IRubyObject call(final Connection connection) throws SQLException {
218
+ return beginTransaction(context, connection, null);
267
219
  }
268
220
  });
221
+ } catch (SQLException e) {
222
+ return handleException(context, e);
223
+ }
224
+ }
225
+
226
+ protected IRubyObject beginTransaction(final ThreadContext context, final Connection connection,
227
+ final IRubyObject isolation) throws SQLException {
228
+ if ( isolation != null ) {
229
+ setTransactionIsolation(context, connection, isolation);
230
+ }
231
+ if ( connection.getAutoCommit() ) connection.setAutoCommit(false);
232
+ return context.nil;
233
+ }
234
+
235
+ protected final void setTransactionIsolation(final ThreadContext context, final Connection connection,
236
+ final IRubyObject isolation) throws SQLException {
237
+ final int level = mapTransactionIsolationLevel(isolation);
238
+ try {
239
+ connection.setTransactionIsolation(level);
269
240
  }
270
241
  catch (SQLException e) {
271
- return handleException(context, e);
242
+ RubyClass txError = ActiveRecord(context).getClass("TransactionIsolationError");
243
+ if ( txError != null ) throw wrapException(context, txError, e);
244
+ throw e; // let it roll - will be wrapped into a JDBCError (non 4.0)
272
245
  }
273
246
  }
274
247
 
275
248
  @JRubyMethod(name = "commit")
276
249
  public IRubyObject commit(final ThreadContext context) {
277
- final Connection connection = getConnection(true);
250
+ final Connection connection = getConnection(context, true);
278
251
  try {
279
252
  if ( ! connection.getAutoCommit() ) {
280
253
  try {
@@ -295,13 +268,13 @@ public class RubyJdbcConnection extends RubyObject {
295
268
 
296
269
  @JRubyMethod(name = "rollback")
297
270
  public IRubyObject rollback(final ThreadContext context) {
298
- final Connection connection = getConnection(true);
271
+ final Connection connection = getConnection(context, true);
299
272
  try {
300
273
  if ( ! connection.getAutoCommit() ) {
301
274
  try {
302
275
  connection.rollback();
303
276
  resetSavepoints(context); // if any
304
- return context.getRuntime().newBoolean(true);
277
+ return context.runtime.getTrue();
305
278
  } finally {
306
279
  connection.setAutoCommit(true);
307
280
  }
@@ -326,7 +299,8 @@ public class RubyJdbcConnection extends RubyObject {
326
299
  @JRubyMethod(name = "create_savepoint", optional = 1)
327
300
  public IRubyObject create_savepoint(final ThreadContext context, final IRubyObject[] args) {
328
301
  IRubyObject name = args.length > 0 ? args[0] : null;
329
- final Connection connection = getConnection(true);
302
+ final Connection connection = getConnection(context, true);
303
+
330
304
  try {
331
305
  connection.setAutoCommit(false);
332
306
 
@@ -358,7 +332,7 @@ public class RubyJdbcConnection extends RubyObject {
358
332
  if ( name == null || name.isNil() ) {
359
333
  throw context.getRuntime().newArgumentError("nil savepoint name given");
360
334
  }
361
- final Connection connection = getConnection(true);
335
+ final Connection connection = getConnection(context, true);
362
336
  try {
363
337
  Savepoint savepoint = getSavepoints(context).get(name);
364
338
  if ( savepoint == null ) {
@@ -374,40 +348,27 @@ public class RubyJdbcConnection extends RubyObject {
374
348
 
375
349
  @JRubyMethod(name = "release_savepoint", required = 1)
376
350
  public IRubyObject release_savepoint(final ThreadContext context, final IRubyObject name) {
377
- if ( name == null || name.isNil() ) {
378
- throw context.getRuntime().newArgumentError("nil savepoint name given");
379
- }
380
- final Connection connection = getConnection(true);
351
+ Ruby runtime = context.runtime;
352
+
353
+ if ( name == null || name.isNil() ) throw runtime.newArgumentError("nil savepoint name given");
354
+
381
355
  try {
382
356
  Object savepoint = getSavepoints(context).remove(name);
383
- if ( savepoint == null ) {
384
- throw context.getRuntime().newRuntimeError("could not release savepoint: '" + name + "' (not set)");
357
+
358
+ if (savepoint == null) {
359
+ RubyClass invalidStatement = ActiveRecord(context).getClass("StatementInvalid");
360
+ throw runtime.newRaiseException(invalidStatement, "could not release savepoint: '" + name + "' (not set)");
385
361
  }
362
+
386
363
  // NOTE: RubyHash.remove does not convert to Java as get does :
387
- if ( ! ( savepoint instanceof Savepoint ) ) {
364
+ if (!( savepoint instanceof Savepoint )) {
388
365
  savepoint = ((IRubyObject) savepoint).toJava(Savepoint.class);
389
366
  }
390
- connection.releaseSavepoint((Savepoint) savepoint);
391
- return context.getRuntime().getNil();
392
- }
393
- catch (SQLException e) {
394
- return handleException(context, e);
395
- }
396
- }
397
367
 
398
- // NOTE: this is iternal API - not to be used by user-code !
399
- @JRubyMethod(name = "marked_savepoint_names")
400
- public IRubyObject marked_savepoint_names(final ThreadContext context) {
401
- if ( hasInstanceVariable("@savepoints") ) {
402
- Map<IRubyObject, Savepoint> savepoints = getSavepoints(context);
403
- final RubyArray names = context.getRuntime().newArray();
404
- for ( Map.Entry<IRubyObject, ?> entry : savepoints.entrySet() ) {
405
- names.add( entry.getKey() ); // keys are RubyString instances
406
- }
407
- return names;
408
- }
409
- else {
410
- return context.getRuntime().newEmptyArray();
368
+ getConnection(context, true).releaseSavepoint((Savepoint) savepoint);
369
+ return runtime.getNil();
370
+ } catch (SQLException e) {
371
+ return handleException(context, e);
411
372
  }
412
373
  }
413
374
 
@@ -465,7 +426,7 @@ public class RubyJdbcConnection extends RubyObject {
465
426
  }
466
427
 
467
428
  private IRubyObject initConnection(final ThreadContext context) throws SQLException {
468
- final IRubyObject jdbcConnection = setConnection( newConnection() );
429
+ final IRubyObject jdbcConnection = setConnection(context, newConnection());
469
430
  final IRubyObject adapter = callMethod("adapter"); // self.adapter
470
431
  if ( ! adapter.isNil() ) {
471
432
  if ( adapter.respondsTo("init_connection") ) {
@@ -481,24 +442,24 @@ public class RubyJdbcConnection extends RubyObject {
481
442
 
482
443
  @JRubyMethod(name = "connection")
483
444
  public IRubyObject connection(final ThreadContext context) {
484
- if ( getConnection(false) == null ) {
445
+ if (getConnection(context, false) == null) {
485
446
  synchronized (this) {
486
- if ( getConnection(false) == null ) {
487
- reconnect(context);
488
- }
447
+ if (getConnection(context, false) == null) reconnect(context);
489
448
  }
490
449
  }
450
+
491
451
  return getInstanceVariable("@connection");
492
452
  }
493
453
 
494
454
  @JRubyMethod(name = "active?", alias = "valid?")
495
455
  public IRubyObject active_p(final ThreadContext context) {
496
456
  IRubyObject connection = getInstanceVariable("@connection");
497
- if ( connection != null && ! connection.isNil() ) {
498
- return isConnectionValid(context, getConnection(false)) ?
499
- context.getRuntime().getTrue() : context.getRuntime().getFalse();
457
+
458
+ if (connection != null && ! connection.isNil()) {
459
+ return context.runtime.newBoolean(isConnectionValid(context, getConnection(context, false)));
500
460
  }
501
- return context.getRuntime().getFalse();
461
+
462
+ return context.runtime.getFalse();
502
463
  }
503
464
 
504
465
  @JRubyMethod(name = "disconnect!")
@@ -515,14 +476,14 @@ public class RubyJdbcConnection extends RubyObject {
515
476
  }
516
477
  runtime.getOut().flush();
517
478
  }
518
- return setConnection(null);
479
+ return setConnection(context, null);
519
480
  }
520
481
 
521
482
  @JRubyMethod(name = "reconnect!")
522
483
  public synchronized IRubyObject reconnect(final ThreadContext context) {
523
484
  try {
524
485
  final Connection connection = newConnection();
525
- final IRubyObject result = setConnection( connection );
486
+ final IRubyObject result = setConnection(context, connection);
526
487
  final IRubyObject adapter = callMethod("adapter");
527
488
  if ( ! adapter.isNil() ) {
528
489
  if ( adapter.respondsTo("configure_connection") ) {
@@ -541,37 +502,40 @@ public class RubyJdbcConnection extends RubyObject {
541
502
 
542
503
  @JRubyMethod(name = { "open?" /* "conn?" */ })
543
504
  public IRubyObject open_p(final ThreadContext context) {
544
- final Connection connection = getConnection(false);
545
- if ( connection == null ) return context.getRuntime().getFalse();
505
+ final Connection connection = getConnection(context, false);
506
+
507
+ if (connection == null) return context.runtime.getFalse();
508
+
546
509
  try {
547
510
  // NOTE: isClosed method generally cannot be called to determine
548
511
  // whether a connection to a database is valid or invalid ...
549
- return context.getRuntime().newBoolean( ! connection.isClosed() );
550
- }
551
- catch (SQLException e) {
512
+ return context.getRuntime().newBoolean(!connection.isClosed());
513
+ } catch (SQLException e) {
552
514
  return handleException(context, e);
553
515
  }
554
516
  }
555
517
 
556
518
  @JRubyMethod(name = "close")
557
519
  public IRubyObject close(final ThreadContext context) {
558
- final Connection connection = getConnection(false);
559
- if ( connection == null ) return context.getRuntime().getFalse();
520
+ final Connection connection = getConnection(context, false);
521
+
522
+ if (connection == null) return context.runtime.getFalse();
523
+
560
524
  try {
561
- final boolean closed = connection.isClosed();
562
- if ( closed ) return context.getRuntime().getFalse();
563
- setConnection(null); // does connection.close();
564
- return context.getRuntime().getTrue();
565
- }
566
- catch (Exception e) {
525
+ if (connection.isClosed()) return context.runtime.getFalse();
526
+
527
+ setConnection(context, null); // does connection.close();
528
+ } catch (Exception e) {
567
529
  debugStackTrace(context, e);
568
- return context.getRuntime().getNil();
530
+ return context.runtime.getNil();
569
531
  }
532
+
533
+ return context.runtime.getTrue();
570
534
  }
571
535
 
572
536
  @JRubyMethod(name = "database_name")
573
537
  public IRubyObject database_name(final ThreadContext context) throws SQLException {
574
- final Connection connection = getConnection(true);
538
+ final Connection connection = getConnection(context, true);
575
539
  String name = connection.getCatalog();
576
540
 
577
541
  if (name == null) {
@@ -591,15 +555,41 @@ public class RubyJdbcConnection extends RubyObject {
591
555
 
592
556
  try {
593
557
  statement = createStatement(context, connection);
594
- if ( doExecute(statement, query) ) {
595
- ResultSet resultSet = statement.getResultSet();
596
- ColumnData[] columns = extractColumns(context.runtime, connection, resultSet, false);
597
558
 
598
- return mapToResult(context, context.runtime, connection, resultSet, columns);
599
- } else {
600
- //return context.runtime.newFixnum( statement.getUpdateCount());
559
+ // For DBs that do support multiple statements, lets return the last result set
560
+ // to be consistent with AR
561
+ boolean hasResultSet = doExecute(statement, query);
562
+ int updateCount = statement.getUpdateCount();
563
+
564
+ ColumnData[] columns = null;
565
+ IRubyObject result = null;
566
+ ResultSet resultSet = null;
567
+
568
+ while (hasResultSet || updateCount != -1) {
569
+
570
+ if (hasResultSet) {
571
+ resultSet = statement.getResultSet();
572
+
573
+ // Unfortunately the result set gets closed when getMoreResults()
574
+ // is called, so we have to process the result sets as we get them
575
+ // this shouldn't be an issue in most cases since we're only getting 1 result set anyways
576
+ columns = extractColumns(context.runtime, connection, resultSet, false);
577
+ result = mapToResult(context, context.runtime, connection, resultSet, columns);
578
+ } else {
579
+ resultSet = null;
580
+ }
581
+
582
+ // Check to see if there is another result set
583
+ hasResultSet = statement.getMoreResults();
584
+ updateCount = statement.getUpdateCount();
585
+ }
586
+
587
+ // Need to check resultSet instead of result because result
588
+ // may have been populated in a previous iteration of the loop
589
+ if (resultSet == null) {
601
590
  return context.runtime.newEmptyArray();
602
- //return mapGeneratedKeysOrUpdateCount(context, connection, statement);
591
+ } else {
592
+ return result;
603
593
  }
604
594
  } catch (final SQLException e) {
605
595
  debugErrorSQL(context, query);
@@ -635,15 +625,7 @@ public class RubyJdbcConnection extends RubyObject {
635
625
  * @throws SQLException
636
626
  */
637
627
  protected boolean doExecute(final Statement statement, final String query) throws SQLException {
638
- return genericExecute(statement, query);
639
- }
640
-
641
- /**
642
- * @deprecated renamed to {@link #doExecute(Statement, String)}
643
- */
644
- @Deprecated
645
- protected boolean genericExecute(final Statement statement, final String query) throws SQLException {
646
- return statement.execute(query); // Statement.RETURN_GENERATED_KEYS
628
+ return statement.execute(query);
647
629
  }
648
630
 
649
631
  @JRubyMethod(name = "execute_insert", required = 1)
@@ -661,7 +643,7 @@ public class RubyJdbcConnection extends RubyObject {
661
643
  return executeUpdate(context, query, true);
662
644
  }
663
645
  else { // we allow prepared statements with empty binds parameters
664
- return executePreparedUpdate(context, query, (List) binds, true);
646
+ return executePreparedUpdate(context, query, (RubyArray) binds, true);
665
647
  }
666
648
  }
667
649
 
@@ -697,16 +679,16 @@ public class RubyJdbcConnection extends RubyObject {
697
679
  return executeUpdate(context, query, false);
698
680
  }
699
681
  else { // we allow prepared statements with empty binds parameters
700
- return executePreparedUpdate(context, query, (List) binds, false);
682
+ return executePreparedUpdate(context, query, (RubyArray) binds, false);
701
683
  }
702
684
  }
703
685
 
704
686
  @JRubyMethod(name = {"execute_prepared_update"}, required = 2)
705
687
  public IRubyObject execute_prepared_update(final ThreadContext context,
706
- final IRubyObject sql, final IRubyObject binds) throws SQLException {
688
+ final IRubyObject sql, final IRubyObject binds) throws SQLException {
707
689
 
708
690
  final String query = sql.convertToString().getUnicodeValue();
709
- return executePreparedUpdate(context, query, (List) binds, false);
691
+ return executePreparedUpdate(context, query, (RubyArray) binds, false);
710
692
  }
711
693
 
712
694
  /**
@@ -745,7 +727,7 @@ public class RubyJdbcConnection extends RubyObject {
745
727
  }
746
728
 
747
729
  private IRubyObject executePreparedUpdate(final ThreadContext context, final String query,
748
- final List<?> binds, final boolean returnGeneratedKeys) {
730
+ final RubyArray binds, final boolean returnGeneratedKeys) {
749
731
  return withConnection(context, new Callable<IRubyObject>() {
750
732
  public IRubyObject call(final Connection connection) throws SQLException {
751
733
  PreparedStatement statement = null;
@@ -774,172 +756,143 @@ public class RubyJdbcConnection extends RubyObject {
774
756
  }
775
757
 
776
758
  /**
777
- * NOTE: since 1.3 this behaves like <code>execute_query</code> in AR-JDBC 1.2
778
- * @param context
779
- * @param sql
780
- * @param block (optional) block to yield row values
781
- * @return raw query result as a name => value Hash (unless block given)
782
- * @throws SQLException
783
- * @see #execute_query_raw(ThreadContext, IRubyObject[], Block)
784
- */
785
- @JRubyMethod(name = "execute_query_raw", required = 1) // optional block
786
- public IRubyObject execute_query_raw(final ThreadContext context,
787
- final IRubyObject sql, final Block block) throws SQLException {
788
- final String query = sql.convertToString().getUnicodeValue();
789
- return executeQueryRaw(context, query, 0, block);
790
- }
791
-
792
- /**
793
- * NOTE: since 1.3 this behaves like <code>execute_query</code> in AR-JDBC 1.2
794
- * @param context
795
- * @param args
796
- * @param block (optional) block to yield row values
797
- * @return raw query result as a name => value Hash (unless block given)
798
- * @throws SQLException
759
+ * This is the same as execute_query but it will return a list of hashes.
760
+ *
761
+ * @see RubyJdbcConnection#execute_query(ThreadContext, IRubyObject[])
762
+ * @param context which context this method is executing on.
763
+ * @param args arguments being supplied to this method.
764
+ * @param block (optional) block to yield row values (Hash(name: value))
765
+ * @return List of Hash(name: value) unless block is given.
766
+ * @throws SQLException when a database error occurs<
799
767
  */
800
- @JRubyMethod(name = "execute_query_raw", required = 2, optional = 1)
801
- // @JRubyMethod(name = "execute_query_raw", required = 1, optional = 2)
768
+ @JRubyMethod(required = 1, optional = 2)
802
769
  public IRubyObject execute_query_raw(final ThreadContext context,
803
770
  final IRubyObject[] args, final Block block) throws SQLException {
804
- // args: (sql), (sql, max_rows), (sql, binds), (sql, max_rows, binds)
805
771
  final String query = args[0].convertToString().getUnicodeValue(); // sql
806
- IRubyObject max_rows = args.length > 1 ? args[1] : null;
807
- IRubyObject binds = args.length > 2 ? args[2] : null;
772
+ final RubyArray binds;
808
773
  final int maxRows;
809
- if ( max_rows == null || max_rows.isNil() ) maxRows = 0;
810
- else {
811
- if ( binds instanceof RubyNumeric ) { // (sql, max_rows)
812
- maxRows = RubyNumeric.fix2int(binds); binds = null;
813
- }
814
- else {
815
- if ( max_rows instanceof RubyNumeric ) {
816
- maxRows = RubyNumeric.fix2int(max_rows);
817
- }
818
- else {
819
- if ( binds == null ) binds = max_rows; // (sql, binds)
774
+
775
+ // args: (sql), (sql, max_rows), (sql, binds), (sql, max_rows, binds)
776
+ switch (args.length) {
777
+ case 2:
778
+ if (args[1] instanceof RubyNumeric) { // (sql, max_rows)
779
+ maxRows = RubyNumeric.fix2int(args[1]);
780
+ binds = null;
781
+ } else { // (sql, binds)
820
782
  maxRows = 0;
783
+ binds = (RubyArray) TypeConverter.checkArrayType(args[1]);
821
784
  }
822
- }
823
- }
824
-
825
- if ( binds == null || binds.isNil() ) { // no prepared statements
826
- return executeQueryRaw(context, query, maxRows, block);
827
- }
828
- else { // we allow prepared statements with empty binds parameters
829
- return executePreparedQueryRaw(context, query, (List) binds, maxRows, block);
785
+ break;
786
+ case 3: // (sql, max_rows, binds)
787
+ maxRows = RubyNumeric.fix2int(args[1]);
788
+ binds = (RubyArray) TypeConverter.checkArrayType(args[2]);
789
+ break;
790
+ default: // (sql) 1-arg
791
+ maxRows = 0;
792
+ binds = null;
793
+ break;
830
794
  }
831
- }
832
-
833
- /**
834
- * @param context
835
- * @param query
836
- * @param maxRows
837
- * @param block
838
- * @return raw query result (in case no block was given)
839
- *
840
- * @see #execute_query_raw(ThreadContext, IRubyObject[], Block)
841
- */
842
- protected IRubyObject executeQueryRaw(final ThreadContext context,
843
- final String query, final int maxRows, final Block block) {
844
- return doExecuteQueryRaw(context, query, maxRows, block, null); // binds == null
845
- }
846
795
 
847
- protected IRubyObject executePreparedQueryRaw(final ThreadContext context,
848
- final String query, final List<?> binds, final int maxRows, final Block block) {
849
796
  return doExecuteQueryRaw(context, query, maxRows, block, binds);
850
797
  }
851
798
 
852
799
  private IRubyObject doExecuteQueryRaw(final ThreadContext context,
853
- final String query, final int maxRows, final Block block, final List<?> binds) {
800
+ final String query, final int maxRows, final Block block, final RubyArray binds) {
854
801
  return withConnection(context, new Callable<IRubyObject>() {
855
802
  public IRubyObject call(final Connection connection) throws SQLException {
856
803
  final Ruby runtime = context.getRuntime();
857
804
 
858
- Statement statement = null; ResultSet resultSet = null;
805
+ Statement statement = null;
806
+ boolean hasResult = false;
859
807
  try {
860
- if ( binds == null ) { // plain statement
808
+ if ( binds == null || binds.isEmpty()) { // plain statement
861
809
  statement = createStatement(context, connection);
862
810
  statement.setMaxRows(maxRows); // zero means there is no limit
863
- resultSet = statement.executeQuery(query);
811
+ hasResult = statement.execute(query);
864
812
  }
865
813
  else {
866
814
  final PreparedStatement prepStatement;
867
815
  statement = prepStatement = connection.prepareStatement(query);
868
816
  statement.setMaxRows(maxRows); // zero means there is no limit
869
817
  setStatementParameters(context, connection, prepStatement, binds);
870
- resultSet = prepStatement.executeQuery();
818
+ hasResult = prepStatement.execute();
871
819
  }
872
820
 
873
- if ( block != null && block.isGiven() ) {
874
- // yield(id1, name1) ... row 1 result data
875
- // yield(id2, name2) ... row 2 result data
876
- return yieldResultRows(context, runtime, connection, resultSet, block);
821
+ if (block.isGiven()) {
822
+ if (hasResult) {
823
+ // yield(id1, name1) ... row 1 result data
824
+ // yield(id2, name2) ... row 2 result data
825
+ return yieldResultRows(context, runtime, connection, statement.getResultSet(), block);
826
+ } else {
827
+ return runtime.getNil();
828
+ }
829
+ } else if (hasResult) {
830
+ return mapToRawResult(context, runtime, connection, statement.getResultSet(), false);
831
+ } else {
832
+ return runtime.newEmptyArray();
877
833
  }
878
-
879
- return mapToRawResult(context, runtime, connection, resultSet, false);
880
834
  }
881
835
  catch (final SQLException e) {
882
836
  debugErrorSQL(context, query);
883
837
  throw e;
884
838
  }
885
- finally { close(resultSet); close(statement); }
839
+ finally {
840
+ close(statement);
841
+ }
886
842
  }
887
843
  });
888
844
  }
889
845
 
890
846
  /**
891
- * Executes a query and returns the (AR) result.
892
- * @param context
893
- * @param sql
894
- * @return raw query result as a name => value Hash (unless block given)
895
- * @throws SQLException
896
- */
897
- @JRubyMethod(name = "execute_query", required = 1)
898
- public IRubyObject execute_query(final ThreadContext context,
899
- final IRubyObject sql) throws SQLException {
900
- final String query = sql.convertToString().getUnicodeValue();
901
- return executeQuery(context, query, 0);
902
- }
903
-
904
- /**
905
- * Executes a query and returns the (AR) result.
906
- * @param context
907
- * @param args
908
- * @return and <code>ActiveRecord::Result</code>
909
- * @throws SQLException
847
+ * Executes a query and returns the (AR) result. There are three parameters:
848
+ * <ul>
849
+ * <li>sql - String of sql</li>
850
+ * <li>max_rows - Integer of how many rows to return</li>
851
+ * <li>binds - Array of bindings for a prepared statement</li>
852
+ * </ul>
853
+ *
854
+ * In true Ruby fashion if there are only two arguments then the last argument
855
+ * may be either max_rows or binds. Note: If you want to force the query to be
856
+ * done using a prepared statement then you must provide an empty array to binds.
857
+ *
858
+ * @param context which context this method is executing on.
859
+ * @param args arguments being supplied to this method.
860
+ * @return a Ruby <code>ActiveRecord::Result</code> instance
861
+ * @throws SQLException when a database error occurs
910
862
  *
911
863
  */
912
- @JRubyMethod(name = "execute_query", required = 2, optional = 1)
913
- // @JRubyMethod(name = "execute_query", required = 1, optional = 2)
914
- public IRubyObject execute_query(final ThreadContext context,
915
- final IRubyObject[] args) throws SQLException {
916
- // args: (sql), (sql, max_rows), (sql, binds), (sql, max_rows, binds)
864
+ @JRubyMethod(required = 1, optional = 2)
865
+ public IRubyObject execute_query(final ThreadContext context, final IRubyObject[] args) throws SQLException {
917
866
  final String query = args[0].convertToString().getUnicodeValue(); // sql
918
- IRubyObject max_rows = args.length > 1 ? args[1] : null;
919
- IRubyObject binds = args.length > 2 ? args[2] : null;
867
+ final RubyArray binds;
920
868
  final int maxRows;
921
- if ( max_rows == null || max_rows.isNil() ) maxRows = 0;
922
- else {
923
- if ( binds instanceof RubyNumeric ) { // (sql, max_rows)
924
- maxRows = RubyNumeric.fix2int(binds); binds = null;
925
- }
926
- else {
927
- if ( max_rows instanceof RubyNumeric ) {
928
- maxRows = RubyNumeric.fix2int(max_rows);
929
- }
930
- else {
931
- if ( binds == null ) binds = max_rows; // (sql, binds)
869
+
870
+ // args: (sql), (sql, max_rows), (sql, binds), (sql, max_rows, binds)
871
+ switch (args.length) {
872
+ case 2:
873
+ if (args[1] instanceof RubyNumeric) { // (sql, max_rows)
874
+ maxRows = RubyNumeric.fix2int(args[1]);
875
+ binds = null;
876
+ } else { // (sql, binds)
932
877
  maxRows = 0;
878
+ binds = (RubyArray) TypeConverter.checkArrayType(args[1]);
933
879
  }
934
- }
880
+ break;
881
+ case 3: // (sql, max_rows, binds)
882
+ maxRows = RubyNumeric.fix2int(args[1]);
883
+ binds = (RubyArray) TypeConverter.checkArrayType(args[2]);
884
+ break;
885
+ default: // (sql) 1-arg
886
+ maxRows = 0;
887
+ binds = null;
888
+ break;
935
889
  }
936
890
 
937
- if ( binds == null || binds.isNil() ) { // no prepared statements
891
+ if (binds != null) { // prepared statement
892
+ return executePreparedQuery(context, query, binds, maxRows);
893
+ } else {
938
894
  return executeQuery(context, query, maxRows);
939
895
  }
940
- else { // we allow prepared statements with empty binds parameters
941
- return executePreparedQuery(context, query, (List) binds, maxRows);
942
- }
943
896
  }
944
897
 
945
898
  @JRubyMethod(name = "execute_prepared_query")
@@ -951,12 +904,10 @@ public class RubyJdbcConnection extends RubyObject {
951
904
  throw context.runtime.newArgumentError("binds exptected to an instance of Array");
952
905
  }
953
906
 
954
- return executePreparedQuery(context, query, (List) binds, 0);
907
+ return executePreparedQuery(context, query, (RubyArray) binds, 0);
955
908
  }
956
909
 
957
910
  /**
958
- * NOTE: This methods behavior changed in AR-JDBC 1.3 the old behavior is
959
- * achievable using {@link #executeQueryRaw(ThreadContext, String, int, Block)}.
960
911
  *
961
912
  * @param context
962
913
  * @param query
@@ -986,42 +937,58 @@ public class RubyJdbcConnection extends RubyObject {
986
937
  });
987
938
  }
988
939
 
989
- @JRubyMethod
990
- public IRubyObject execute_prepared(final ThreadContext context, final IRubyObject sql, final IRubyObject binds) {
940
+ // Called from exec_query in abstract/database_statements
941
+ @JRubyMethod(required = 3)
942
+ public IRubyObject execute_prepared(final ThreadContext context, final IRubyObject sql,
943
+ final IRubyObject binds, final IRubyObject cachedStatement) {
991
944
  return withConnection(context, new Callable<IRubyObject>() {
992
945
  public IRubyObject call(final Connection connection) throws SQLException {
993
- PreparedStatement statement = null;
946
+ final boolean cached = !(cachedStatement == null || cachedStatement.isNil());
994
947
  final String query = sql.convertToString().getUnicodeValue();
995
-
996
- // FIXME: array type check for binds
948
+ PreparedStatement statement = null;
997
949
 
998
950
  try {
999
- statement = connection.prepareStatement(query);
1000
- setStatementParameters(context, connection, statement, (List) binds);
951
+ if (cached) {
952
+ statement = (PreparedStatement) JavaEmbedUtils.rubyToJava(cachedStatement);
953
+ } else {
954
+ statement = connection.prepareStatement(query);
955
+ }
956
+
957
+ setStatementParameters(context, connection, statement, (RubyArray) binds);
1001
958
  boolean hasResultSet = statement.execute();
1002
959
 
1003
960
  if (hasResultSet) {
1004
961
  ResultSet resultSet = statement.getResultSet();
1005
962
  ColumnData[] columns = extractColumns(context.runtime, connection, resultSet, false);
1006
963
 
1007
- return mapToResult(context, context.runtime, connection, resultSet, columns);
964
+ IRubyObject results = mapToResult(context, context.runtime, connection, resultSet, columns);
965
+
966
+ if (cached) {
967
+ // Make sure we free the result set if we are caching the statement
968
+ // It gets closed automatically when the statement is closed if we aren't caching
969
+ resultSet.close();
970
+ }
971
+
972
+ return results;
1008
973
  } else {
1009
974
  return context.runtime.newEmptyArray();
1010
- //return context.runtime.newFixnum( statement.getUpdateCount());
1011
- // return mapGeneratedKeysOrUpdateCount(context, connection, statement);
1012
975
  }
1013
976
  } catch (final SQLException e) {
1014
977
  debugErrorSQL(context, query);
1015
978
  throw e;
1016
979
  } finally {
1017
- close(statement);
980
+ if ( cached ) {
981
+ statement.clearParameters();
982
+ } else {
983
+ close(statement);
984
+ }
1018
985
  }
1019
986
  }
1020
987
  });
1021
988
  }
1022
989
 
1023
990
  protected IRubyObject executePreparedQuery(final ThreadContext context, final String query,
1024
- final List<?> binds, final int maxRows) {
991
+ final RubyArray binds, final int maxRows) {
1025
992
  return withConnection(context, new Callable<IRubyObject>() {
1026
993
  public IRubyObject call(final Connection connection) throws SQLException {
1027
994
  PreparedStatement statement = null; ResultSet resultSet = null;
@@ -1081,7 +1048,7 @@ public class RubyJdbcConnection extends RubyObject {
1081
1048
  @JRubyMethod(name = "supported_data_types")
1082
1049
  public IRubyObject supported_data_types(final ThreadContext context) throws SQLException {
1083
1050
  final Ruby runtime = context.getRuntime();
1084
- final Connection connection = getConnection(true);
1051
+ final Connection connection = getConnection(context, true);
1085
1052
  final ResultSet typeDesc = connection.getMetaData().getTypeInfo();
1086
1053
  final IRubyObject types;
1087
1054
  try {
@@ -1106,7 +1073,7 @@ public class RubyJdbcConnection extends RubyObject {
1106
1073
  return withConnection(context, new Callable<List<RubyString>>() {
1107
1074
  public List<RubyString> call(final Connection connection) throws SQLException {
1108
1075
  final String _tableName = caseConvertIdentifierForJdbc(connection, tableName);
1109
- final TableName table = extractTableName(connection, null, _tableName);
1076
+ final TableName table = extractTableName(connection, null, null, _tableName);
1110
1077
  return primaryKeys(context, connection, table);
1111
1078
  }
1112
1079
  });
@@ -1204,7 +1171,7 @@ public class RubyJdbcConnection extends RubyObject {
1204
1171
  final Ruby runtime = context.getRuntime();
1205
1172
  return withConnection(context, new Callable<RubyBoolean>() {
1206
1173
  public RubyBoolean call(final Connection connection) throws SQLException {
1207
- final TableName components = extractTableName(connection, defaultSchema, tableName);
1174
+ final TableName components = extractTableName(connection, null, defaultSchema, tableName);
1208
1175
  return runtime.newBoolean( tableExists(runtime, connection, components) );
1209
1176
  }
1210
1177
  });
@@ -1223,12 +1190,7 @@ public class RubyJdbcConnection extends RubyObject {
1223
1190
  final String defaultSchema = args.length > 2 ? toStringOrNull(args[2]) : null;
1224
1191
 
1225
1192
  final TableName components;
1226
- if ( catalog == null ) { // backwards-compatibility with < 1.3.0
1227
- components = extractTableName(connection, defaultSchema, tableName);
1228
- }
1229
- else {
1230
- components = extractTableName(connection, catalog, defaultSchema, tableName);
1231
- }
1193
+ components = extractTableName(connection, catalog, defaultSchema, tableName);
1232
1194
 
1233
1195
  if ( ! tableExists(context.getRuntime(), connection, components) ) {
1234
1196
  throw new SQLException("table: " + tableName + " does not exist");
@@ -1277,7 +1239,7 @@ public class RubyJdbcConnection extends RubyObject {
1277
1239
 
1278
1240
  String _tableName = caseConvertIdentifierForJdbc(connection, tableName);
1279
1241
  String _schemaName = caseConvertIdentifierForJdbc(connection, schemaName);
1280
- final TableName table = extractTableName(connection, _schemaName, _tableName);
1242
+ final TableName table = extractTableName(connection, null, _schemaName, _tableName);
1281
1243
 
1282
1244
  final List<RubyString> primaryKeys = primaryKeys(context, connection, table);
1283
1245
 
@@ -1451,53 +1413,6 @@ public class RubyJdbcConnection extends RubyObject {
1451
1413
  });
1452
1414
  }
1453
1415
 
1454
- // NOTE: this seems to be not used ... at all ?!
1455
- /*
1456
- * sql, values (array), types (column.type array), name = nil, pk = nil, id_value = nil, sequence_name = nil
1457
- */
1458
- @Deprecated
1459
- @JRubyMethod(name = "insert_bind", required = 3, rest = true)
1460
- public IRubyObject insert_bind(final ThreadContext context, final IRubyObject[] args) throws SQLException {
1461
- final Ruby runtime = context.getRuntime();
1462
- return withConnection(context, new Callable<IRubyObject>() {
1463
- public IRubyObject call(final Connection connection) throws SQLException {
1464
- final String sql = args[0].convertToString().toString();
1465
- PreparedStatement statement = null;
1466
- try {
1467
- statement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
1468
- setPreparedStatementValues(context, connection, statement, args[1], args[2]);
1469
- statement.executeUpdate();
1470
- return mapGeneratedKeys(runtime, connection, statement);
1471
- }
1472
- finally { close(statement); }
1473
- }
1474
- });
1475
- }
1476
-
1477
- // NOTE: this seems to be not used ... at all ?!
1478
- /*
1479
- * sql, values (array), types (column.type array), name = nil
1480
- */
1481
- @Deprecated
1482
- @JRubyMethod(name = "update_bind", required = 3, rest = true)
1483
- public IRubyObject update_bind(final ThreadContext context, final IRubyObject[] args) throws SQLException {
1484
- final Ruby runtime = context.getRuntime();
1485
- Arity.checkArgumentCount(runtime, args, 3, 4);
1486
- return withConnection(context, new Callable<IRubyObject>() {
1487
- public IRubyObject call(final Connection connection) throws SQLException {
1488
- final String sql = args[0].convertToString().toString();
1489
- PreparedStatement statement = null;
1490
- try {
1491
- statement = connection.prepareStatement(sql);
1492
- setPreparedStatementValues(context, connection, statement, args[1], args[2]);
1493
- statement.executeUpdate();
1494
- }
1495
- finally { close(statement); }
1496
- return runtime.getNil();
1497
- }
1498
- });
1499
- }
1500
-
1501
1416
  @JRubyMethod(name = "with_connection_retry_guard", frame = true)
1502
1417
  public IRubyObject with_connection_retry_guard(final ThreadContext context, final Block block) {
1503
1418
  return withConnection(context, new Callable<IRubyObject>() {
@@ -1562,11 +1477,15 @@ public class RubyJdbcConnection extends RubyObject {
1562
1477
 
1563
1478
  final String sql = "UPDATE "+ tableName +" SET "+ columnName +" = ? WHERE "+ idKey +" = ?" ;
1564
1479
 
1480
+ // TODO: Fix this, the columns don't have the info needed to handle this anymore
1481
+ // currently commented out so that it will compile
1482
+
1565
1483
  return withConnection(context, new Callable<Integer>() {
1566
1484
  public Integer call(final Connection connection) throws SQLException {
1567
1485
  PreparedStatement statement = null;
1568
1486
  try {
1569
1487
  statement = connection.prepareStatement(sql);
1488
+ /*
1570
1489
  if ( binary ) { // blob
1571
1490
  setBlobParameter(context, connection, statement, 1, value, column, Types.BLOB);
1572
1491
  }
@@ -1574,6 +1493,7 @@ public class RubyJdbcConnection extends RubyObject {
1574
1493
  setClobParameter(context, connection, statement, 1, value, column, Types.CLOB);
1575
1494
  }
1576
1495
  setStatementParameter(context, context.getRuntime(), connection, statement, 2, idValue, idColumn);
1496
+ */
1577
1497
  return statement.executeUpdate();
1578
1498
  }
1579
1499
  finally { close(statement); }
@@ -1672,14 +1592,6 @@ public class RubyJdbcConnection extends RubyObject {
1672
1592
  return config.callMethod(context, "[]", keySym);
1673
1593
  }
1674
1594
 
1675
- /**
1676
- * @deprecated renamed to {@link #getConfigValue(ThreadContext, String)}
1677
- */
1678
- @Deprecated
1679
- protected IRubyObject config_value(ThreadContext context, String key) {
1680
- return getConfigValue(context, key);
1681
- }
1682
-
1683
1595
  private static String toStringOrNull(final IRubyObject arg) {
1684
1596
  return arg.isNil() ? null : arg.toString();
1685
1597
  }
@@ -1736,9 +1648,8 @@ public class RubyJdbcConnection extends RubyObject {
1736
1648
  final ThreadContext context, final Ruby runtime,
1737
1649
  final List<IRubyObject> results, final ResultSet resultSet,
1738
1650
  final ColumnData[] columns) throws SQLException {
1739
- final ResultHandler resultHandler = ResultHandler.getInstance(runtime);
1740
1651
  while ( resultSet.next() ) {
1741
- results.add( resultHandler.mapRawRow(context, runtime, columns, resultSet, this) );
1652
+ results.add(mapRawRow(context, runtime, columns, resultSet, this));
1742
1653
  }
1743
1654
  }
1744
1655
 
@@ -1756,14 +1667,13 @@ public class RubyJdbcConnection extends RubyObject {
1756
1667
  final Connection connection, final ResultSet resultSet,
1757
1668
  final ColumnData[] columns) throws SQLException {
1758
1669
 
1759
- final ResultHandler resultHandler = ResultHandler.getInstance(runtime);
1760
1670
  final RubyArray resultRows = runtime.newArray();
1761
1671
 
1762
- while ( resultSet.next() ) {
1763
- resultRows.append( resultHandler.mapRow(context, runtime, columns, resultSet, this) );
1672
+ while (resultSet.next()) {
1673
+ resultRows.append(mapRow(context, runtime, columns, resultSet, this));
1764
1674
  }
1765
1675
 
1766
- return resultHandler.newResult(context, runtime, columns, resultRows);
1676
+ return newResult(context, columns, resultRows);
1767
1677
  }
1768
1678
 
1769
1679
  @Deprecated
@@ -1790,12 +1700,7 @@ public class RubyJdbcConnection extends RubyObject {
1790
1700
  return readerToRuby(context, runtime, resultSet, column);
1791
1701
  case Types.LONGVARCHAR:
1792
1702
  case Types.LONGNVARCHAR: // JDBC 4.0
1793
- if ( runtime.is1_9() ) {
1794
- return readerToRuby(context, runtime, resultSet, column);
1795
- }
1796
- else {
1797
- return streamToRuby(context, runtime, resultSet, column);
1798
- }
1703
+ return readerToRuby(context, runtime, resultSet, column);
1799
1704
  case Types.TINYINT:
1800
1705
  case Types.SMALLINT:
1801
1706
  case Types.INTEGER:
@@ -1852,16 +1757,7 @@ public class RubyJdbcConnection extends RubyObject {
1852
1757
  throws SQLException {
1853
1758
  final long value = resultSet.getLong(column);
1854
1759
  if ( value == 0 && resultSet.wasNull() ) return runtime.getNil();
1855
- return integerToRuby(runtime, resultSet, value);
1856
- }
1857
-
1858
- @Deprecated
1859
- protected IRubyObject integerToRuby(
1860
- final Ruby runtime, final ResultSet resultSet, final long longValue)
1861
- throws SQLException {
1862
- if ( longValue == 0 && resultSet.wasNull() ) return runtime.getNil();
1863
-
1864
- return runtime.newFixnum(longValue);
1760
+ return runtime.newFixnum(value);
1865
1761
  }
1866
1762
 
1867
1763
  protected IRubyObject doubleToRuby(final ThreadContext context,
@@ -1869,58 +1765,29 @@ public class RubyJdbcConnection extends RubyObject {
1869
1765
  throws SQLException {
1870
1766
  final double value = resultSet.getDouble(column);
1871
1767
  if ( value == 0 && resultSet.wasNull() ) return runtime.getNil();
1872
- return doubleToRuby(runtime, resultSet, value);
1768
+ return runtime.newFloat(value);
1873
1769
  }
1874
1770
 
1875
- @Deprecated
1876
- protected IRubyObject doubleToRuby(
1877
- final Ruby runtime, final ResultSet resultSet, double doubleValue)
1878
- throws SQLException {
1879
- if ( doubleValue == 0 && resultSet.wasNull() ) return runtime.getNil();
1880
- return runtime.newFloat(doubleValue);
1771
+ protected IRubyObject stringToRuby(final ThreadContext context,
1772
+ final Ruby runtime, final ResultSet resultSet, final int column) throws SQLException {
1773
+ final String value = resultSet.getString(column);
1774
+ if ( value == null && resultSet.wasNull() ) return runtime.getNil();
1775
+ return RubyString.newInternalFromJavaExternal(runtime, value);
1881
1776
  }
1882
1777
 
1883
- protected IRubyObject stringToRuby(final ThreadContext context,
1884
- final Ruby runtime, final ResultSet resultSet, final int column)
1885
- throws SQLException {
1778
+ protected IRubyObject bigIntegerToRuby(final ThreadContext context,
1779
+ final Ruby runtime, final ResultSet resultSet, final int column) throws SQLException {
1886
1780
  final String value = resultSet.getString(column);
1887
1781
  if ( value == null && resultSet.wasNull() ) return runtime.getNil();
1888
- return stringToRuby(runtime, resultSet, value);
1889
- }
1890
-
1891
- @Deprecated
1892
- protected IRubyObject stringToRuby(
1893
- final Ruby runtime, final ResultSet resultSet, final String string)
1894
- throws SQLException {
1895
- if ( string == null && resultSet.wasNull() ) return runtime.getNil();
1896
-
1897
- return RubyString.newUnicodeString(runtime, string);
1898
- }
1899
-
1900
- protected IRubyObject bigIntegerToRuby(final ThreadContext context,
1901
- final Ruby runtime, final ResultSet resultSet, final int column)
1902
- throws SQLException {
1903
- final String value = resultSet.getString(column);
1904
- if ( value == null && resultSet.wasNull() ) return runtime.getNil();
1905
- return bigIntegerToRuby(runtime, resultSet, value);
1906
- }
1907
-
1908
- @Deprecated
1909
- protected IRubyObject bigIntegerToRuby(
1910
- final Ruby runtime, final ResultSet resultSet, final String intValue)
1911
- throws SQLException {
1912
- if ( intValue == null && resultSet.wasNull() ) return runtime.getNil();
1913
-
1914
- return RubyBignum.bignorm(runtime, new BigInteger(intValue));
1782
+ return RubyBignum.bignorm(runtime, new BigInteger(value));
1915
1783
  }
1916
1784
 
1917
1785
  protected IRubyObject decimalToRuby(final ThreadContext context,
1918
- final Ruby runtime, final ResultSet resultSet, final int column)
1919
- throws SQLException {
1786
+ final Ruby runtime, final ResultSet resultSet, final int column) throws SQLException {
1920
1787
  final String value = resultSet.getString(column);
1921
1788
  if ( value == null && resultSet.wasNull() ) return runtime.getNil();
1922
- // NOTE: JRuby 1.6 -> 1.7 API change : moved org.jruby.RubyBigDecimal
1923
- return runtime.getKernel().callMethod("BigDecimal", runtime.newString(value));
1789
+
1790
+ return RubyBigDecimal.newInstance(context, runtime.getModule("BigDecimal"), runtime.newString(value));
1924
1791
  }
1925
1792
 
1926
1793
  protected static Boolean rawDateTime;
@@ -1957,7 +1824,7 @@ public class RubyJdbcConnection extends RubyObject {
1957
1824
  protected static IRubyObject typeCastFromDatabase(final ThreadContext context,
1958
1825
  final IRubyObject adapter, final RubySymbol typeName, final RubyString value) {
1959
1826
  final IRubyObject type = adapter.callMethod(context, "lookup_cast_type", typeName);
1960
- return type.callMethod(context, "type_cast_from_database", value);
1827
+ return type.callMethod(context, "deserialize", value);
1961
1828
  }
1962
1829
 
1963
1830
  protected IRubyObject dateToRuby(final ThreadContext context,
@@ -1976,11 +1843,8 @@ public class RubyJdbcConnection extends RubyObject {
1976
1843
  final IRubyObject adapter = callMethod(context, "adapter"); // self.adapter
1977
1844
  if ( adapter.isNil() ) return strValue; // NOTE: we warn on init_connection
1978
1845
 
1979
- if ( usesType(runtime) ) {
1980
- // NOTE: this CAN NOT be 100% correct - as :date is just a type guess!
1981
- return typeCastFromDatabase(context, adapter, runtime.newSymbol("date"), strValue);
1982
- }
1983
- return adapter.callMethod(context, "_string_to_date", strValue);
1846
+ // NOTE: this CAN NOT be 100% correct - as :date is just a type guess!
1847
+ return typeCastFromDatabase(context, adapter, runtime.newSymbol("date"), strValue);
1984
1848
  }
1985
1849
 
1986
1850
  protected IRubyObject timeToRuby(final ThreadContext context,
@@ -1999,11 +1863,8 @@ public class RubyJdbcConnection extends RubyObject {
1999
1863
  final IRubyObject adapter = callMethod(context, "adapter"); // self.adapter
2000
1864
  if ( adapter.isNil() ) return strValue; // NOTE: we warn on init_connection
2001
1865
 
2002
- if ( usesType(runtime) ) {
2003
- // NOTE: this CAN NOT be 100% correct - as :time is just a type guess!
2004
- return typeCastFromDatabase(context, adapter, runtime.newSymbol("time"), strValue);
2005
- }
2006
- return adapter.callMethod(context, "_string_to_time", strValue);
1866
+ // NOTE: this CAN NOT be 100% correct - as :time is just a type guess!
1867
+ return typeCastFromDatabase(context, adapter, runtime.newSymbol("time"), strValue);
2007
1868
  }
2008
1869
 
2009
1870
  protected IRubyObject timestampToRuby(final ThreadContext context, // TODO
@@ -2022,11 +1883,8 @@ public class RubyJdbcConnection extends RubyObject {
2022
1883
  final IRubyObject adapter = callMethod(context, "adapter"); // self.adapter
2023
1884
  if ( adapter.isNil() ) return strValue; // NOTE: we warn on init_connection
2024
1885
 
2025
- if ( usesType(runtime) ) {
2026
- // NOTE: this CAN NOT be 100% correct - as :timestamp is just a type guess!
2027
- return typeCastFromDatabase(context, adapter, runtime.newSymbol("timestamp"), strValue);
2028
- }
2029
- return adapter.callMethod(context, "_string_to_timestamp", strValue);
1886
+ // NOTE: this CAN NOT be 100% correct - as :timestamp is just a type guess!
1887
+ return typeCastFromDatabase(context, adapter, runtime.newSymbol("timestamp"), strValue);
2030
1888
  }
2031
1889
 
2032
1890
  protected static RubyString timestampToRubyString(final Ruby runtime, String value) {
@@ -2041,14 +1899,6 @@ public class RubyJdbcConnection extends RubyObject {
2041
1899
  return RubyString.newUnicodeString(runtime, value);
2042
1900
  }
2043
1901
 
2044
- @Deprecated
2045
- protected IRubyObject timestampToRuby(
2046
- final Ruby runtime, final ResultSet resultSet, final Timestamp value)
2047
- throws SQLException {
2048
- if ( value == null && resultSet.wasNull() ) return runtime.getNil();
2049
-
2050
- return timestampToRubyString(runtime, value.toString());
2051
- }
2052
1902
 
2053
1903
  protected static Boolean rawBoolean;
2054
1904
  static {
@@ -2151,7 +2001,7 @@ public class RubyJdbcConnection extends RubyObject {
2151
2001
  string.append(buf, 0, len);
2152
2002
  }
2153
2003
 
2154
- return RubyString.newUnicodeString(runtime, string.toString());
2004
+ return RubyString.newInternalFromJavaExternal(runtime, string.toString());
2155
2005
  }
2156
2006
 
2157
2007
  protected IRubyObject objectToRuby(final ThreadContext context,
@@ -2190,161 +2040,93 @@ public class RubyJdbcConnection extends RubyObject {
2190
2040
  try {
2191
2041
  if ( xml == null || resultSet.wasNull() ) return runtime.getNil();
2192
2042
 
2193
- return RubyString.newUnicodeString(runtime, xml.getString());
2043
+ return RubyString.newInternalFromJavaExternal(runtime, xml.getString());
2194
2044
  }
2195
2045
  finally { if ( xml != null ) xml.free(); }
2196
2046
  }
2197
2047
 
2198
2048
  protected void setStatementParameters(final ThreadContext context,
2199
2049
  final Connection connection, final PreparedStatement statement,
2200
- final List<?> binds) throws SQLException {
2201
-
2202
- final Ruby runtime = context.getRuntime();
2203
-
2204
- for ( int i = 0; i < binds.size(); i++ ) {
2205
- // [ [ column1, param1 ], [ column2, param2 ], ... ]
2206
- Object param = binds.get(i); IRubyObject column = null;
2207
- if ( param instanceof RubyArray ) {
2208
- final RubyArray _param = (RubyArray) param;
2209
- column = _param.eltInternal(0); param = _param.eltInternal(1);
2210
- }
2211
- else if ( param instanceof List ) {
2212
- final List<?> _param = (List<?>) param;
2213
- column = (IRubyObject) _param.get(0); param = _param.get(1);
2214
- }
2215
- else if ( param instanceof Object[] ) {
2216
- final Object[] _param = (Object[]) param;
2217
- column = (IRubyObject) _param[0]; param = _param[1];
2218
- }
2050
+ final RubyArray binds) throws SQLException {
2219
2051
 
2220
- setStatementParameter(context, runtime, connection, statement, i + 1, param, column);
2052
+ for ( int i = 0; i < binds.getLength(); i++ ) {
2053
+ setStatementParameter(context, connection, statement, i + 1, binds.eltInternal(i));
2221
2054
  }
2222
2055
  }
2223
2056
 
2224
- // So far we have only examined the needs to Sqlite3 but for that adapter (and it is old JDBC adapter)
2225
- // we can pass all tests but binary column types with just the supplied value. So we will leave it
2226
- // this way until we upgrade Sqlite adapter and get some more databases supported.
2227
- protected int typeHack(ThreadContext context, IRubyObject column, Object value) throws SQLException {
2228
- if (column != null) {
2229
- String columnType = column.asString().toString();
2057
+ // Set the prepared statement attributes based on the passed in Attribute object
2058
+ protected void setStatementParameter(final ThreadContext context,
2059
+ final Connection connection, final PreparedStatement statement,
2060
+ final int index, IRubyObject attribute) throws SQLException {
2230
2061
 
2231
- if (columnType.equals("binary")) return jdbcTypeFor(context, context.runtime, column, value);
2062
+ //debugMessage(context, attribute);
2063
+ int type = jdbcTypeForAttribute(context, attribute);
2064
+ IRubyObject value = valueForDatabase(context, attribute);
2232
2065
 
2233
- column = null;
2066
+ // All the set methods were calling this first so save a method call in the nil case
2067
+ if ( value.isNil() ) {
2068
+ statement.setNull(index, type);
2069
+ return;
2234
2070
  }
2235
2071
 
2236
- return jdbcTypeFor(context, context.runtime, column, value);
2237
- }
2238
-
2239
- protected void setStatementParameter(final ThreadContext context,
2240
- final Ruby runtime, final Connection connection,
2241
- final PreparedStatement statement, final int index,
2242
- final Object value, IRubyObject column) throws SQLException {
2243
- int type = typeHack(context, column, value);
2244
-
2245
2072
  switch (type) {
2246
2073
  case Types.TINYINT:
2247
2074
  case Types.SMALLINT:
2248
2075
  case Types.INTEGER:
2249
- if ( value instanceof RubyBignum ) { // e.g. HSQLDB / H2 report JDBC type 4
2250
- setBigIntegerParameter(context, connection, statement, index, (RubyBignum) value, column, type);
2251
- }
2252
- else {
2253
- setIntegerParameter(context, connection, statement, index, value, column, type);
2254
- }
2076
+ setIntegerParameter(context, connection, statement, index, value, attribute, type);
2255
2077
  break;
2256
2078
  case Types.BIGINT:
2257
- setBigIntegerParameter(context, connection, statement, index, value, column, type);
2079
+ setBigIntegerParameter(context, connection, statement, index, value, attribute, type);
2258
2080
  break;
2259
2081
  case Types.REAL:
2260
2082
  case Types.FLOAT:
2261
2083
  case Types.DOUBLE:
2262
- setDoubleParameter(context, connection, statement, index, value, column, type);
2084
+ setDoubleParameter(context, connection, statement, index, value, attribute, type);
2263
2085
  break;
2264
2086
  case Types.NUMERIC:
2265
2087
  case Types.DECIMAL:
2266
- setDecimalParameter(context, connection, statement, index, value, column, type);
2088
+ setDecimalParameter(context, connection, statement, index, value, attribute, type);
2267
2089
  break;
2268
2090
  case Types.DATE:
2269
- setDateParameter(context, connection, statement, index, value, column, type);
2091
+ setDateParameter(context, connection, statement, index, value, attribute, type);
2270
2092
  break;
2271
2093
  case Types.TIME:
2272
- setTimeParameter(context, connection, statement, index, value, column, type);
2094
+ setTimeParameter(context, connection, statement, index, value, attribute, type);
2273
2095
  break;
2274
2096
  case Types.TIMESTAMP:
2275
- setTimestampParameter(context, connection, statement, index, value, column, type);
2097
+ setTimestampParameter(context, connection, statement, index, value, attribute, type);
2276
2098
  break;
2277
2099
  case Types.BIT:
2278
2100
  case Types.BOOLEAN:
2279
- setBooleanParameter(context, connection, statement, index, value, column, type);
2101
+ setBooleanParameter(context, connection, statement, index, value, attribute, type);
2280
2102
  break;
2281
2103
  case Types.SQLXML:
2282
- setXmlParameter(context, connection, statement, index, value, column, type);
2104
+ setXmlParameter(context, connection, statement, index, value, attribute, type);
2283
2105
  break;
2284
2106
  case Types.ARRAY:
2285
- setArrayParameter(context, connection, statement, index, value, column, type);
2107
+ setArrayParameter(context, connection, statement, index, value, attribute, type);
2286
2108
  break;
2287
2109
  case Types.JAVA_OBJECT:
2288
2110
  case Types.OTHER:
2289
- setObjectParameter(context, connection, statement, index, value, column, type);
2111
+ setObjectParameter(context, connection, statement, index, value, attribute, type);
2290
2112
  break;
2291
2113
  case Types.BINARY:
2292
2114
  case Types.VARBINARY:
2293
2115
  case Types.LONGVARBINARY:
2294
2116
  case Types.BLOB:
2295
- setBlobParameter(context, connection, statement, index, value, column, type);
2117
+ setBlobParameter(context, connection, statement, index, value, attribute, type);
2296
2118
  break;
2297
2119
  case Types.CLOB:
2298
2120
  case Types.NCLOB: // JDBC 4.0
2299
- setClobParameter(context, connection, statement, index, value, column, type);
2121
+ setClobParameter(context, connection, statement, index, value, attribute, type);
2300
2122
  break;
2301
2123
  case Types.CHAR:
2302
2124
  case Types.VARCHAR:
2303
2125
  case Types.NCHAR: // JDBC 4.0
2304
2126
  case Types.NVARCHAR: // JDBC 4.0
2305
2127
  default:
2306
- setStringParameter(context, connection, statement, index, value, column, type);
2307
- }
2308
- }
2309
-
2310
- @Deprecated // NOTE: only used from deprecated methods
2311
- private void setPreparedStatementValues(final ThreadContext context,
2312
- final Connection connection, final PreparedStatement statement,
2313
- final IRubyObject valuesArg, final IRubyObject typesArg) throws SQLException {
2314
- final Ruby runtime = context.getRuntime();
2315
- final RubyArray values = (RubyArray) valuesArg;
2316
- final RubyArray types = (RubyArray) typesArg; // column types
2317
- for( int i = 0, j = values.getLength(); i < j; i++ ) {
2318
- setStatementParameter(
2319
- context, runtime, connection, statement, i + 1,
2320
- values.eltInternal(i), types.eltInternal(i)
2321
- );
2322
- }
2323
- }
2324
-
2325
- private RubySymbol resolveColumnType(final ThreadContext context, final Ruby runtime,
2326
- final IRubyObject column) {
2327
- if ( column instanceof RubySymbol ) { // deprecated behavior
2328
- return (RubySymbol) column;
2329
- }
2330
- if ( column instanceof RubyString) { // deprecated behavior
2331
- if ( runtime.is1_9() ) {
2332
- return ( (RubyString) column ).intern19();
2333
- }
2334
- else {
2335
- return ( (RubyString) column ).intern();
2336
- }
2337
- }
2338
-
2339
- if ( column == null || column.isNil() ) {
2340
- throw runtime.newArgumentError("nil column passed");
2341
- }
2342
-
2343
- final IRubyObject type = column.callMethod(context, "type");
2344
- if ( type.isNil() || ! (type instanceof RubySymbol) ) {
2345
- throw new IllegalStateException("unexpected type = " + type.inspect() + " for " + column.inspect());
2128
+ setStringParameter(context, connection, statement, index, value, attribute, type);
2346
2129
  }
2347
- return (RubySymbol) type;
2348
2130
  }
2349
2131
 
2350
2132
  protected static final Map<String, Integer> JDBC_TYPE_FOR = new HashMap<String, Integer>(32, 1);
@@ -2359,7 +2141,6 @@ public class RubyJdbcConnection extends RubyObject {
2359
2141
  JDBC_TYPE_FOR.put("time", Types.TIME);
2360
2142
  JDBC_TYPE_FOR.put("datetime", Types.TIMESTAMP);
2361
2143
  JDBC_TYPE_FOR.put("timestamp", Types.TIMESTAMP);
2362
- JDBC_TYPE_FOR.put("binary", Types.BLOB);
2363
2144
  JDBC_TYPE_FOR.put("boolean", Types.BOOLEAN);
2364
2145
  JDBC_TYPE_FOR.put("array", Types.ARRAY);
2365
2146
  JDBC_TYPE_FOR.put("xml", Types.SQLXML);
@@ -2384,107 +2165,89 @@ public class RubyJdbcConnection extends RubyObject {
2384
2165
  JDBC_TYPE_FOR.put("nclob", Types.NCLOB);
2385
2166
  }
2386
2167
 
2387
- protected int jdbcTypeFor(final ThreadContext context, final Ruby runtime,
2388
- final IRubyObject column, final Object value) throws SQLException {
2168
+ protected int jdbcTypeForAttribute(final ThreadContext context,
2169
+ final IRubyObject attribute) throws SQLException {
2389
2170
 
2390
- final String internedType;
2391
- if ( column != null && ! column.isNil() ) {
2392
- // NOTE: there's no ActiveRecord "convention" really for this ...
2393
- // this is based on Postgre's initial support for arrays :
2394
- // `column.type` contains the base type while there's `column.array?`
2395
- if ( column.respondsTo("array?") && column.callMethod(context, "array?").isTrue() ) {
2396
- internedType = "array";
2397
- }
2398
- else {
2399
- internedType = resolveColumnType(context, runtime, column).asJavaString();
2400
- }
2171
+ final String internedType = internedTypeFor(context, attribute);
2172
+ final Integer sqlType = jdbcTypeFor(internedType);
2173
+ if ( sqlType != null ) {
2174
+ return sqlType.intValue();
2401
2175
  }
2402
- else {
2403
- if ( value instanceof RubyInteger ) internedType = "integer";
2404
- else if ( value instanceof RubyNumeric ) internedType = "float";
2405
- else if ( value instanceof RubyTime ) internedType = "timestamp";
2406
- else internedType = "string";
2407
- }
2408
-
2409
- final Integer sqlType = JDBC_TYPE_FOR.get(internedType);
2410
- if ( sqlType != null ) return sqlType.intValue();
2411
2176
 
2412
2177
  return Types.OTHER; // -1 as well as 0 are used in Types
2413
2178
  }
2414
2179
 
2415
- protected void setIntegerParameter(final ThreadContext context,
2416
- final Connection connection, final PreparedStatement statement,
2417
- final int index, final Object value,
2418
- final IRubyObject column, final int type) throws SQLException {
2419
- if ( value instanceof IRubyObject ) {
2420
- setIntegerParameter(context, connection, statement, index, (IRubyObject) value, column, type);
2180
+ protected Integer jdbcTypeFor(final String type) {
2181
+ return JDBC_TYPE_FOR.get(type);
2182
+ }
2183
+
2184
+ protected IRubyObject attributeType(final ThreadContext context, final IRubyObject attribute) {
2185
+ return attribute.callMethod(context, "type");
2186
+ }
2187
+
2188
+ protected IRubyObject attributeSQLType(final ThreadContext context, final IRubyObject attribute) {
2189
+ return attributeType(context, attribute).callMethod(context, "type");
2190
+ }
2191
+
2192
+ protected String internedTypeFor(final ThreadContext context, final IRubyObject attribute) throws SQLException {
2193
+
2194
+ final IRubyObject type = attributeSQLType(context, attribute);
2195
+
2196
+ if ( !type.isNil() ) {
2197
+ return type.asJavaString();
2421
2198
  }
2422
- else {
2423
- if ( value == null ) statement.setNull(index, Types.INTEGER);
2424
- else {
2425
- statement.setLong(index, ((Number) value).longValue());
2426
- }
2199
+
2200
+ final IRubyObject value = attribute.callMethod(context, "value");
2201
+
2202
+ if ( value instanceof RubyInteger ) {
2203
+ return "integer";
2204
+ }
2205
+
2206
+ if ( value instanceof RubyNumeric ) {
2207
+ return "float";
2427
2208
  }
2209
+
2210
+ if ( value instanceof RubyTime ) {
2211
+ return "timestamp";
2212
+ }
2213
+
2214
+ return "string";
2428
2215
  }
2429
2216
 
2430
2217
  protected void setIntegerParameter(final ThreadContext context,
2431
2218
  final Connection connection, final PreparedStatement statement,
2432
2219
  final int index, final IRubyObject value,
2433
- final IRubyObject column, final int type) throws SQLException {
2434
- if ( value.isNil() ) statement.setNull(index, Types.INTEGER);
2435
- else {
2436
- if ( value instanceof RubyFixnum ) {
2437
- statement.setLong(index, ((RubyFixnum) value).getLongValue());
2438
- }
2439
- else if ( value instanceof RubyNumeric ) {
2440
- // NOTE: fix2int will call value.convertToIngeter for non-numeric
2441
- // types which won't work for Strings since it uses `to_int` ...
2442
- statement.setInt(index, RubyNumeric.fix2int(value));
2443
- }
2444
- else {
2445
- statement.setLong(index, value.convertToInteger("to_i").getLongValue());
2446
- }
2447
- }
2448
- }
2220
+ final IRubyObject attribute, final int type) throws SQLException {
2449
2221
 
2450
- protected void setBigIntegerParameter(final ThreadContext context,
2451
- final Connection connection, final PreparedStatement statement,
2452
- final int index, final Object value,
2453
- final IRubyObject column, final int type) throws SQLException {
2454
- if ( value instanceof IRubyObject ) {
2455
- setBigIntegerParameter(context, connection, statement, index, (IRubyObject) value, column, type);
2222
+ if ( value instanceof RubyBignum ) { // e.g. HSQLDB / H2 report JDBC type 4
2223
+ setBigIntegerParameter(context, connection, statement, index, (RubyBignum) value, attribute, type);
2224
+ }
2225
+ else if ( value instanceof RubyFixnum ) {
2226
+ statement.setLong(index, ((RubyFixnum) value).getLongValue());
2227
+ }
2228
+ else if ( value instanceof RubyNumeric ) {
2229
+ // NOTE: fix2int will call value.convertToInteger for non-numeric
2230
+ // types which won't work for Strings since it uses `to_int` ...
2231
+ statement.setInt(index, RubyNumeric.fix2int(value));
2456
2232
  }
2457
2233
  else {
2458
- if ( value == null ) statement.setNull(index, Types.BIGINT);
2459
- else {
2460
- if ( value instanceof BigDecimal ) {
2461
- statement.setBigDecimal(index, (BigDecimal) value);
2462
- }
2463
- else if ( value instanceof BigInteger ) {
2464
- setLongOrDecimalParameter(statement, index, (BigInteger) value);
2465
- }
2466
- else {
2467
- statement.setLong(index, ((Number) value).longValue());
2468
- }
2469
- }
2234
+ statement.setLong(index, value.convertToInteger("to_i").getLongValue());
2470
2235
  }
2471
2236
  }
2472
2237
 
2473
2238
  protected void setBigIntegerParameter(final ThreadContext context,
2474
2239
  final Connection connection, final PreparedStatement statement,
2475
2240
  final int index, final IRubyObject value,
2476
- final IRubyObject column, final int type) throws SQLException {
2477
- if ( value.isNil() ) statement.setNull(index, Types.INTEGER);
2241
+ final IRubyObject attribute, final int type) throws SQLException {
2242
+
2243
+ if ( value instanceof RubyBignum ) {
2244
+ setLongOrDecimalParameter(statement, index, ((RubyBignum) value).getValue());
2245
+ }
2246
+ else if ( value instanceof RubyInteger ) {
2247
+ statement.setLong(index, ((RubyInteger) value).getLongValue());
2248
+ }
2478
2249
  else {
2479
- if ( value instanceof RubyBignum ) {
2480
- setLongOrDecimalParameter(statement, index, ((RubyBignum) value).getValue());
2481
- }
2482
- else if ( value instanceof RubyInteger ) {
2483
- statement.setLong(index, ((RubyInteger) value).getLongValue());
2484
- }
2485
- else {
2486
- setLongOrDecimalParameter(statement, index, value.convertToInteger("to_i").getBigIntegerValue());
2487
- }
2250
+ setLongOrDecimalParameter(statement, index, value.convertToInteger("to_i").getBigIntegerValue());
2488
2251
  }
2489
2252
  }
2490
2253
 
@@ -2502,153 +2265,63 @@ public class RubyJdbcConnection extends RubyObject {
2502
2265
  }
2503
2266
  }
2504
2267
 
2505
- protected void setDoubleParameter(final ThreadContext context,
2506
- final Connection connection, final PreparedStatement statement,
2507
- final int index, final Object value,
2508
- final IRubyObject column, final int type) throws SQLException {
2509
- if ( value instanceof IRubyObject ) {
2510
- setDoubleParameter(context, connection, statement, index, (IRubyObject) value, column, type);
2511
- }
2512
- else {
2513
- if ( value == null ) statement.setNull(index, Types.DOUBLE);
2514
- else {
2515
- statement.setDouble(index, ((Number) value).doubleValue());
2516
- }
2517
- }
2518
- }
2519
-
2520
2268
  protected void setDoubleParameter(final ThreadContext context,
2521
2269
  final Connection connection, final PreparedStatement statement,
2522
2270
  final int index, final IRubyObject value,
2523
- final IRubyObject column, final int type) throws SQLException {
2524
- if ( value.isNil() ) statement.setNull(index, Types.DOUBLE);
2525
- else {
2526
- if ( value instanceof RubyNumeric ) {
2527
- statement.setDouble(index, ((RubyNumeric) value).getDoubleValue());
2528
- }
2529
- else {
2530
- statement.setDouble(index, value.convertToFloat().getDoubleValue());
2531
- }
2532
- }
2533
- }
2271
+ final IRubyObject attribute, final int type) throws SQLException {
2534
2272
 
2535
- protected void setDecimalParameter(final ThreadContext context,
2536
- final Connection connection, final PreparedStatement statement,
2537
- final int index, final Object value,
2538
- final IRubyObject column, final int type) throws SQLException {
2539
- if ( value instanceof IRubyObject ) {
2540
- setDecimalParameter(context, connection, statement, index, (IRubyObject) value, column, type);
2273
+ if ( value instanceof RubyNumeric ) {
2274
+ statement.setDouble(index, ((RubyNumeric) value).getDoubleValue());
2541
2275
  }
2542
2276
  else {
2543
- if ( value == null ) statement.setNull(index, Types.DECIMAL);
2544
- else {
2545
- if ( value instanceof BigDecimal ) {
2546
- statement.setBigDecimal(index, (BigDecimal) value);
2547
- }
2548
- else if ( value instanceof BigInteger ) {
2549
- setLongOrDecimalParameter(statement, index, (BigInteger) value);
2550
- }
2551
- else {
2552
- statement.setDouble(index, ((Number) value).doubleValue());
2553
- }
2554
- }
2277
+ statement.setDouble(index, value.convertToFloat().getDoubleValue());
2555
2278
  }
2556
2279
  }
2557
2280
 
2558
2281
  protected void setDecimalParameter(final ThreadContext context,
2559
2282
  final Connection connection, final PreparedStatement statement,
2560
2283
  final int index, final IRubyObject value,
2561
- final IRubyObject column, final int type) throws SQLException {
2562
- if ( value.isNil() ) statement.setNull(index, Types.DECIMAL);
2563
- else {
2564
- // NOTE: RubyBigDecimal moved into org.jruby.ext.bigdecimal (1.6 -> 1.7)
2565
- if ( value.getMetaClass().getName().indexOf("BigDecimal") != -1 ) {
2566
- statement.setBigDecimal(index, getBigDecimalValue(value));
2567
- }
2568
- else if ( value instanceof RubyInteger ) {
2569
- statement.setBigDecimal(index, new BigDecimal(((RubyInteger) value).getBigIntegerValue()));
2570
- }
2571
- else if ( value instanceof RubyNumeric ) {
2572
- statement.setDouble(index, ((RubyNumeric) value).getDoubleValue());
2573
- }
2574
- else { // e.g. `BigDecimal '42.00000000000000000001'`
2575
- IRubyObject v = callMethod(context, "BigDecimal", value);
2576
- statement.setBigDecimal(index, getBigDecimalValue(v));
2577
- }
2578
- }
2579
- }
2284
+ final IRubyObject attribute, final int type) throws SQLException {
2580
2285
 
2581
- private static BigDecimal getBigDecimalValue(final IRubyObject value) {
2582
- try { // reflect ((RubyBigDecimal) value).getValue() :
2583
- return (BigDecimal) value.getClass().
2584
- getMethod("getValue", (Class<?>[]) null).
2585
- invoke(value, (Object[]) null);
2286
+ if (value instanceof RubyBigDecimal) {
2287
+ statement.setBigDecimal(index, ((RubyBigDecimal) value).getValue());
2586
2288
  }
2587
- catch (NoSuchMethodException e) {
2588
- throw new RuntimeException(e);
2289
+ else if ( value instanceof RubyInteger ) {
2290
+ statement.setBigDecimal(index, new BigDecimal(((RubyInteger) value).getBigIntegerValue()));
2589
2291
  }
2590
- catch (IllegalAccessException e) {
2591
- throw new RuntimeException(e);
2592
- }
2593
- catch (InvocationTargetException e) {
2594
- throw new RuntimeException(e.getCause() != null ? e.getCause() : e);
2595
- }
2596
- }
2597
-
2598
- protected void setTimestampParameter(final ThreadContext context,
2599
- final Connection connection, final PreparedStatement statement,
2600
- final int index, final Object value,
2601
- final IRubyObject column, final int type) throws SQLException {
2602
- if ( value instanceof IRubyObject ) {
2603
- setTimestampParameter(context, connection, statement, index, (IRubyObject) value, column, type);
2292
+ else if ( value instanceof RubyNumeric ) {
2293
+ statement.setDouble(index, ((RubyNumeric) value).getDoubleValue());
2604
2294
  }
2605
- else {
2606
- if ( value == null ) statement.setNull(index, Types.TIMESTAMP);
2607
- else {
2608
- if ( value instanceof Timestamp ) {
2609
- statement.setTimestamp(index, (Timestamp) value);
2610
- }
2611
- else if ( value instanceof java.util.Date ) {
2612
- statement.setTimestamp(index, new Timestamp(((java.util.Date) value).getTime()));
2613
- }
2614
- else {
2615
- statement.setTimestamp(index, Timestamp.valueOf(value.toString()));
2616
- }
2617
- }
2295
+ else { // e.g. `BigDecimal '42.00000000000000000001'`
2296
+ statement.setBigDecimal(index,
2297
+ RubyBigDecimal.newInstance(context, context.runtime.getModule("BigDecimal"), value).getValue());
2618
2298
  }
2619
2299
  }
2620
2300
 
2621
2301
  protected void setTimestampParameter(final ThreadContext context,
2622
2302
  final Connection connection, final PreparedStatement statement,
2623
2303
  final int index, IRubyObject value,
2624
- final IRubyObject column, final int type) throws SQLException {
2625
- if ( value.isNil() ) statement.setNull(index, Types.TIMESTAMP);
2626
- else {
2627
- value = getTimeInDefaultTimeZone(context, value);
2628
- if ( value instanceof RubyTime ) {
2629
- final RubyTime timeValue = (RubyTime) value;
2630
- final DateTime dateTime = timeValue.getDateTime();
2631
-
2632
- final Timestamp timestamp = new Timestamp( dateTime.getMillis() );
2633
- if ( type != Types.DATE ) { // 1942-11-30T01:02:03.123_456
2634
- // getMillis already set nanos to: 123_000_000
2635
- final int usec = (int) timeValue.getUSec(); // 456 on JRuby
2636
- if ( usec >= 0 ) {
2637
- timestamp.setNanos( timestamp.getNanos() + usec * 1000 );
2638
- }
2639
- }
2640
- statement.setTimestamp( index, timestamp, getTimeZoneCalendar(dateTime.getZone().getID()) );
2641
- }
2642
- else if ( value instanceof RubyString ) { // yyyy-[m]m-[d]d hh:mm:ss[.f...]
2643
- final Timestamp timestamp = Timestamp.valueOf( value.toString() );
2644
- statement.setTimestamp( index, timestamp ); // assume local time-zone
2645
- }
2646
- else { // DateTime ( ActiveSupport::TimeWithZone.to_time )
2647
- final RubyFloat timeValue = value.convertToFloat(); // to_f
2648
- final Timestamp timestamp = convertToTimestamp(timeValue);
2304
+ final IRubyObject attribute, final int type) throws SQLException {
2649
2305
 
2650
- statement.setTimestamp( index, timestamp, getTimeZoneCalendar("GMT") );
2651
- }
2306
+ value = callMethod(context, "time_in_default_timezone", value);
2307
+
2308
+ if (value instanceof RubyTime) {
2309
+ final RubyTime timeValue = (RubyTime) value;
2310
+ final DateTime dateTime = timeValue.getDateTime();
2311
+ final Timestamp timestamp = new Timestamp(dateTime.getMillis());
2312
+
2313
+ // 1942-11-30T01:02:03.123_456
2314
+ if (type != Types.DATE && timeValue.getNSec() >= 0) timestamp.setNanos((int) (timestamp.getNanos() + timeValue.getNSec()));
2315
+
2316
+ statement.setTimestamp(index, timestamp, getTimeZoneCalendar(dateTime.getZone().getID()));
2317
+ } else if ( value instanceof RubyString ) { // yyyy-[m]m-[d]d hh:mm:ss[.f...]
2318
+ final Timestamp timestamp = Timestamp.valueOf(value.toString());
2319
+ statement.setTimestamp(index, timestamp); // assume local time-zone
2320
+ } else { // DateTime ( ActiveSupport::TimeWithZone.to_time )
2321
+ final RubyFloat timeValue = value.convertToFloat(); // to_f
2322
+ final Timestamp timestamp = convertToTimestamp(timeValue);
2323
+
2324
+ statement.setTimestamp( index, timestamp, getTimeZoneCalendar("GMT") );
2652
2325
  }
2653
2326
  }
2654
2327
 
@@ -2663,7 +2336,7 @@ public class RubyJdbcConnection extends RubyObject {
2663
2336
  final int len = strValue.getRealSize() - strValue.getBegin();
2664
2337
  if ( dot1 > 0 && dot4 < len ) { // skip .123 but handle .1234
2665
2338
  final int end = Math.min( len - dot4, 3 );
2666
- CharSequence usecSeq = strValue.subSequence(dot4, end);
2339
+ CharSequence usecSeq = strValue.subSequence(dot4, dot4 + end);
2667
2340
  final int usec = Integer.parseInt( usecSeq.toString() );
2668
2341
  if ( usec < 10 ) { // 0.1234 ~> 4
2669
2342
  timestamp.setNanos( timestamp.getNanos() + usec * 100 );
@@ -2679,301 +2352,124 @@ public class RubyJdbcConnection extends RubyObject {
2679
2352
  return timestamp;
2680
2353
  }
2681
2354
 
2682
- protected static IRubyObject getTimeInDefaultTimeZone(final ThreadContext context, IRubyObject value) {
2683
- if ( value.respondsTo("to_time") ) {
2684
- value = value.callMethod(context, "to_time");
2685
- }
2686
- final String method = isDefaultTimeZoneUTC(context) ? "getutc" : "getlocal";
2687
- if ( value.respondsTo(method) ) {
2688
- value = value.callMethod(context, method);
2689
- }
2690
- return value;
2691
- }
2692
-
2693
- protected static boolean isDefaultTimeZoneUTC(final ThreadContext context) {
2694
- final RubyClass base = getBase(context.getRuntime());
2695
- final String tz = base.callMethod(context, "default_timezone").toString(); // :utc
2696
- return "utc".equalsIgnoreCase(tz);
2697
- }
2698
-
2699
2355
  private static Calendar getTimeZoneCalendar(final String ID) {
2700
2356
  return Calendar.getInstance( TimeZone.getTimeZone(ID) );
2701
2357
  }
2702
2358
 
2703
- protected void setTimeParameter(final ThreadContext context,
2704
- final Connection connection, final PreparedStatement statement,
2705
- final int index, final Object value,
2706
- final IRubyObject column, final int type) throws SQLException {
2707
- if ( value instanceof IRubyObject ) {
2708
- setTimeParameter(context, connection, statement, index, (IRubyObject) value, column, type);
2709
- }
2710
- else {
2711
- if ( value == null ) statement.setNull(index, Types.TIME);
2712
- else {
2713
- if ( value instanceof Time ) {
2714
- statement.setTime(index, (Time) value);
2715
- }
2716
- else if ( value instanceof java.util.Date ) {
2717
- statement.setTime(index, new Time(((java.util.Date) value).getTime()));
2718
- }
2719
- else { // hh:mm:ss
2720
- statement.setTime(index, Time.valueOf(value.toString()));
2721
- // statement.setString(index, value.toString());
2722
- }
2723
- }
2724
- }
2725
- }
2726
-
2727
2359
  protected void setTimeParameter(final ThreadContext context,
2728
2360
  final Connection connection, final PreparedStatement statement,
2729
2361
  final int index, IRubyObject value,
2730
- final IRubyObject column, final int type) throws SQLException {
2731
- if ( value.isNil() ) statement.setNull(index, Types.TIME);
2732
- else {
2733
- value = getTimeInDefaultTimeZone(context, value);
2734
- if ( value instanceof RubyTime ) {
2735
- final RubyTime timeValue = (RubyTime) value;
2736
- final DateTime dateTime = timeValue.getDateTime();
2362
+ final IRubyObject attribute, final int type) throws SQLException {
2737
2363
 
2738
- final Time time = new Time( dateTime.getMillis() );
2739
- statement.setTime( index, time, getTimeZoneCalendar(dateTime.getZone().getID()) );
2740
- }
2741
- else if ( value instanceof RubyString ) {
2742
- final Time time = Time.valueOf( value.toString() );
2743
- statement.setTime( index, time ); // assume local time-zone
2744
- }
2745
- else { // DateTime ( ActiveSupport::TimeWithZone.to_time )
2746
- final RubyFloat timeValue = value.convertToFloat(); // to_f
2747
- final Time time = new Time(timeValue.getLongValue() * 1000); // millis
2748
- // java.sql.Time is expected to be only up to second precision
2749
- statement.setTime( index, time, getTimeZoneCalendar("GMT") );
2750
- }
2751
- }
2752
- }
2364
+ value = callMethod(context, "time_in_default_timezone", value);
2753
2365
 
2754
- protected void setDateParameter(final ThreadContext context,
2755
- final Connection connection, final PreparedStatement statement,
2756
- final int index, final Object value,
2757
- final IRubyObject column, final int type) throws SQLException {
2758
- if ( value instanceof IRubyObject ) {
2759
- setDateParameter(context, connection, statement, index, (IRubyObject) value, column, type);
2366
+ if ( value instanceof RubyTime ) {
2367
+ final DateTime dateTime = ((RubyTime) value).getDateTime();
2368
+ final Time time = new Time(dateTime.getMillis());
2369
+
2370
+ statement.setTime(index, time, getTimeZoneCalendar(dateTime.getZone().getID()));
2760
2371
  }
2761
- else {
2762
- if ( value == null ) statement.setNull(index, Types.DATE);
2763
- else {
2764
- if ( value instanceof Date ) {
2765
- statement.setDate(index, (Date) value);
2766
- }
2767
- else if ( value instanceof java.util.Date ) {
2768
- statement.setDate(index, new Date(((java.util.Date) value).getTime()));
2769
- }
2770
- else { // yyyy-[m]m-[d]d
2771
- statement.setDate(index, Date.valueOf(value.toString()));
2772
- // statement.setString(index, value.toString());
2773
- }
2774
- }
2372
+ else if ( value instanceof RubyString ) {
2373
+ final Time time = Time.valueOf(value.toString());
2374
+ statement.setTime(index, time); // assume local time-zone
2375
+ }
2376
+ else { // DateTime ( ActiveSupport::TimeWithZone.to_time )
2377
+ final RubyFloat timeValue = value.convertToFloat(); // to_f
2378
+ final Time time = new Time(timeValue.getLongValue() * 1000); // millis
2379
+ // java.sql.Time is expected to be only up to second precision
2380
+ statement.setTime(index, time, getTimeZoneCalendar("GMT"));
2775
2381
  }
2776
2382
  }
2777
2383
 
2778
2384
  protected void setDateParameter(final ThreadContext context,
2779
2385
  final Connection connection, final PreparedStatement statement,
2780
2386
  final int index, IRubyObject value,
2781
- final IRubyObject column, final int type) throws SQLException {
2782
- if ( value.isNil() ) statement.setNull(index, Types.DATE);
2783
- else {
2784
- //if ( value instanceof RubyString ) {
2785
- // final Date date = Date.valueOf( value.toString() );
2786
- // statement.setDate( index, date ); // assume local time-zone
2787
- // return;
2788
- //}
2789
- if ( ! "Date".equals( value.getMetaClass().getName() ) ) {
2790
- if ( value.respondsTo("to_date") ) {
2791
- value = value.callMethod(context, "to_date");
2792
- }
2793
- }
2794
- final Date date = Date.valueOf( value.asString().toString() ); // to_s
2795
- statement.setDate( index, date /*, getTimeZoneCalendar("GMT") */ );
2796
- }
2797
- }
2387
+ final IRubyObject attribute, final int type) throws SQLException {
2798
2388
 
2799
- protected void setBooleanParameter(final ThreadContext context,
2800
- final Connection connection, final PreparedStatement statement,
2801
- final int index, final Object value,
2802
- final IRubyObject column, final int type) throws SQLException {
2803
- if ( value instanceof IRubyObject ) {
2804
- setBooleanParameter(context, connection, statement, index, (IRubyObject) value, column, type);
2805
- }
2806
- else {
2807
- if ( value == null ) statement.setNull(index, Types.BOOLEAN);
2808
- else {
2809
- statement.setBoolean(index, ((Boolean) value).booleanValue());
2810
- }
2389
+ if ( ! "Date".equals(value.getMetaClass().getName()) && value.respondsTo("to_date") ) {
2390
+ value = value.callMethod(context, "to_date");
2811
2391
  }
2392
+ final Date date = Date.valueOf(value.asString().toString()); // to_s
2393
+ statement.setDate(index, date);
2812
2394
  }
2813
2395
 
2814
2396
  protected void setBooleanParameter(final ThreadContext context,
2815
2397
  final Connection connection, final PreparedStatement statement,
2816
2398
  final int index, final IRubyObject value,
2817
- final IRubyObject column, final int type) throws SQLException {
2818
- if ( value.isNil() ) statement.setNull(index, Types.BOOLEAN);
2819
- else {
2820
- statement.setBoolean(index, value.isTrue());
2821
- }
2822
- }
2823
-
2824
- protected void setStringParameter(final ThreadContext context,
2825
- final Connection connection, final PreparedStatement statement,
2826
- final int index, final Object value,
2827
- final IRubyObject column, final int type) throws SQLException {
2828
- if ( value instanceof IRubyObject ) {
2829
- setStringParameter(context, connection, statement, index, (IRubyObject) value, column, type);
2830
- }
2831
- else {
2832
- if ( value == null ) statement.setNull(index, Types.VARCHAR);
2833
- else {
2834
- statement.setString(index, value.toString());
2835
- }
2836
- }
2399
+ final IRubyObject attribute, final int type) throws SQLException {
2400
+ statement.setBoolean(index, value.isTrue());
2837
2401
  }
2838
2402
 
2839
2403
  protected void setStringParameter(final ThreadContext context,
2840
2404
  final Connection connection, final PreparedStatement statement,
2841
2405
  final int index, final IRubyObject value,
2842
- final IRubyObject column, final int type) throws SQLException {
2843
- if ( value.isNil() ) statement.setNull(index, Types.VARCHAR);
2844
- else {
2845
- statement.setString(index, value.asString().toString());
2846
- }
2847
- }
2406
+ final IRubyObject attribute, final int type) throws SQLException {
2848
2407
 
2849
- protected void setArrayParameter(final ThreadContext context,
2850
- final Connection connection, final PreparedStatement statement,
2851
- final int index, final Object value,
2852
- final IRubyObject column, final int type) throws SQLException {
2853
- if ( value instanceof IRubyObject ) {
2854
- setArrayParameter(context, connection, statement, index, (IRubyObject) value, column, type);
2855
- } else {
2856
- if ( value == null ) {
2857
- statement.setNull(index, Types.ARRAY);
2858
- } else {
2859
- String typeName = resolveArrayBaseTypeName(context, value, column, type);
2860
- Array array = connection.createArrayOf(typeName, (Object[]) value);
2861
- statement.setArray(index, array);
2862
- }
2863
- }
2408
+ statement.setString(index, value.asString().toString());
2864
2409
  }
2865
2410
 
2866
2411
  protected void setArrayParameter(final ThreadContext context,
2867
2412
  final Connection connection, final PreparedStatement statement,
2868
2413
  final int index, final IRubyObject value,
2869
- final IRubyObject column, final int type) throws SQLException {
2870
- if ( value.isNil() ) {
2871
- statement.setNull(index, Types.ARRAY);
2872
- } else {
2873
- String typeName = resolveArrayBaseTypeName(context, value, column, type);
2874
- Array array = connection.createArrayOf(typeName, ((RubyArray) value).toArray());
2875
- statement.setArray(index, array);
2876
- }
2877
- }
2414
+ final IRubyObject attribute, final int type) throws SQLException {
2878
2415
 
2879
- protected String resolveArrayBaseTypeName(final ThreadContext context,
2880
- final Object value, final IRubyObject column, final int type) {
2881
- // return column.callMethod(context, "sql_type").toString();
2882
- String sqlType = column.callMethod(context, "sql_type").toString();
2883
- final int index = sqlType.indexOf('('); // e.g. "character varying(255)"
2884
- if ( index > 0 ) sqlType = sqlType.substring(0, index);
2885
- return sqlType;
2416
+ final String typeName = resolveArrayBaseTypeName(context, attribute);
2417
+ final IRubyObject valueForDB = value.callMethod(context, "values");
2418
+ Array array = connection.createArrayOf(typeName, ((RubyArray) valueForDB).toArray());
2419
+ statement.setArray(index, array);
2886
2420
  }
2887
2421
 
2888
- protected void setXmlParameter(final ThreadContext context,
2889
- final Connection connection, final PreparedStatement statement,
2890
- final int index, final Object value,
2891
- final IRubyObject column, final int type) throws SQLException {
2892
- if ( value instanceof IRubyObject ) {
2893
- setXmlParameter(context, connection, statement, index, (IRubyObject) value, column, type);
2894
- }
2895
- else {
2896
- if ( value == null ) statement.setNull(index, Types.SQLXML);
2897
- else {
2898
- SQLXML xml = connection.createSQLXML();
2899
- xml.setString(value.toString());
2900
- statement.setSQLXML(index, xml);
2901
- }
2422
+ protected String resolveArrayBaseTypeName(final ThreadContext context, final IRubyObject attribute) throws SQLException {
2423
+
2424
+ // This shouldn't return nil at this point because we know we have an array typed attribute
2425
+ final RubySymbol type = (RubySymbol) attributeSQLType(context, attribute);
2426
+
2427
+ // For some reason the driver doesn't like "character varying" as a type
2428
+ if ( type.eql(context.runtime.newSymbol("string")) ){
2429
+ return "text";
2902
2430
  }
2431
+
2432
+ final IRubyObject adapter = callMethod("adapter");
2433
+ final RubyHash nativeTypes = (RubyHash) adapter.callMethod(context, "native_database_types");
2434
+ final RubyHash typeInfo = (RubyHash) nativeTypes.op_aref(context, type);
2435
+
2436
+ return typeInfo.op_aref(context, context.runtime.newSymbol("name")).asString().toString();
2903
2437
  }
2904
2438
 
2905
2439
  protected void setXmlParameter(final ThreadContext context,
2906
2440
  final Connection connection, final PreparedStatement statement,
2907
2441
  final int index, final IRubyObject value,
2908
- final IRubyObject column, final int type) throws SQLException {
2909
- if ( value.isNil() ) statement.setNull(index, Types.SQLXML);
2910
- else {
2911
- SQLXML xml = connection.createSQLXML();
2912
- xml.setString(value.asString().toString());
2913
- statement.setSQLXML(index, xml);
2914
- }
2915
- }
2442
+ final IRubyObject attribute, final int type) throws SQLException {
2916
2443
 
2917
- protected void setBlobParameter(final ThreadContext context,
2918
- final Connection connection, final PreparedStatement statement,
2919
- final int index, final Object value,
2920
- final IRubyObject column, final int type) throws SQLException {
2921
- if ( value instanceof IRubyObject ) {
2922
- setBlobParameter(context, connection, statement, index, (IRubyObject) value, column, type);
2923
- }
2924
- else {
2925
- if ( value == null ) statement.setNull(index, Types.BLOB);
2926
- else {
2927
- //statement.setBlob(index, (InputStream) value);
2928
- statement.setBinaryStream(index, (InputStream) value);
2929
- }
2930
- }
2444
+ SQLXML xml = connection.createSQLXML();
2445
+ xml.setString(value.asString().toString());
2446
+ statement.setSQLXML(index, xml);
2931
2447
  }
2932
2448
 
2933
2449
  protected void setBlobParameter(final ThreadContext context,
2934
2450
  final Connection connection, final PreparedStatement statement,
2935
2451
  final int index, final IRubyObject value,
2936
- final IRubyObject column, final int type) throws SQLException {
2937
- if ( value.isNil() ) statement.setNull(index, Types.BLOB);
2938
- else {
2939
- if ( value instanceof RubyIO ) { // IO/File
2940
- //statement.setBlob(index, ((RubyIO) value).getInStream());
2941
- statement.setBinaryStream(index, ((RubyIO) value).getInStream());
2942
- }
2943
- else { // should be a RubyString
2944
- final ByteList blob = value.asString().getByteList();
2945
- statement.setBytes(index, blob.bytes());
2946
- //statement.setBinaryStream(index,
2947
- // new ByteArrayInputStream(blob.unsafeBytes(), blob.getBegin(), blob.getRealSize()),
2948
- // blob.getRealSize() // length
2949
- // );
2950
- // JDBC 4.0 :
2951
- //statement.setBlob(index,
2952
- // new ByteArrayInputStream(bytes.unsafeBytes(), bytes.getBegin(), bytes.getRealSize())
2953
- //);
2954
- }
2955
- }
2956
- }
2452
+ final IRubyObject attribute, final int type) throws SQLException {
2957
2453
 
2958
- protected void setClobParameter(final ThreadContext context,
2959
- final Connection connection, final PreparedStatement statement,
2960
- final int index, final Object value,
2961
- final IRubyObject column, final int type) throws SQLException {
2962
- if ( value instanceof IRubyObject ) {
2963
- setClobParameter(context, connection, statement, index, (IRubyObject) value, column, type);
2454
+ if ( value instanceof RubyIO ) { // IO/File
2455
+ // JDBC 4.0: statement.setBlob(index, ((RubyIO) value).getInStream());
2456
+ statement.setBinaryStream(index, ((RubyIO) value).getInStream());
2964
2457
  }
2965
- else {
2966
- if ( value == null ) statement.setNull(index, Types.CLOB);
2967
- else {
2968
- statement.setClob(index, (Reader) value);
2969
- }
2458
+ else { // should be a RubyString
2459
+ final ByteList blob = value.asString().getByteList();
2460
+ statement.setBytes(index, blob.bytes());
2461
+
2462
+ // JDBC 4.0 :
2463
+ //statement.setBlob(index,
2464
+ // new ByteArrayInputStream(bytes.unsafeBytes(), bytes.getBegin(), bytes.getRealSize())
2465
+ //);
2970
2466
  }
2971
2467
  }
2972
2468
 
2973
2469
  protected void setClobParameter(final ThreadContext context,
2974
2470
  final Connection connection, final PreparedStatement statement,
2975
2471
  final int index, final IRubyObject value,
2976
- final IRubyObject column, final int type) throws SQLException {
2472
+ final IRubyObject attribute, final int type) throws SQLException {
2977
2473
  if ( value.isNil() ) statement.setNull(index, Types.CLOB);
2978
2474
  else {
2979
2475
  if ( value instanceof RubyIO ) { // IO/File
@@ -2990,35 +2486,32 @@ public class RubyJdbcConnection extends RubyObject {
2990
2486
 
2991
2487
  protected void setObjectParameter(final ThreadContext context,
2992
2488
  final Connection connection, final PreparedStatement statement,
2993
- final int index, Object value,
2994
- final IRubyObject column, final int type) throws SQLException {
2995
- if (value instanceof IRubyObject) {
2996
- value = ((IRubyObject) value).toJava(Object.class);
2997
- }
2998
- if ( value == null ) statement.setNull(index, Types.JAVA_OBJECT);
2999
- statement.setObject(index, value);
3000
- }
2489
+ final int index, IRubyObject value,
2490
+ final IRubyObject attribute, final int type) throws SQLException {
3001
2491
 
3002
- protected final Connection getConnection() {
3003
- return getConnection(false);
2492
+ statement.setObject(index, value.toJava(Object.class));
3004
2493
  }
3005
2494
 
3006
- protected Connection getConnection(boolean error) {
3007
- final Connection connection = (Connection) dataGetStruct(); // synchronized
3008
- if ( connection == null && error ) {
3009
- final RubyClass errorClass = getConnectionNotEstablished( getRuntime() );
3010
- throw new RaiseException(getRuntime(), errorClass, "no connection available", false);
2495
+ protected Connection getConnection(ThreadContext context, boolean reportMissingConnection) {
2496
+ Connection connection = (Connection) dataGetStruct(); // synchronized
2497
+
2498
+ if (connection == null && reportMissingConnection) {
2499
+ throw new RaiseException(getRuntime(), ActiveRecord(context).getClass("ConnectionNotEstablished"),
2500
+ "no connection available", false);
3011
2501
  }
2502
+
3012
2503
  return connection;
3013
2504
  }
3014
2505
 
3015
- private IRubyObject setConnection(final Connection connection) {
3016
- close( getConnection(false) ); // close previously open connection if there is one
2506
+ private IRubyObject setConnection(ThreadContext context, final Connection connection) {
2507
+ close(getConnection(context, false)); // close previously open connection if there is one
2508
+
2509
+ final IRubyObject rubyConnectionObject = connection != null ?
2510
+ convertJavaToRuby(connection) : context.runtime.getNil();
3017
2511
 
3018
- final IRubyObject rubyConnectionObject =
3019
- connection != null ? convertJavaToRuby(connection) : getRuntime().getNil();
3020
2512
  setInstanceVariable( "@connection", rubyConnectionObject );
3021
2513
  dataWrapStruct(connection);
2514
+
3022
2515
  return rubyConnectionObject;
3023
2516
  }
3024
2517
 
@@ -3152,25 +2645,6 @@ public class RubyJdbcConnection extends RubyObject {
3152
2645
  return tables;
3153
2646
  }
3154
2647
 
3155
- /**
3156
- * NOTE: since 1.3.0 only present for binary compatibility (with extensions).
3157
- *
3158
- * @depreacated no longer used - replaced with
3159
- * {@link #matchTables(Ruby, Connection, String, String, String, String[], boolean)}
3160
- * please update your sub-class esp. if you're overriding this method !
3161
- */
3162
- @Deprecated
3163
- protected SQLBlock tableLookupBlock(final Ruby runtime,
3164
- final String catalog, final String schemaPattern,
3165
- final String tablePattern, final String[] types) {
3166
- return new SQLBlock() {
3167
- @Override
3168
- public IRubyObject call(final Connection connection) throws SQLException {
3169
- return matchTables(runtime, connection, catalog, schemaPattern, tablePattern, types, false);
3170
- }
3171
- };
3172
- }
3173
-
3174
2648
  protected static final int COLUMN_NAME = 4;
3175
2649
  protected static final int DATA_TYPE = 5;
3176
2650
  protected static final int TYPE_NAME = 6;
@@ -3212,24 +2686,7 @@ public class RubyJdbcConnection extends RubyObject {
3212
2686
  private static IRubyObject defaultValueFromResultSet(final Ruby runtime, final ResultSet resultSet)
3213
2687
  throws SQLException {
3214
2688
  final String defaultValue = resultSet.getString(COLUMN_DEF);
3215
- return defaultValue == null ? runtime.getNil() : RubyString.newUnicodeString(runtime, defaultValue);
3216
- }
3217
-
3218
- /**
3219
- * Internal API that might be subject to change!
3220
- * @since 1.3.18
3221
- */
3222
- protected static boolean usesType(final Ruby runtime) { // AR 4.2
3223
- return runtime.getModule("ActiveRecord").getConstantAt("Type") != null;
3224
- }
3225
-
3226
- /**
3227
- * This method is considered internal and is not part of AR-JDBC's Java ext
3228
- * API and thus might be subject to change in the future.
3229
- * Please copy it to your own class if you rely on it to avoid issues.
3230
- */
3231
- protected static boolean isAr42(IRubyObject column) {
3232
- return column.respondsTo("cast_type");
2689
+ return defaultValue == null ? runtime.getNil() : RubyString.newInternalFromJavaExternal(runtime, defaultValue);
3233
2690
  }
3234
2691
 
3235
2692
  protected RubyArray mapColumnsResult(final ThreadContext context,
@@ -3258,9 +2715,9 @@ public class RubyJdbcConnection extends RubyObject {
3258
2715
  final IRubyObject config = getConfig(context);
3259
2716
  while ( results.next() ) {
3260
2717
  final String colName = results.getString(COLUMN_NAME);
3261
- final RubyString railsColumnName = RubyString.newUnicodeString(runtime, caseConvertIdentifierForRails(metaData, colName));
2718
+ final RubyString railsColumnName = RubyString.newInternalFromJavaExternal(runtime, caseConvertIdentifierForRails(metaData, colName));
3262
2719
  final IRubyObject defaultValue = defaultValueFromResultSet( runtime, results );
3263
- final RubyString sqlType = RubyString.newUnicodeString( runtime, typeFromResultSet(results) );
2720
+ final RubyString sqlType = RubyString.newInternalFromJavaExternal( runtime, typeFromResultSet(results) );
3264
2721
  final RubyBoolean nullable = runtime.newBoolean( ! results.getString(IS_NULLABLE).trim().equals("NO") );
3265
2722
  final IRubyObject[] args;
3266
2723
  if ( lookupCastType ) {
@@ -3355,22 +2812,8 @@ public class RubyJdbcConnection extends RubyObject {
3355
2812
  return keys;
3356
2813
  }
3357
2814
 
3358
- protected IRubyObject mapGeneratedKey(final Ruby runtime, final ResultSet genKeys)
3359
- throws SQLException {
3360
- return runtime.newFixnum( genKeys.getLong(1) );
3361
- }
3362
-
3363
- protected IRubyObject mapGeneratedKeysOrUpdateCount(final ThreadContext context,
3364
- final Connection connection, final Statement statement) throws SQLException {
3365
- final Ruby runtime = context.getRuntime();
3366
- final IRubyObject key = mapGeneratedKeys(runtime, connection, statement);
3367
- return ( key == null || key.isNil() ) ? runtime.newFixnum( statement.getUpdateCount() ) : key;
3368
- }
3369
-
3370
- @Deprecated
3371
- protected IRubyObject unmarshalKeysOrUpdateCount(final ThreadContext context,
3372
- final Connection connection, final Statement statement) throws SQLException {
3373
- return mapGeneratedKeysOrUpdateCount(context, connection, statement);
2815
+ protected IRubyObject mapGeneratedKey(final Ruby runtime, final ResultSet genKeys) throws SQLException {
2816
+ return runtime.newFixnum(genKeys.getLong(1));
3374
2817
  }
3375
2818
 
3376
2819
  private Boolean supportsGeneratedKeys;
@@ -3386,64 +2829,6 @@ public class RubyJdbcConnection extends RubyObject {
3386
2829
  return supportsGeneratedKeys.booleanValue();
3387
2830
  }
3388
2831
 
3389
- /**
3390
- * @deprecated no longer used - kept for binary compatibility, this method
3391
- * is confusing since it closes the result set it receives and thus was
3392
- * replaced with {@link #mapGeneratedKeys(Ruby, Connection, Statement)}
3393
- */
3394
- @Deprecated
3395
- public static IRubyObject unmarshal_id_result(
3396
- final Ruby runtime, final ResultSet genKeys) throws SQLException {
3397
- try {
3398
- if (genKeys.next() && genKeys.getMetaData().getColumnCount() > 0) {
3399
- return runtime.newFixnum( genKeys.getLong(1) );
3400
- }
3401
- return runtime.getNil();
3402
- }
3403
- finally { close(genKeys); }
3404
- }
3405
-
3406
- protected IRubyObject mapResults(final ThreadContext context,
3407
- final Connection connection, final Statement statement,
3408
- final boolean downCase) throws SQLException {
3409
-
3410
- final Ruby runtime = context.getRuntime();
3411
- IRubyObject result;
3412
- ResultSet resultSet = statement.getResultSet();
3413
- try {
3414
- result = mapToRawResult(context, runtime, connection, resultSet, downCase);
3415
- }
3416
- finally { close(resultSet); }
3417
-
3418
- if ( ! statement.getMoreResults() ) return result;
3419
-
3420
- final List<IRubyObject> results = new ArrayList<IRubyObject>();
3421
- results.add(result);
3422
-
3423
- do {
3424
- resultSet = statement.getResultSet();
3425
- try {
3426
- result = mapToRawResult(context, runtime, connection, resultSet, downCase);
3427
- }
3428
- finally { close(resultSet); }
3429
-
3430
- results.add(result);
3431
- }
3432
- while ( statement.getMoreResults() );
3433
-
3434
- return runtime.newArray(results);
3435
- }
3436
-
3437
- /**
3438
- * @deprecated no longer used but kept for binary compatibility
3439
- */
3440
- @Deprecated
3441
- protected IRubyObject unmarshalResult(final ThreadContext context,
3442
- final DatabaseMetaData metaData, final ResultSet resultSet,
3443
- final boolean downCase) throws SQLException {
3444
- return mapToRawResult(context, context.getRuntime(), metaData, resultSet, downCase);
3445
- }
3446
-
3447
2832
  /**
3448
2833
  * Converts a JDBC result set into an array (rows) of hashes (row).
3449
2834
  *
@@ -3462,20 +2847,6 @@ public class RubyJdbcConnection extends RubyObject {
3462
2847
  return results;
3463
2848
  }
3464
2849
 
3465
- @Deprecated
3466
- @SuppressWarnings("unchecked")
3467
- private IRubyObject mapToRawResult(final ThreadContext context, final Ruby runtime,
3468
- final DatabaseMetaData metaData, final ResultSet resultSet,
3469
- final boolean downCase) throws SQLException {
3470
-
3471
- final ColumnData[] columns = extractColumns(runtime, metaData, resultSet, downCase);
3472
-
3473
- final RubyArray results = runtime.newArray();
3474
- // [ { 'col1': 1, 'col2': 2 }, { 'col1': 3, 'col2': 4 } ]
3475
- populateFromResultSet(context, runtime, (List<IRubyObject>) results, resultSet, columns);
3476
- return results;
3477
- }
3478
-
3479
2850
  private IRubyObject yieldResultRows(final ThreadContext context, final Ruby runtime,
3480
2851
  final Connection connection, final ResultSet resultSet,
3481
2852
  final Block block) throws SQLException {
@@ -3509,23 +2880,6 @@ public class RubyJdbcConnection extends RubyObject {
3509
2880
  return setupColumns(runtime, connection, resultSet.getMetaData(), downCase);
3510
2881
  }
3511
2882
 
3512
- @Deprecated
3513
- protected ColumnData[] extractColumns(final Ruby runtime,
3514
- final DatabaseMetaData metaData, final ResultSet resultSet,
3515
- final boolean downCase) throws SQLException {
3516
- return setupColumns(runtime, metaData, resultSet.getMetaData(), downCase);
3517
- }
3518
-
3519
- /**
3520
- * @deprecated renamed and parameterized to {@link #withConnection(ThreadContext, boolean, Callable)}
3521
- */
3522
- @Deprecated
3523
- @SuppressWarnings("unchecked")
3524
- protected Object withConnectionAndRetry(final ThreadContext context, final SQLBlock block)
3525
- throws RaiseException {
3526
- return withConnection(context, block);
3527
- }
3528
-
3529
2883
  protected <T> T withConnection(final ThreadContext context, final Callable<T> block)
3530
2884
  throws RaiseException {
3531
2885
  try {
@@ -3544,7 +2898,7 @@ public class RubyJdbcConnection extends RubyObject {
3544
2898
  do {
3545
2899
  if ( retry > 0 ) reconnect(context); // we're retrying running block
3546
2900
 
3547
- final Connection connection = getConnection(true);
2901
+ final Connection connection = getConnection(context, true);
3548
2902
  boolean autoCommit = true; // retry in-case getAutoCommit throws
3549
2903
  try {
3550
2904
  autoCommit = connection.getAutoCommit();
@@ -3607,15 +2961,6 @@ public class RubyJdbcConnection extends RubyObject {
3607
2961
  throw wrapException(context, exception);
3608
2962
  }
3609
2963
 
3610
- /**
3611
- * @deprecated use {@link #wrapException(ThreadContext, Throwable)} instead
3612
- * for overriding how exceptions are handled use {@link #handleException(ThreadContext, Throwable)}
3613
- */
3614
- @Deprecated
3615
- protected RuntimeException wrap(final ThreadContext context, final Throwable exception) {
3616
- return wrapException(context, exception);
3617
- }
3618
-
3619
2964
  protected RaiseException wrapException(final ThreadContext context, final Throwable exception) {
3620
2965
  final Ruby runtime = context.getRuntime();
3621
2966
  if ( exception instanceof SQLException ) {
@@ -3703,63 +3048,19 @@ public class RubyJdbcConnection extends RubyObject {
3703
3048
  return end;
3704
3049
  }
3705
3050
 
3706
- /**
3707
- * JDBC connection helper that handles mapping results to
3708
- * <code>ActiveRecord::Result</code> (available since AR-3.1).
3709
- *
3710
- * @see #populateFromResultSet(ThreadContext, Ruby, List, ResultSet, RubyJdbcConnection.ColumnData[])
3711
- * @author kares
3712
- */
3713
- protected static class ResultHandler {
3714
-
3715
- protected static Boolean USE_RESULT;
3716
-
3717
- // AR-3.2 : initialize(columns, rows)
3718
- // AR-4.0 : initialize(columns, rows, column_types = {})
3719
- protected static Boolean INIT_COLUMN_TYPES = Boolean.FALSE;
3051
+ // maps a AR::Result row
3052
+ protected IRubyObject mapRow(final ThreadContext context, final Ruby runtime,
3053
+ final ColumnData[] columns, final ResultSet resultSet,
3054
+ final RubyJdbcConnection connection) throws SQLException {
3055
+ final RubyArray row = runtime.newArray(columns.length);
3720
3056
 
3721
- protected static Boolean FORCE_HASH_ROWS = Boolean.FALSE;
3722
-
3723
- private static volatile ResultHandler instance;
3724
-
3725
- public static ResultHandler getInstance(final Ruby runtime) {
3726
- if ( instance == null ) {
3727
- synchronized(ResultHandler.class) {
3728
- if ( instance == null ) { // fine to initialize twice
3729
- setInstance( new ResultHandler(runtime) );
3730
- }
3731
- }
3732
- }
3733
- return instance;
3057
+ for (int i = 0; i < columns.length; i++) {
3058
+ final ColumnData column = columns[i];
3059
+ row.append(connection.jdbcToRuby(context, runtime, column.index, column.type, resultSet));
3734
3060
  }
3735
3061
 
3736
- protected static synchronized void setInstance(final ResultHandler instance) {
3737
- ResultHandler.instance = instance;
3738
- }
3739
-
3740
- protected ResultHandler(final Ruby runtime) {
3741
- final RubyClass result = getResult(runtime);
3742
- USE_RESULT = result != null && result != runtime.getNilClass();
3743
- }
3744
-
3745
- public IRubyObject mapRow(final ThreadContext context, final Ruby runtime,
3746
- final ColumnData[] columns, final ResultSet resultSet,
3747
- final RubyJdbcConnection connection) throws SQLException {
3748
-
3749
- if ( USE_RESULT ) { // maps a AR::Result row
3750
- final RubyArray row = runtime.newArray(columns.length);
3751
-
3752
- for ( int i = 0; i < columns.length; i++ ) {
3753
- final ColumnData column = columns[i];
3754
- row.append( connection.jdbcToRuby(context, runtime, column.index, column.type, resultSet) );
3755
- }
3756
-
3757
- return row;
3758
- }
3759
- else {
3760
- return mapRawRow(context, runtime, columns, resultSet, connection);
3761
- }
3762
- }
3062
+ return row;
3063
+ }
3763
3064
 
3764
3065
  IRubyObject mapRawRow(final ThreadContext context, final Ruby runtime,
3765
3066
  final ColumnData[] columns, final ResultSet resultSet,
@@ -3777,37 +3078,20 @@ public class RubyJdbcConnection extends RubyObject {
3777
3078
  return row;
3778
3079
  }
3779
3080
 
3780
- public IRubyObject newResult(final ThreadContext context, final Ruby runtime,
3781
- final ColumnData[] columns, final IRubyObject rows) { // rows array
3782
- if ( USE_RESULT ) { // ActiveRecord::Result.new(columns, rows)
3783
- final RubyClass result = getResult(runtime);
3784
- return result.callMethod( context, "new", initArgs(runtime, columns, rows), Block.NULL_BLOCK );
3785
- }
3786
- return rows; // contains { 'col1' => 1, ... } Hash-es
3787
- }
3788
-
3789
- private IRubyObject[] initArgs(final Ruby runtime,
3790
- final ColumnData[] columns, final IRubyObject rows) {
3081
+ protected IRubyObject newResult(final ThreadContext context, ColumnData[] columns, IRubyObject rows) {
3082
+ RubyClass result = ActiveRecord(context).getClass("Result");
3791
3083
 
3792
- final IRubyObject[] args;
3084
+ return Helpers.invoke(context, result, "new", columnsToArray(context, columns), rows);
3085
+ }
3793
3086
 
3794
- final RubyArray cols = RubyArray.newArray(runtime, columns.length);
3087
+ private RubyArray columnsToArray(ThreadContext context, ColumnData[] columns) {
3088
+ final RubyArray cols = RubyArray.newArray(context.runtime, columns.length);
3795
3089
 
3796
- if ( INIT_COLUMN_TYPES ) { // NOTE: NOT IMPLEMENTED
3797
- for ( int i = 0; i < columns.length; i++ ) {
3798
- cols.append( columns[i].name );
3799
- }
3800
- args = new IRubyObject[] { cols, rows };
3801
- }
3802
- else {
3803
- for ( int i = 0; i < columns.length; i++ ) {
3804
- cols.append( columns[i].name );
3805
- }
3806
- args = new IRubyObject[] { cols, rows };
3807
- }
3808
- return args;
3090
+ for ( int i = 0; i < columns.length; i++ ) {
3091
+ cols.append( columns[i].name );
3809
3092
  }
3810
3093
 
3094
+ return cols;
3811
3095
  }
3812
3096
 
3813
3097
 
@@ -3876,14 +3160,8 @@ public class RubyJdbcConnection extends RubyObject {
3876
3160
  return new TableName(catalog, schema, name);
3877
3161
  }
3878
3162
 
3879
- /**
3880
- * @deprecated use {@link #extractTableName(Connection, String, String, String)}
3881
- */
3882
- @Deprecated
3883
- protected TableName extractTableName(
3884
- final Connection connection, final String schema,
3885
- final String tableName) throws IllegalArgumentException, SQLException {
3886
- return extractTableName(connection, null, schema, tableName);
3163
+ protected IRubyObject valueForDatabase(final ThreadContext context, final IRubyObject attribute) {
3164
+ return attribute.callMethod(context, "value_for_database");
3887
3165
  }
3888
3166
 
3889
3167
  protected static final class ColumnData {
@@ -3921,32 +3199,8 @@ public class RubyJdbcConnection extends RubyObject {
3921
3199
  } else {
3922
3200
  name = caseConvertIdentifierForRails(connection, name);
3923
3201
  }
3924
- final RubyString columnName = RubyString.newUnicodeString(runtime, name);
3925
- final int columnType = resultMetaData.getColumnType(i);
3926
- columns[i - 1] = new ColumnData(columnName, columnType, i);
3927
- }
3928
-
3929
- return columns;
3930
- }
3931
-
3932
- @Deprecated
3933
- private ColumnData[] setupColumns(
3934
- final Ruby runtime,
3935
- final DatabaseMetaData metaData,
3936
- final ResultSetMetaData resultMetaData,
3937
- final boolean downCase) throws SQLException {
3938
3202
 
3939
- final int columnCount = resultMetaData.getColumnCount();
3940
- final ColumnData[] columns = new ColumnData[columnCount];
3941
-
3942
- for ( int i = 1; i <= columnCount; i++ ) { // metadata is one-based
3943
- String name = resultMetaData.getColumnLabel(i);
3944
- if ( downCase ) {
3945
- name = name.toLowerCase();
3946
- } else {
3947
- name = caseConvertIdentifierForRails(metaData, name);
3948
- }
3949
- final RubyString columnName = RubyString.newUnicodeString(runtime, name);
3203
+ final RubyString columnName = RubyString.newInternalFromJavaExternal(runtime, name);
3950
3204
  final int columnType = resultMetaData.getColumnType(i);
3951
3205
  columns[i - 1] = new ColumnData(columnName, columnType, i);
3952
3206
  }
@@ -3998,6 +3252,10 @@ public class RubyJdbcConnection extends RubyObject {
3998
3252
  }
3999
3253
  }
4000
3254
 
3255
+ public static void debugMessage(final ThreadContext context, final IRubyObject item) {
3256
+ debugMessage(context, item.callMethod(context, "inspect").asString().toString());
3257
+ }
3258
+
4001
3259
  protected static void debugErrorSQL(final ThreadContext context, final String sql) {
4002
3260
  if ( debug || ( context != null && context.runtime.isDebug() ) ) {
4003
3261
  final PrintStream out = context != null ? context.runtime.getOut() : System.out;