activerecord-jdbc-adapter 50.8-java → 51.1-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 (62) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -2
  3. data/.travis.yml +26 -51
  4. data/Gemfile +3 -1
  5. data/README.md +9 -11
  6. data/Rakefile +15 -78
  7. data/activerecord-jdbc-adapter.gemspec +2 -2
  8. data/lib/active_record/connection_adapters/mssql_adapter.rb +1 -0
  9. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +1 -0
  10. data/lib/arjdbc/abstract/core.rb +4 -12
  11. data/lib/arjdbc/abstract/database_statements.rb +4 -10
  12. data/lib/arjdbc/abstract/statement_cache.rb +4 -4
  13. data/lib/arjdbc/abstract/transaction_support.rb +2 -9
  14. data/lib/arjdbc/jdbc.rb +4 -0
  15. data/lib/arjdbc/jdbc/column.rb +11 -5
  16. data/lib/arjdbc/jdbc/connection_methods.rb +9 -2
  17. data/lib/arjdbc/jdbc/error.rb +1 -1
  18. data/lib/arjdbc/jdbc/jdbc.rake +4 -0
  19. data/lib/arjdbc/mssql.rb +7 -0
  20. data/lib/arjdbc/mssql/adapter.rb +804 -0
  21. data/lib/arjdbc/mssql/column.rb +200 -0
  22. data/lib/arjdbc/mssql/connection_methods.rb +79 -0
  23. data/lib/arjdbc/mssql/explain_support.rb +99 -0
  24. data/lib/arjdbc/mssql/limit_helpers.rb +231 -0
  25. data/lib/arjdbc/mssql/lock_methods.rb +77 -0
  26. data/lib/arjdbc/mssql/types.rb +343 -0
  27. data/lib/arjdbc/mssql/utils.rb +82 -0
  28. data/lib/arjdbc/mysql/adapter.rb +14 -11
  29. data/lib/arjdbc/mysql/connection_methods.rb +9 -18
  30. data/lib/arjdbc/postgresql/adapter.rb +108 -59
  31. data/lib/arjdbc/postgresql/column.rb +3 -6
  32. data/lib/arjdbc/postgresql/connection_methods.rb +3 -12
  33. data/lib/arjdbc/postgresql/oid_types.rb +14 -93
  34. data/lib/arjdbc/sqlite3/adapter.rb +171 -140
  35. data/lib/arjdbc/sqlite3/connection_methods.rb +1 -2
  36. data/lib/arjdbc/tasks/database_tasks.rb +36 -16
  37. data/lib/arjdbc/tasks/databases.rake +75 -32
  38. data/lib/arjdbc/tasks/databases3.rake +215 -0
  39. data/lib/arjdbc/tasks/databases4.rake +39 -0
  40. data/lib/arjdbc/version.rb +1 -1
  41. data/rakelib/01-tomcat.rake +2 -2
  42. data/rakelib/02-test.rake +3 -0
  43. data/rakelib/compile.rake +70 -0
  44. data/rakelib/db.rake +7 -21
  45. data/rakelib/rails.rake +4 -5
  46. data/src/java/arjdbc/ArJdbcModule.java +15 -5
  47. data/src/java/arjdbc/derby/DerbyRubyJdbcConnection.java +2 -2
  48. data/src/java/arjdbc/jdbc/ConnectionFactory.java +87 -0
  49. data/src/java/arjdbc/jdbc/DataSourceConnectionFactory.java +1 -0
  50. data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +41 -120
  51. data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +14 -310
  52. data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +2 -2
  53. data/src/java/arjdbc/postgresql/ByteaUtils.java +1 -0
  54. data/src/java/arjdbc/postgresql/PgResultSetMetaDataWrapper.java +23 -0
  55. data/src/java/arjdbc/postgresql/PostgreSQLResult.java +13 -21
  56. data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +46 -41
  57. data/src/java/arjdbc/util/DateTimeUtils.java +5 -141
  58. data/src/java/arjdbc/util/QuotingUtils.java +7 -6
  59. data/src/java/arjdbc/util/StringHelper.java +20 -6
  60. metadata +25 -16
  61. data/src/java/arjdbc/jdbc/RubyConnectionFactory.java +0 -61
  62. data/src/java/arjdbc/postgresql/PgDateTimeUtils.java +0 -52
