activerecord-jdbc-adapter 51.8-java → 52.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -2
  3. data/.travis.yml +26 -51
  4. data/README.md +9 -11
  5. data/Rakefile +19 -74
  6. data/activerecord-jdbc-adapter.gemspec +2 -2
  7. data/lib/active_record/connection_adapters/mssql_adapter.rb +1 -0
  8. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +1 -0
  9. data/lib/arjdbc/abstract/core.rb +2 -12
  10. data/lib/arjdbc/abstract/database_statements.rb +24 -10
  11. data/lib/arjdbc/abstract/statement_cache.rb +4 -4
  12. data/lib/arjdbc/db2/adapter.rb +52 -2
  13. data/lib/arjdbc/jdbc.rb +4 -0
  14. data/lib/arjdbc/jdbc/column.rb +11 -5
  15. data/lib/arjdbc/jdbc/connection_methods.rb +9 -2
  16. data/lib/arjdbc/jdbc/jdbc.rake +4 -0
  17. data/lib/arjdbc/mssql.rb +7 -0
  18. data/lib/arjdbc/mssql/adapter.rb +804 -0
  19. data/lib/arjdbc/mssql/column.rb +200 -0
  20. data/lib/arjdbc/mssql/connection_methods.rb +79 -0
  21. data/lib/arjdbc/mssql/explain_support.rb +99 -0
  22. data/lib/arjdbc/mssql/limit_helpers.rb +231 -0
  23. data/lib/arjdbc/mssql/lock_methods.rb +77 -0
  24. data/lib/arjdbc/mssql/types.rb +343 -0
  25. data/lib/arjdbc/mssql/utils.rb +82 -0
  26. data/lib/arjdbc/mysql/adapter.rb +22 -14
  27. data/lib/arjdbc/mysql/connection_methods.rb +9 -18
  28. data/lib/arjdbc/postgresql/adapter.rb +102 -75
  29. data/lib/arjdbc/postgresql/column.rb +3 -6
  30. data/lib/arjdbc/postgresql/connection_methods.rb +3 -12
  31. data/lib/arjdbc/postgresql/oid_types.rb +12 -86
  32. data/lib/arjdbc/sqlite3/adapter.rb +88 -92
  33. data/lib/arjdbc/sqlite3/connection_methods.rb +0 -1
  34. data/lib/arjdbc/tasks/database_tasks.rb +36 -16
  35. data/lib/arjdbc/tasks/databases.rake +75 -32
  36. data/lib/arjdbc/tasks/databases3.rake +215 -0
  37. data/lib/arjdbc/tasks/databases4.rake +39 -0
  38. data/lib/arjdbc/version.rb +1 -1
  39. data/rakelib/01-tomcat.rake +2 -2
  40. data/rakelib/02-test.rake +3 -0
  41. data/rakelib/compile.rake +70 -0
  42. data/rakelib/db.rake +7 -21
  43. data/rakelib/rails.rake +4 -5
  44. data/src/java/arjdbc/ArJdbcModule.java +15 -5
  45. data/src/java/arjdbc/derby/DerbyRubyJdbcConnection.java +2 -2
  46. data/src/java/arjdbc/jdbc/ConnectionFactory.java +87 -0
  47. data/src/java/arjdbc/jdbc/DataSourceConnectionFactory.java +1 -0
  48. data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +29 -113
  49. data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +14 -310
  50. data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +2 -2
  51. data/src/java/arjdbc/postgresql/PgResultSetMetaDataWrapper.java +23 -0
  52. data/src/java/arjdbc/postgresql/PostgreSQLResult.java +13 -21
  53. data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +50 -44
  54. data/src/java/arjdbc/util/DateTimeUtils.java +5 -141
  55. data/src/java/arjdbc/util/QuotingUtils.java +7 -6
  56. metadata +26 -11
  57. data/src/java/arjdbc/jdbc/RubyConnectionFactory.java +0 -61
  58. data/src/java/arjdbc/postgresql/PgDateTimeUtils.java +0 -52
@@ -1,3 +1,3 @@
1
1
  module ArJdbc
2
- VERSION = '51.8'
2
+ VERSION = '52.0'
3
3
  end
@@ -1,6 +1,6 @@
1
1
  namespace :'tomcat-jndi' do # contains a FS JNDI impl (for tests)
2
2
 
3
- TOMCAT_MAVEN_REPO = 'https://repo1.maven.org/maven2/org/apache/tomcat'
3
+ TOMCAT_MAVEN_REPO = 'http://repo2.maven.org/maven2/org/apache/tomcat'
4
4
  TOMCAT_VERSION = '7.0.54'
5
5
 
6
6
  DOWNLOAD_DIR = File.expand_path('../test/jars', File.dirname(__FILE__))
@@ -48,4 +48,4 @@ namespace :'tomcat-jndi' do # contains a FS JNDI impl (for tests)
48
48
  rm jar_path if File.exist?(jar_path)
49
49
  end
50
50
 
51
- end
51
+ end
data/rakelib/02-test.rake CHANGED
@@ -58,6 +58,7 @@ end
58
58
  test_task_for :Derby, :desc => 'Run tests against (embedded) DerbyDB'
59
59
  test_task_for :H2, :desc => 'Run tests against H2 database engine'
60
60
  test_task_for :HSQLDB, :desc => 'Run tests against HyperSQL (Java) database'
