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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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;