@@ -1,3 +1,3 @@
1
1
  module ArJdbc
2
- VERSION = '50.8'
2
+ VERSION = '51.1'
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);
@@ -285,7 +284,7 @@ public class RubyJdbcConnection extends RubyObject {
285
284
  public static int mapTransactionIsolationLevel(final IRubyObject isolation) {
286
285
  final Object isolationString;
287
286
  if ( isolation instanceof RubySymbol ) {
288
- isolationString = ((RubySymbol) isolation).asJavaString(); // RubySymbol (interned)
287
+ isolationString = isolation.toString(); // RubySymbol.toString (interned)
289
288
  }
290
289
  else {
291
290
  isolationString = isolation.asString().toString().toLowerCase(Locale.ENGLISH).intern();
@@ -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(); }
@@ -2740,23 +2667,27 @@ public class RubyJdbcConnection extends RubyObject {
2740
2667
 
2741
2668
  final IRubyObject value = value_site.call(context, attribute, attribute);
2742
2669
 
2743
- if ( value instanceof RubyInteger ) {
2670
+ if (value instanceof RubyInteger) {
2744
2671
  return "integer";
2745
2672
  }
2746
2673
 
2747
- if ( value instanceof RubyNumeric ) {
2674
+ if (value instanceof RubyNumeric) {
2748
2675
  return "float";
2749
2676
  }
2750
2677
 
2751
- if ( value instanceof RubyTime ) {
2678
+ if (value instanceof RubyTime) {
2752
2679
  return "timestamp";
2753
2680
  }
2754
2681
 
2682
+ if (value instanceof RubyBoolean) {
2683
+ return "boolean";
2684
+ }
2685
+
2755
2686
  return "string";
2756
2687
  }
2757
2688
 
2758
2689
  protected final RubyTime timeInDefaultTimeZone(final ThreadContext context, final IRubyObject value) {
2759
- return timeInDefaultTimeZone(context, DateTimeUtils.toTime(context, value));
2690
+ return timeInDefaultTimeZone(context, toTime(context, value));
2760
2691
  }
2761
2692
 
2762
2693
  protected final RubyTime timeInDefaultTimeZone(final ThreadContext context, final RubyTime time) {
@@ -2768,14 +2699,11 @@ public class RubyJdbcConnection extends RubyObject {
2768
2699
  return timeInDefaultTZ;
2769
2700
  }
2770
2701
 
2771
- protected final DateTime dateTimeInDefaultTimeZone(final ThreadContext context, final DateTime dateTime) {
2772
- final DateTimeZone defaultZone = getDefaultTimeZone(context);
2773
- if (defaultZone == dateTime.getZone()) return dateTime;
2774
- return dateTime.withZone(defaultZone);
2775
- }
2776
-
2777
2702
  public static RubyTime toTime(final ThreadContext context, final IRubyObject value) {
2778
- 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;
2779
2707
  }
2780
2708
 
2781
2709
  protected boolean isDefaultTimeZoneUTC(final ThreadContext context) {
@@ -2788,7 +2716,7 @@ public class RubyJdbcConnection extends RubyObject {
2788
2716
 
2789
2717
  private String default_timezone(final ThreadContext context) {
2790
2718
  final RubyClass base = getBase(context.runtime);
2791
- return default_timezone.call(context, base, base).asJavaString(); // :utc (or :local)
2719
+ return default_timezone.call(context, base, base).toString(); // :utc (or :local)
2792
2720
  }
2793
2721
 
2794
2722
  // ActiveRecord::Base.default_timezone
@@ -2875,8 +2803,8 @@ public class RubyJdbcConnection extends RubyObject {
2875
2803
  final int index, IRubyObject value,
2876
2804
  final IRubyObject attribute, final int type) throws SQLException {
2877
2805
 
2878
- final RubyTime timeValue = DateTimeUtils.toTime(context, value);
2879
- final DateTime dateTime = dateTimeInDefaultTimeZone(context, timeValue.getDateTime());
2806
+ final RubyTime timeValue = timeInDefaultTimeZone(context, value);
2807
+ final DateTime dateTime = timeValue.getDateTime();
2880
2808
  final Timestamp timestamp = new Timestamp(dateTime.getMillis());
2881
2809
  // 1942-11-30T01:02:03.123_456
2882
2810
  if (timeValue.getNSec() > 0) timestamp.setNanos((int) (timestamp.getNanos() + timeValue.getNSec()));
@@ -2970,13 +2898,14 @@ public class RubyJdbcConnection extends RubyObject {
2970
2898
  final RubySymbol type = (RubySymbol) attributeSQLType(context, attribute);
2971
2899
 
2972
2900
  // For some reason the driver doesn't like "character varying" as a type
2973
- if ( type.eql(context.runtime.newSymbol("string")) ) return "varchar";
2901
+ if ( type.eql(context.runtime.newSymbol("string")) ){
2902
+ return "text";
2903
+ }
2974
2904
 
2975
2905
  final RubyHash nativeTypes = (RubyHash) getAdapter().callMethod(context, "native_database_types");
2976
- // e.g. `integer: { name: 'integer' }`
2977
2906
  final RubyHash typeInfo = (RubyHash) nativeTypes.op_aref(context, type);
2978
2907
 
2979
- return typeInfo.op_aref(context, context.runtime.newSymbol("name")).toString();
2908
+ return typeInfo.op_aref(context, context.runtime.newSymbol("name")).asString().toString();
2980
2909
  }
2981
2910
 
2982
2911
  protected void setXmlParameter(final ThreadContext context,
@@ -3077,7 +3006,7 @@ public class RubyJdbcConnection extends RubyObject {
3077
3006
  private void handleNotConnected() {
3078
3007
  final Ruby runtime = getRuntime();
3079
3008
  final RubyClass errorClass = getConnectionNotEstablished( runtime );
3080
- throw runtime.newRaiseException(errorClass, "no connection available");
3009
+ throw new RaiseException(runtime, errorClass, "no connection available", false);
3081
3010
  }
3082
3011
 
3083
3012
  /**
@@ -3517,14 +3446,12 @@ public class RubyJdbcConnection extends RubyObject {
3517
3446
  if ( ! gotConnection ) { // SQLException from driver/data-source
3518
3447
  reconnectOnRetry = connected;
3519
3448
  }
3520
- else if (!autoCommit) {
3521
- // never retry inside a transaction
3522
- break;
3523
- }
3524
3449
  else if ( isTransient(exception) ) {
3525
3450
  reconnectOnRetry = false; // continue;
3526
3451
  }
3527
3452
  else {
3453
+ if ( ! autoCommit ) break; // do not retry if (inside) transactions
3454
+
3528
3455
  if ( isConnectionValid(context, getConnectionImpl()) ) {
3529
3456
  break; // connection not broken yet failed (do not retry)
3530
3457
  }
@@ -3614,7 +3541,7 @@ public class RubyJdbcConnection extends RubyObject {
3614
3541
  return (RaiseException) exception;
3615
3542
  }
3616
3543
  if ( exception instanceof RuntimeException ) {
3617
- return wrapException(context, context.runtime.getRuntimeError(), exception);
3544
+ return RaiseException.createNativeRaiseException(runtime, exception);
3618
3545
  }
3619
3546
  // NOTE: compat - maybe makes sense or maybe not (e.g. IOException) :
3620
3547
  return wrapException(context, getJDBCError(runtime), exception);
@@ -3627,7 +3554,7 @@ public class RubyJdbcConnection extends RubyObject {
3627
3554
 
3628
3555
  public static RaiseException wrapException(final ThreadContext context,
3629
3556
  final RubyClass errorClass, final Throwable exception, final String message) {
3630
- final RaiseException error = context.runtime.newRaiseException(errorClass, message);
3557
+ final RaiseException error = new RaiseException(context.runtime, errorClass, message, true);
3631
3558
  error.initCause(exception);
3632
3559
  return error;
3633
3560
  }
@@ -3961,12 +3888,6 @@ public class RubyJdbcConnection extends RubyObject {
3961
3888
  }
3962
3889
  }
3963
3890
 
3964
- public static void debugMessage(final ThreadContext context, final IRubyObject obj) {
3965
- if ( isDebug(context.runtime) ) {
3966
- debugMessage(context.runtime, obj.callMethod(context, "inspect"));
3967
- }
3968
- }
3969
-
3970
3891
  public static void debugMessage(final Ruby runtime, final String msg, final Object e) {
3971
3892
  if ( isDebug(runtime) ) {
3972
3893
  final PrintStream out = runtime != null ? runtime.getOut() : System.out;