61
+ test_task_for :MSSQL, :driver => :jtds, :database_name => 'MS-SQL (SQLServer)'
61
62
  test_task_for :MySQL #, :prereqs => 'db:mysql'
62
63
  task :test_mysql2 => :test_mysql
63
64
  test_task_for :PostgreSQL, :driver => ENV['JDBC_POSTGRES_VERSION'] || 'postgres' #, :prereqs => 'db:postgresql'
@@ -75,6 +76,8 @@ end
75
76
  test_task_for adapter, :desc => "Run tests against #{adapter} (ensure driver is on class-path)"
76
77
  end
77
78
 
79
+ #test_task_for :MSSQL, :name => 'test_sqlserver', :driver => nil, :database_name => 'MS-SQL using SQLJDBC'
80
+
78
81
  test_task_for :AS400, :desc => "Run tests against AS400 (DB2) (ensure driver is on class-path)",
79
82
  :files => FileList["test/db2*_test.rb"] + FileList["test/db/db2/*_test.rb"]
80
83
 
@@ -0,0 +1,70 @@
1
+ jar_file = File.join(*%w(lib arjdbc jdbc adapter_java.jar))
2
+ begin
3
+ require 'ant'
4
+ directory classes = "pkg/classes"
5
+ CLEAN << classes
6
+
7
+ driver_jars = []
8
+ # PostgreSQL driver :
9
+ driver_jars << Dir.glob("jdbc-postgres/lib/*.jar").sort.last
10
+
11
+ file jar_file => FileList['src/java/**/*.java', 'pkg/classes'] do
12
+ rm_rf FileList["#{classes}/**/*"]
13
+ ant.javac :srcdir => "src/java", :destdir => "pkg/classes",
14
+ :source => "7", :target => "7", :debug => true, :deprecation => true,
15
+ :classpath => "${java.class.path}:${sun.boot.class.path}:#{driver_jars.join(':')}",
16
+ :includeantRuntime => false
17
+
18
+ ant.tstamp do |ts|
19
+ ts.format(:property => 'TODAY', :pattern => 'yyyy-MM-dd HH:mm:ss')
20
+ end
21
+
22
+ begin
23
+ require 'arjdbc/version'
24
+ rescue LoadError
25
+ path = File.expand_path('../lib', File.dirname(__FILE__))
26
+ unless $LOAD_PATH.include?(path)
27
+ $LOAD_PATH << path; retry
28
+ end
29
+ end
30
+
31
+ gem_version = Gem::Version.create(ArJdbc::VERSION)
32
+ if gem_version.segments.last == 'DEV'
33
+ version = gem_version.segments[0...-1] # 1.3.0.DEV -> 1.3.0
34
+ else
35
+ version = gem_version.segments.dup
36
+ end
37
+ version = version.join('.')
38
+
39
+ ant.manifest :file => 'MANIFEST.MF' do |mf|
40
+ mf.attribute :name => 'Built-By', :value => '${user.name}'
41
+ mf.attribute :name => 'Built-Time', :value => '${TODAY}'
42
+ mf.attribute :name => 'Built-Jdk', :value => '${java.version}'
43
+ mf.attribute :name => 'Built-JRuby', :value => JRUBY_VERSION
44
+
45
+ mf.attribute :name => 'Specification-Title', :value => 'ActiveRecord-JDBC'
46
+ mf.attribute :name => 'Specification-Version', :value => '1.3'
47
+ mf.attribute :name => 'Specification-Vendor', :value => 'JRuby'
48
+ mf.attribute :name => 'Implementation-Version', :value => version
49
+ mf.attribute :name => 'Implementation-Vendor', :value => 'The JRuby Team'
50
+ end
51
+
52
+ ant.jar :basedir => "pkg/classes", :includes => "**/*.class",
53
+ :destfile => jar_file, :manifest => 'MANIFEST.MF'
54
+ end
55
+
56
+ desc "Compile the native Java code."
57
+ task :jar => jar_file
58
+
59
+ namespace :jar do
60
+ task :force do
61
+ rm jar_file if File.exist?(jar_file)
62
+ Rake::Task['jar'].invoke
63
+ end
64
+ end
65
+
66
+ rescue LoadError
67
+ task :jar do
68
+ puts "Run 'jar' with JRuby to re-compile the agent extension class"
69
+ end
70
+ end
data/rakelib/db.rake CHANGED
@@ -4,35 +4,25 @@ namespace :db do
4
4
  task :mysql do
5
5
  require File.expand_path('../../test/shared_helper', __FILE__)
6
6
  fail "could not create test database: mysql executable not found" unless mysql = which('mysql')
7
-
8
7
  load 'test/db/mysql_config.rb' # rescue nil
9
8
  enc = MYSQL_CONFIG[:encoding] || 'utf8' # 'utf8mb4'
10
9
  puts MYSQL_CONFIG.inspect if $VERBOSE
11
-
12
- clean_script = sql_script <<-SQL, 'mysqlclean'
13
- DROP USER #{MYSQL_CONFIG[:username]}@localhost;
14
- SQL
15
-
10
+ # DROP USER arjdbc@localhost; __ERROR 1396 (HY000): Operation CREATE USER failed__
16
11
  script = sql_script <<-SQL, 'mysql'
17
12
  DROP DATABASE IF EXISTS `#{MYSQL_CONFIG[:database]}`;
18
13
  CREATE DATABASE `#{MYSQL_CONFIG[:database]}` DEFAULT CHARACTER SET `#{enc}` COLLATE `#{enc}_general_ci`;
19
- CREATE USER #{MYSQL_CONFIG[:username]}@localhost IDENTIFIED BY '#{MYSQL_CONFIG[:password]}';
20
14
  GRANT ALL PRIVILEGES ON `#{MYSQL_CONFIG[:database]}`.* TO #{MYSQL_CONFIG[:username]}@localhost;
21
15
  GRANT ALL PRIVILEGES ON `test\_%`.* TO #{MYSQL_CONFIG[:username]}@localhost;
16
+ SET PASSWORD FOR #{MYSQL_CONFIG[:username]}@localhost = PASSWORD('#{MYSQL_CONFIG[:password]}');
22
17
  SQL
23
-
24
18
  params = { '-u' => 'root' }
25
- if ENV['DATABASE_YML']
26
- require 'yaml'
27
- params['-p'] = YAML.load(File.new(ENV['DATABASE_YML']))["production"]["password"]
19
+ if ENV['DATABASE_YML']; require 'yaml'
20
+ params['-p'] = YAML.load(File.new(ENV['DATABASE_YML']))["production"]["password"]
28
21
  end
29
22
  params['-u'] = ENV['MY_USER'] if ENV['MY_USER']
30
23
  params['-p'] = ENV['MY_PASSWORD'] if ENV['MY_PASSWORD']
31
-
32
24
  puts "Creating MySQL (test) database: #{MYSQL_CONFIG[:database]}"
33
- mysql_cmd = "#{mysql} -f #{params.map {|k, v| "#{k}#{v}"}.join(' ')}"
34
- sh "cat #{clean_script.path} | #{mysql_cmd}", verbose: false
35
- sh "cat #{script.path} | #{mysql_cmd}", verbose: $VERBOSE # so password is not echoed
25
+ sh "cat #{script.path} | #{mysql} -f #{params.map {|k, v| "#{k}#{v}"}.join(' ')}", :verbose => $VERBOSE # so password is not echoed
36
26
  end
37
27
 
38
28
  desc "Creates the test database for PostgreSQL"
@@ -40,10 +30,8 @@ GRANT ALL PRIVILEGES ON `test\_%`.* TO #{MYSQL_CONFIG[:username]}@localhost;
40
30
  require File.expand_path('../../test/shared_helper', __FILE__)
41
31
  fail 'could not create test database: psql executable not found' unless psql = which('psql')
42
32
  fail 'could not create test database: missing "postgres" role' unless PostgresHelper.postgres_role?
43
-
44
33
  load 'test/db/postgres_config.rb' # rescue nil
45
34
  puts POSTGRES_CONFIG.inspect if $VERBOSE
46
-
47
35
  script = sql_script <<-SQL, 'psql'
48
36
  DROP DATABASE IF EXISTS #{POSTGRES_CONFIG[:database]};
49
37
  DROP USER IF EXISTS #{POSTGRES_CONFIG[:username]};
@@ -52,14 +40,12 @@ CREATE DATABASE #{POSTGRES_CONFIG[:database]} OWNER #{POSTGRES_CONFIG[:username]
52
40
  TEMPLATE template0
53
41
  ENCODING '#{POSTGRES_CONFIG[:encoding]}' LC_COLLATE '#{POSTGRES_CONFIG[:collate]}' LC_CTYPE '#{POSTGRES_CONFIG[:collate]}';
54
42
  SQL
55
-
56
43
  params = { '-U' => ENV['PSQL_USER'] || 'postgres' }
57
44
  params['-q'] = nil unless $VERBOSE
58
-
59
45
  puts "Creating PostgreSQL (test) database: #{POSTGRES_CONFIG[:database]}"
60
- sh "cat #{script.path} | #{psql} #{params.to_a.join(' ')}", verbose: $VERBOSE
46
+ sh "cat #{script.path} | #{psql} #{params.to_a.join(' ')}", :verbose => $VERBOSE
61
47
  end
62
- task postgres: :postgresql
48
+ task :postgres => :postgresql
63
49
 
64
50
  private
65
51
 
data/rakelib/rails.rake CHANGED
@@ -9,15 +9,14 @@ namespace :rails do
9
9
  if ENV['RAILS']
10
10
  ar_path = File.join(ENV['RAILS'], 'activerecord')
11
11
  end
12
-
12
+
13
13
  unless ar_path && File.exist?(ar_path)
14
- ar_path = `bundle info --path activerecord`.lines.last.chomp
14
+ ar_path = `bundle info --path activerecord`.chomp
15
15
  end
16
16
 
17
17
  unless File.exist? ar_test_dir = File.join(ar_path, 'test')
18
18
  raise "can not directly load Rails tests;" +
19
- " try setting a local repository path e.g. export RAILS=`pwd`/../rails;" +
20
- " failed guess: #{ar_path}"
19
+ " try setting a local repository path e.g. export RAILS=`pwd`/../rails"
21
20
  end
22
21
 
23
22
  driver = "jdbc-#{ENV['DRIVER'] ? ENV['DRIVER'].downcase : (adapter =~ /postgres/i ? 'postgres' : adapter)}"
@@ -51,7 +50,7 @@ namespace :rails do
51
50
  ruby_opts_string += " -C \"#{ar_path}\""
52
51
  ruby_opts_string += " -rbundler/setup"
53
52
  ruby_opts_string += " -rminitest -rminitest/excludes" unless ENV['NO_EXCLUDES'].eql?('true')
54
- file_list = ENV["TEST"] ? FileList[ ENV["TEST"].split(',') ] : test_files_finder.call
53
+ file_list = ENV["TEST"] ? FileList[ ENV["TEST"] ] : test_files_finder.call
55
54
  file_list_string = file_list.map { |fn| "\"#{fn}\"" }.join(' ')
56
55
  # test_loader_code = "-e \"ARGV.each{|f| require f}\"" # :direct
57
56
  option_list = ( ENV["TESTOPTS"] || ENV["TESTOPT"] || ENV["TEST_OPTS"] || '' )
@@ -29,6 +29,7 @@ import java.util.HashMap;
29
29
  import java.util.Map;
30
30
  import java.util.WeakHashMap;
31
31
 
32
+ import org.jruby.NativeException;
32
33
  import org.jruby.Ruby;
33
34
  import org.jruby.RubyArray;
34
35
  import org.jruby.RubyClass;
@@ -147,7 +148,13 @@ public class ArJdbcModule {
147
148
  }
148
149
  }
149
150
  catch (ClassNotFoundException e) { /* ignored */ }
150
- catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
151
+ catch (NoSuchMethodException e) {
152
+ throw newNativeException(runtime, e);
153
+ }
154
+ catch (IllegalAccessException e) {
155
+ throw newNativeException(runtime, e);
156
+ }
157
+ catch (InvocationTargetException e) {
151
158
  throw newNativeException(runtime, e);
152
159
  }
153
160
 
@@ -256,15 +263,18 @@ public class ArJdbcModule {
256
263
  try {
257
264
  return klass.getMethod(name, argType).invoke(null, arg);
258
265
  }
259
- catch (IllegalAccessException | InvocationTargetException e) {
266
+ catch (IllegalAccessException e) {
267
+ throw newNativeException(runtime, e);
268
+ }
269
+ catch (InvocationTargetException e) {
260
270
  throw newNativeException(runtime, e);
261
271
  }
262
272
  }
263
273
 
264
274
  private static RaiseException newNativeException(final Ruby runtime, final Throwable cause) {
265
- final RaiseException error = runtime.newRuntimeError(cause.toString());
266
- error.initCause(cause);
267
- return error;
275
+ RubyClass nativeClass = runtime.getClass(NativeException.CLASS_NAME);
276
+ NativeException nativeException = new NativeException(runtime, nativeClass, cause);
277
+ return new RaiseException(cause, nativeException);
268
278
  }
269
279
 
270
280
  @JRubyMethod(meta = true)
@@ -83,8 +83,8 @@ public class DerbyRubyJdbcConnection extends RubyJdbcConnection {
83
83
  final int minor = jdbcDriver.getMinorVersion();
84
84
  if ( major < 10 || ( major == 10 && minor < 5 ) ) {
85
85
  final RubyClass errorClass = getConnectionNotEstablished(context.runtime);
86
- throw context.runtime.newRaiseException(errorClass,
87
- "adapter requires Derby >= 10.5 got: " + major + "." + minor + "");
86
+ throw new RaiseException(context.runtime, errorClass,
87
+ "adapter requires Derby >= 10.5 got: " + major + "." + minor + "", false);
88
88
  }
89
89
  if ( major == 10 && minor < 8 ) { // 10.8 ~ supports JDBC 4.1
90
90
  // config[:connection_alive_sql] ||= 'SELECT 1 FROM SYS.SYSSCHEMAS FETCH FIRST 1 ROWS ONLY'
@@ -27,6 +27,12 @@ package arjdbc.jdbc;
27
27
 
28
28
  import java.sql.Connection;
29
29
  import java.sql.SQLException;
30
+ import javax.sql.DataSource;
31
+
32
+ import org.jruby.RubyObject;
33
+ import org.jruby.RubyString;
34
+ import org.jruby.runtime.ThreadContext;
35
+ import org.jruby.runtime.builtin.IRubyObject;
30
36
 
31
37
  /**
32
38
  * Interface to be implemented in Ruby for retrieving a new connection.
@@ -43,3 +49,84 @@ public interface ConnectionFactory {
43
49
  Connection newConnection() throws SQLException;
44
50
 
45
51
  }
52
+
53
+ class DataSourceConnectionFactoryImpl implements ConnectionFactory {
54
+
55
+ private final DataSource dataSource;
56
+ final String username, password; // optional
57
+
58
+ public DataSourceConnectionFactoryImpl(final DataSource dataSource) {
59
+ this.dataSource = dataSource;
60
+ this.username = null; this.password = null;
61
+ }
62
+
63
+ public DataSourceConnectionFactoryImpl(final DataSource dataSource,
64
+ final String username, final String password) {
65
+ this.dataSource = dataSource;
66
+ this.username = username; this.password = password;
67
+ }
68
+
69
+ @Override
70
+ public Connection newConnection() throws SQLException {
71
+ if ( username != null ) {
72
+ dataSource.getConnection(username, password);
73
+ }
74
+ return dataSource.getConnection();
75
+ }
76
+
77
+ DataSource getDataSource() { return dataSource; } /* for tests */
78
+
79
+ }
80
+
81
+ class DriverConnectionFactoryImpl implements ConnectionFactory {
82
+
83
+ private final DriverWrapper driverWrapper;
84
+ final String url;
85
+ final String username, password; // null allowed
86
+
87
+ public DriverConnectionFactoryImpl(final DriverWrapper driver, final String url) {
88
+ this.driverWrapper = driver; this.url = url;
89
+ this.username = null; this.password = null;
90
+ }
91
+
92
+ public DriverConnectionFactoryImpl(final DriverWrapper driver, final String url,
93
+ final String username, final String password) {
94
+ this.driverWrapper = driver; this.url = url;
95
+ this.username = username; this.password = password;
96
+ }
97
+
98
+ @Override
99
+ public Connection newConnection() throws SQLException {
100
+ return driverWrapper.connect(url, username, password);
101
+ }
102
+
103
+ DriverWrapper getDriverWrapper() { return driverWrapper; } /* for tests */
104
+
105
+ }
106
+
107
+ // @legacy ActiveRecord::ConnectionAdapters::JdbcDriver
108
+ class RubyConnectionFactoryImpl implements ConnectionFactory {
109
+
110
+ private final IRubyObject driver;
111
+ final RubyString url;
112
+ final IRubyObject username, password; // null allowed
113
+
114
+ private final RubyObject contextProvider;
115
+
116
+ public RubyConnectionFactoryImpl(final IRubyObject driver, final RubyString url,
117
+ final IRubyObject username, final IRubyObject password) {
118
+ this.driver = driver; this.url = url;
119
+ this.username = username; this.password = password;
120
+ contextProvider = (RubyObject) driver;
121
+ }
122
+
123
+ @Override
124
+ public Connection newConnection() throws SQLException {
125
+ final ThreadContext context = contextProvider.getRuntime().getCurrentContext();
126
+ final IRubyObject connection = driver.callMethod(context, "connection", new IRubyObject[] { url, username, password });
127
+ return (Connection) connection.toJava(Connection.class);
128
+ }
129
+
130
+ IRubyObject getDriver() { return driver; } /* for tests */
131
+
132
+ }
@@ -68,6 +68,7 @@ final class DataSourceConnectionFactory implements ConnectionFactory {
68
68
 
69
69
  @Override
70
70
  public Connection newConnection() throws SQLException {
71
+ DataSource dataSource = this.dataSource;
71
72
  // in case DS failed previously look it up again from JNDI :
72
73
  if (dataSource == null) {
73
74
  lookupDataSource();
@@ -128,7 +128,6 @@ public class RubyJdbcConnection extends RubyObject {
128
128
  private boolean lazy = false; // final once set on initialize
129
129
  private boolean jndi; // final once set on initialize
130
130
  private boolean configureConnection = true; // final once initialized
131
- private int fetchSize = 0; // 0 = JDBC default
132
131
 
133
132
  protected RubyJdbcConnection(Ruby runtime, RubyClass metaClass) {
134
133
  super(runtime, metaClass);
@@ -487,7 +486,7 @@ public class RubyJdbcConnection extends RubyObject {
487
486
  savepoint = ((IRubyObject) savepoint).toJava(Savepoint.class);
488
487
  }
489
488
 
490
- releaseSavepoint(connection, (Savepoint) savepoint);
489
+ connection.releaseSavepoint((Savepoint) savepoint);
491
490
  return context.nil;
492
491
  }
493
492
  catch (SQLException e) {
@@ -495,11 +494,6 @@ public class RubyJdbcConnection extends RubyObject {
495
494
  }
496
495
  }
497
496
 
498
- // MSSQL doesn't support releasing savepoints so we make it possible to override the actual release action
499
- protected void releaseSavepoint(final Connection connection, final Savepoint savepoint) throws SQLException {
500
- connection.releaseSavepoint(savepoint);
501
- }
502
-
503
497
  protected static RuntimeException newSavepointNotSetError(final ThreadContext context, final IRubyObject name, final String op) {
504
498
  RubyClass StatementInvalid = ActiveRecord(context).getClass("StatementInvalid");
505
499
  return context.runtime.newRaiseException(StatementInvalid, "could not " + op + " savepoint: '" + name + "' (not set)");
@@ -577,11 +571,6 @@ public class RubyJdbcConnection extends RubyObject {
577
571
  else {
578
572
  this.configureConnection = value != context.runtime.getFalse();
579
573
  }
580
-
581
- IRubyObject jdbcFetchSize = getConfigValue(context, "jdbc_fetch_size");
582
- if (jdbcFetchSize != context.nil) {
583
- this.fetchSize = RubyNumeric.fix2int(jdbcFetchSize);
584
- }
585
574
  }
586
575
 
587
576
  @JRubyMethod(name = "adapter")
@@ -727,10 +716,7 @@ public class RubyJdbcConnection extends RubyObject {
727
716
 
728
717
  private void connectImpl(final boolean forceConnection) throws SQLException {
729
718
  setConnection( forceConnection ? newConnection() : null );
730
- if (forceConnection) {
731
- if (getConnectionImpl() == null) throw new SQLException("Didn't get a connection. Wrong URL?");
732
- configureConnection();
733
- }
719
+ if ( forceConnection ) configureConnection();
734
720
  }
735
721
 
736
722
  @JRubyMethod(name = "read_only?")
@@ -832,7 +818,6 @@ public class RubyJdbcConnection extends RubyObject {
832
818
  // is called, so we have to process the result sets as we get them
833
819
  // this shouldn't be an issue in most cases since we're only getting 1 result set anyways
834
820
  result = mapExecuteResult(context, connection, resultSet);
835
- resultSet.close();
836
821
  } else {
837
822
  result = context.runtime.newFixnum(updateCount);
838
823
  }
@@ -866,7 +851,6 @@ public class RubyJdbcConnection extends RubyObject {
866
851
  else {
867
852
  statement.setEscapeProcessing(escapeProcessing.isTrue());
868
853
  }
869
- if (fetchSize != 0) statement.setFetchSize(fetchSize);
870
854
  return statement;
871
855
  }
872
856
 
@@ -888,31 +872,15 @@ public class RubyJdbcConnection extends RubyObject {
888
872
  return mapQueryResult(context, connection, resultSet);
889
873
  }
890
874
 
891
- private static String[] createStatementPk(IRubyObject pk) {
892
- String[] statementPk;
893
- if (pk instanceof RubyArray) {
894
- RubyArray ary = (RubyArray) pk;
895
- int size = ary.size();
896
- statementPk = new String[size];
897
- for (int i = 0; i < size; i++) {
898
- statementPk[i] = sqlString(ary.eltInternal(i));
899
- }
900
- } else {
901
- statementPk = new String[] { sqlString(pk) };
902
- }
903
- return statementPk;
904
- }
905
-
906
875
  /**
907
876
  * Executes an INSERT SQL statement
908
877
  * @param context
909
878
  * @param sql
910
- * @param pk Rails PK
911
879
  * @return ActiveRecord::Result
912
880
  * @throws SQLException
913
881
  */
914
- @JRubyMethod(name = "execute_insert_pk", required = 2)
915
- public IRubyObject execute_insert_pk(final ThreadContext context, final IRubyObject sql, final IRubyObject pk) {
882
+ @JRubyMethod(name = "execute_insert", required = 1)
883
+ public IRubyObject execute_insert(final ThreadContext context, final IRubyObject sql) {
916
884
  return withConnection(context, new Callable<IRubyObject>() {
917
885
  public IRubyObject call(final Connection connection) throws SQLException {
918
886
  Statement statement = null;
@@ -920,13 +888,7 @@ public class RubyJdbcConnection extends RubyObject {
920
888
  try {
921
889
 
922
890
  statement = createStatement(context, connection);
923
-
924
- if (pk == context.nil || pk == context.fals || !supportsGeneratedKeys(connection)) {
925
- statement.executeUpdate(query, Statement.RETURN_GENERATED_KEYS);
926
- } else {
927
- statement.executeUpdate(query, createStatementPk(pk));
928
- }
929
-
891
+ statement.executeUpdate(query, Statement.RETURN_GENERATED_KEYS);
930
892
  return mapGeneratedKeys(context, connection, statement);
931
893
 
932
894
  } catch (final SQLException e) {
@@ -939,35 +901,23 @@ public class RubyJdbcConnection extends RubyObject {
939
901
  });
940
902
  }
941
903
 
942
- @Deprecated
943
- @JRubyMethod(name = "execute_insert", required = 1)
944
- public IRubyObject execute_insert(final ThreadContext context, final IRubyObject sql) {
945
- return execute_insert_pk(context, sql, context.nil);
946
- }
947
-
948
904
  /**
949
905
  * Executes an INSERT SQL statement using a prepared statement
950
906
  * @param context
951
907
  * @param sql
952
908
  * @param binds RubyArray of values to be bound to the query
953
- * @param pk Rails PK
954
909
  * @return ActiveRecord::Result
955
910
  * @throws SQLException
956
911
  */
957
- @JRubyMethod(name = "execute_insert_pk", required = 3)
958
- public IRubyObject execute_insert_pk(final ThreadContext context, final IRubyObject sql, final IRubyObject binds,
959
- final IRubyObject pk) {
912
+ @JRubyMethod(name = "execute_insert", required = 2)
913
+ public IRubyObject execute_insert(final ThreadContext context, final IRubyObject sql, final IRubyObject binds) {
960
914
  return withConnection(context, new Callable<IRubyObject>() {
961
915
  public IRubyObject call(final Connection connection) throws SQLException {
962
916
  PreparedStatement statement = null;
963
917
  final String query = sqlString(sql);
964
918
  try {
965
- if (pk == context.nil || pk == context.fals || !supportsGeneratedKeys(connection)) {
966
- statement = connection.prepareStatement(query, Statement.RETURN_GENERATED_KEYS);
967
- } else {
968
- statement = connection.prepareStatement(query, createStatementPk(pk));
969
- }
970
919
 
920
+ statement = connection.prepareStatement(query, Statement.RETURN_GENERATED_KEYS);
971
921
  setStatementParameters(context, connection, statement, (RubyArray) binds);
972
922
  statement.executeUpdate();
973
923
  return mapGeneratedKeys(context, connection, statement);
@@ -982,12 +932,6 @@ public class RubyJdbcConnection extends RubyObject {
982
932
  });
983
933
  }
984
934
 
985
- @Deprecated
986
- @JRubyMethod(name = "execute_insert", required = 2)
987
- public IRubyObject execute_insert(final ThreadContext context, final IRubyObject binds, final IRubyObject sql) {
988
- return execute_insert_pk(context, sql, binds, context.nil);
989
- }
990
-
991
935
  /**
992
936
  * Executes an UPDATE (DELETE) SQL statement
993
937
  * @param context
@@ -1101,7 +1045,6 @@ public class RubyJdbcConnection extends RubyObject {
1101
1045
  else {
1102
1046
  final PreparedStatement prepStatement;
1103
1047
  statement = prepStatement = connection.prepareStatement(query);
1104
- if (fetchSize != 0) statement.setFetchSize(fetchSize);
1105
1048
  statement.setMaxRows(maxRows); // zero means there is no limit
1106
1049
  setStatementParameters(context, connection, prepStatement, binds);
1107
1050
  hasResult = prepStatement.execute();
@@ -1169,24 +1112,6 @@ public class RubyJdbcConnection extends RubyObject {
1169
1112
  });
1170
1113
  }
1171
1114
 
1172
- /**
1173
- * Prepares a query, returns a wrapped PreparedStatement. This takes care of exception wrapping
1174
- * @param context which context this method is executing on.
1175
- * @param sql the query to prepare-
1176
- * @return a Ruby <code>PreparedStatement</code>
1177
- */
1178
- @JRubyMethod(required = 1)
1179
- public IRubyObject prepare_statement(final ThreadContext context, final IRubyObject sql) {
1180
- return withConnection(context, new Callable<IRubyObject>() {
1181
- public IRubyObject call(Connection connection) throws SQLException {
1182
- final String query = sql.convertToString().getUnicodeValue();
1183
- PreparedStatement statement = connection.prepareStatement(query);
1184
- if (fetchSize != 0) statement.setFetchSize(fetchSize);
1185
- return JavaUtil.convertJavaToRuby(context.runtime, statement);
1186
- }
1187
- });
1188
- }
1189
-
1190
1115
  // Called from exec_query in abstract/database_statements
1191
1116
  /**
1192
1117
  * Executes a query and returns the (AR) result. There are three parameters:
@@ -1217,7 +1142,6 @@ public class RubyJdbcConnection extends RubyObject {
1217
1142
  statement = (PreparedStatement) JavaEmbedUtils.rubyToJava(cachedStatement);
1218
1143
  } else {
1219
1144
  statement = connection.prepareStatement(query);
1220
- if (fetchSize != 0) statement.setFetchSize(fetchSize);
1221
1145
  }
1222
1146
 
1223
1147
  setStatementParameters(context, connection, statement, (RubyArray) binds);
@@ -1225,7 +1149,12 @@ public class RubyJdbcConnection extends RubyObject {
1225
1149
  if (statement.execute()) {
1226
1150
  ResultSet resultSet = statement.getResultSet();
1227
1151
  IRubyObject results = mapQueryResult(context, connection, resultSet);
1228
- resultSet.close();
1152
+
1153
+ if (cached) {
1154
+ // Make sure we free the result set if we are caching the statement
1155
+ // It gets closed automatically when the statement is closed if we aren't caching
1156
+ resultSet.close();
1157
+ }
1229
1158
 
1230
1159
  return results;
1231
1160
  } else {
@@ -1878,7 +1807,7 @@ public class RubyJdbcConnection extends RubyObject {
1878
1807
  if ( url.isNil() || ( driver.isNil() && driver_instance.isNil() ) ) {
1879
1808
  final Ruby runtime = context.runtime;
1880
1809
  final RubyClass errorClass = getConnectionNotEstablished( runtime );
1881
- throw runtime.newRaiseException(errorClass, "adapter requires :driver class and jdbc :url");
1810
+ throw new RaiseException(runtime, errorClass, "adapter requires :driver class and jdbc :url", false);
1882
1811
  }
1883
1812
 
1884
1813
  final String jdbcURL = buildURL(context, url);
@@ -1895,7 +1824,7 @@ public class RubyJdbcConnection extends RubyObject {
1895
1824
  return factory;
1896
1825
  }
1897
1826
  else {
1898
- setConnectionFactory(factory = new RubyConnectionFactory(
1827
+ setConnectionFactory(factory = new RubyConnectionFactoryImpl(
1899
1828
  driver_instance, context.runtime.newString(jdbcURL),
1900
1829
  ( username.isNil() ? username : username.asString() ),
1901
1830
  ( password.isNil() ? password : password.asString() )
@@ -2556,8 +2485,6 @@ public class RubyJdbcConnection extends RubyObject {
2556
2485
  while ( arrayResult.next() ) {
2557
2486
  array.append( jdbcToRuby(context, runtime, 2, baseType, arrayResult) );
2558
2487
  }
2559
- arrayResult.close();
2560
-
2561
2488
  return array;
2562
2489
  }
2563
2490
  finally { if ( value != null ) value.free(); }
@@ -2760,7 +2687,7 @@ public class RubyJdbcConnection extends RubyObject {
2760
2687
  }
2761
2688
 
2762
2689
  protected final RubyTime timeInDefaultTimeZone(final ThreadContext context, final IRubyObject value) {
2763
- return timeInDefaultTimeZone(context, DateTimeUtils.toTime(context, value));
2690
+ return timeInDefaultTimeZone(context, toTime(context, value));
2764
2691
  }
2765
2692
 
2766
2693
  protected final RubyTime timeInDefaultTimeZone(final ThreadContext context, final RubyTime time) {
@@ -2772,14 +2699,11 @@ public class RubyJdbcConnection extends RubyObject {
2772
2699
  return timeInDefaultTZ;
2773
2700
  }
2774
2701
 
2775
- protected final DateTime dateTimeInDefaultTimeZone(final ThreadContext context, final DateTime dateTime) {
2776
- final DateTimeZone defaultZone = getDefaultTimeZone(context);
2777
- if (defaultZone == dateTime.getZone()) return dateTime;
2778
- return dateTime.withZone(defaultZone);
2779
- }
2780
-
2781
2702
  public static RubyTime toTime(final ThreadContext context, final IRubyObject value) {
2782
- return DateTimeUtils.toTime(context, value);
2703
+ if ( ! ( value instanceof RubyTime ) ) { // unlikely
2704
+ return (RubyTime) TypeConverter.convertToTypeWithCheck(value, context.runtime.getTime(), "to_time");
2705
+ }
2706
+ return (RubyTime) value;
2783
2707
  }
2784
2708
 
2785
2709
  protected boolean isDefaultTimeZoneUTC(final ThreadContext context) {
@@ -2879,8 +2803,8 @@ public class RubyJdbcConnection extends RubyObject {
2879
2803
  final int index, IRubyObject value,
2880
2804
  final IRubyObject attribute, final int type) throws SQLException {
2881
2805
 
2882
- final RubyTime timeValue = DateTimeUtils.toTime(context, value);
2883
- final DateTime dateTime = dateTimeInDefaultTimeZone(context, timeValue.getDateTime());
2806
+ final RubyTime timeValue = timeInDefaultTimeZone(context, value);
2807
+ final DateTime dateTime = timeValue.getDateTime();
2884
2808
  final Timestamp timestamp = new Timestamp(dateTime.getMillis());
2885
2809
  // 1942-11-30T01:02:03.123_456
2886
2810
  if (timeValue.getNSec() > 0) timestamp.setNanos((int) (timestamp.getNanos() + timeValue.getNSec()));
@@ -2974,7 +2898,7 @@ public class RubyJdbcConnection extends RubyObject {
2974
2898
  final RubySymbol type = (RubySymbol) attributeSQLType(context, attribute);
2975
2899
 
2976
2900
  // For some reason the driver doesn't like "character varying" as a type
2977
- if ( type.eql(context.runtime.newSymbol("string")) ) return "varchar";
2901
+ if ( type.eql(context.runtime.newSymbol("string")) ) return "text";
2978
2902
 
2979
2903
  final RubyHash nativeTypes = (RubyHash) getAdapter().callMethod(context, "native_database_types");
2980
2904
  // e.g. `integer: { name: 'integer' }`
@@ -3081,7 +3005,7 @@ public class RubyJdbcConnection extends RubyObject {
3081
3005
  private void handleNotConnected() {
3082
3006
  final Ruby runtime = getRuntime();
3083
3007
  final RubyClass errorClass = getConnectionNotEstablished( runtime );
3084
- throw runtime.newRaiseException(errorClass, "no connection available");
3008
+ throw new RaiseException(runtime, errorClass, "no connection available", false);
3085
3009
  }
3086
3010
 
3087
3011
  /**
@@ -3521,14 +3445,12 @@ public class RubyJdbcConnection extends RubyObject {
3521
3445
  if ( ! gotConnection ) { // SQLException from driver/data-source
3522
3446
  reconnectOnRetry = connected;
3523
3447
  }
3524
- else if (!autoCommit) {
3525
- // never retry inside a transaction
3526
- break;
3527
- }
3528
3448
  else if ( isTransient(exception) ) {
3529
3449
  reconnectOnRetry = false; // continue;
3530
3450
  }
3531
3451
  else {
3452
+ if ( ! autoCommit ) break; // do not retry if (inside) transactions
3453
+
3532
3454
  if ( isConnectionValid(context, getConnectionImpl()) ) {
3533
3455
  break; // connection not broken yet failed (do not retry)
3534
3456
  }
@@ -3618,7 +3540,7 @@ public class RubyJdbcConnection extends RubyObject {
3618
3540
  return (RaiseException) exception;
3619
3541
  }
3620
3542
  if ( exception instanceof RuntimeException ) {
3621
- return wrapException(context, context.runtime.getRuntimeError(), exception);
3543
+ return RaiseException.createNativeRaiseException(runtime, exception);
3622
3544
  }
3623
3545
  // NOTE: compat - maybe makes sense or maybe not (e.g. IOException) :
3624
3546
  return wrapException(context, getJDBCError(runtime), exception);
@@ -3631,7 +3553,7 @@ public class RubyJdbcConnection extends RubyObject {
3631
3553
 
3632
3554
  public static RaiseException wrapException(final ThreadContext context,
3633
3555
  final RubyClass errorClass, final Throwable exception, final String message) {
3634
- final RaiseException error = context.runtime.newRaiseException(errorClass, message);
3556
+ final RaiseException error = new RaiseException(context.runtime, errorClass, message, true);
3635
3557
  error.initCause(exception);
3636
3558
  return error;
3637
3559
  }
@@ -3965,12 +3887,6 @@ public class RubyJdbcConnection extends RubyObject {
3965
3887
  }
3966
3888
  }
3967
3889
 
3968
- public static void debugMessage(final ThreadContext context, final IRubyObject obj) {
3969
- if ( isDebug(context.runtime) ) {
3970
- debugMessage(context.runtime, obj.callMethod(context, "inspect"));
3971
- }
3972
- }
3973
-
3974
3890
  public static void debugMessage(final Ruby runtime, final String msg, final Object e) {
3975
3891
  if ( isDebug(runtime) ) {
3976
3892
  final PrintStream out = runtime != null ? runtime.getOut() : System.out;