activerecord-jdbc-adapter 72.1-java → 81.0.pre1-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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +129 -24
  3. data/.mise.toml +3 -0
  4. data/Gemfile +42 -47
  5. data/README.md +4 -2
  6. data/RUNNING_TESTS.md +9 -1
  7. data/Rakefile +63 -15
  8. data/activerecord-jdbc-adapter.gemspec +2 -2
  9. data/lib/arjdbc/abstract/core.rb +1 -1
  10. data/lib/arjdbc/abstract/database_statements.rb +22 -7
  11. data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
  12. data/lib/arjdbc/mysql/adapter_hash_config.rb +1 -2
  13. data/lib/arjdbc/postgresql/adapter.rb +4 -1
  14. data/lib/arjdbc/postgresql/schema_statements.rb +17 -0
  15. data/lib/arjdbc/sqlite3/adapter.rb +61 -11
  16. data/lib/arjdbc/sqlite3/column.rb +1 -1
  17. data/lib/arjdbc/version.rb +1 -1
  18. data/pom.xml +3 -3
  19. data/rakelib/db.rake +5 -3
  20. data/rakelib/rails.rake +0 -1
  21. data/src/java/arjdbc/ArJdbcModule.java +13 -10
  22. data/src/java/arjdbc/db2/DB2Module.java +4 -4
  23. data/src/java/arjdbc/db2/DB2RubyJdbcConnection.java +8 -9
  24. data/src/java/arjdbc/h2/H2Module.java +2 -1
  25. data/src/java/arjdbc/h2/H2RubyJdbcConnection.java +8 -7
  26. data/src/java/arjdbc/hsqldb/HSQLDBModule.java +5 -6
  27. data/src/java/arjdbc/jdbc/DataSourceConnectionFactory.java +4 -3
  28. data/src/java/arjdbc/jdbc/DriverWrapper.java +13 -8
  29. data/src/java/arjdbc/jdbc/JdbcResult.java +10 -7
  30. data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +168 -154
  31. data/src/java/arjdbc/mssql/MSSQLModule.java +3 -3
  32. data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +13 -9
  33. data/src/java/arjdbc/mysql/MySQLModule.java +3 -3
  34. data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +30 -24
  35. data/src/java/arjdbc/oracle/OracleModule.java +2 -3
  36. data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +22 -18
  37. data/src/java/arjdbc/postgresql/PostgreSQLModule.java +2 -3
  38. data/src/java/arjdbc/postgresql/PostgreSQLResult.java +24 -12
  39. data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +16 -12
  40. data/src/java/arjdbc/sqlite3/SQLite3Module.java +2 -3
  41. data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +78 -29
  42. data/src/java/arjdbc/util/DateTimeUtils.java +7 -5
  43. data/src/java/arjdbc/util/ObjectSupport.java +2 -2
  44. data/src/java/arjdbc/util/StringHelper.java +1 -1
  45. metadata +6 -6
  46. data/.travis.yml +0 -128
@@ -9,9 +9,18 @@ module ArJdbc
9
9
 
10
10
  NO_BINDS = [].freeze
11
11
 
12
- def exec_insert(sql, name = nil, binds = NO_BINDS, pk = nil, sequence_name = nil, returning: nil)
13
- sql = transform_query(sql)
12
+ def mark_transaction_written_if_write(sql)
13
+ if write_query?(sql)
14
+ ensure_writes_are_allowed(sql)
15
+ mark_transaction_written
16
+ end
17
+ end
14
18
 
19
+ def check_if_write_query(sql)
20
+ ensure_writes_are_allowed(sql) if write_query?(sql)
21
+ end
22
+
23
+ def exec_insert(sql, name = nil, binds = NO_BINDS, pk = nil, sequence_name = nil, returning: nil)
15
24
  if preventing_writes?
16
25
  raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
17
26
  end
@@ -34,8 +43,6 @@ module ArJdbc
34
43
  # It appears that at this point (AR 5.0) "prepare" should only ever be true
35
44
  # if prepared statements are enabled
36
45
  def internal_exec_query(sql, name = nil, binds = NO_BINDS, prepare: false, async: false, allow_retry: false, materialize_transactions: true)
37
- sql = transform_query(sql)
38
-
39
46
  if preventing_writes? && write_query?(sql)
40
47
  raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
41
48
  end
@@ -58,8 +65,6 @@ module ArJdbc
58
65
  end
59
66
 
60
67
  def exec_update(sql, name = 'SQL', binds = NO_BINDS)
61
- sql = transform_query(sql)
62
-
63
68
  if preventing_writes?
64
69
  raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
65
70
  end
@@ -86,13 +91,23 @@ module ArJdbc
86
91
 
87
92
  private
88
93
 
94
+ def without_prepared_statement?(binds)
95
+ !prepared_statements || binds.empty?
96
+ end
97
+
89
98
  def convert_legacy_binds_to_attributes(binds)
90
99
  binds.map do |column, value|
91
100
  ActiveRecord::Relation::QueryAttribute.new(nil, type_cast(value, column), ActiveModel::Type::Value.new)
92
101
  end
93
102
  end
94
103
 
95
- def raw_execute(sql, name, async: false, allow_retry: false, materialize_transactions: true)
104
+ def preprocess_query(sql)
105
+ check_if_write_query(sql) if respond_to?(:check_if_write_query, true)
106
+ mark_transaction_written_if_write(sql) if respond_to?(:mark_transaction_written_if_write, true)
107
+ sql
108
+ end
109
+
110
+ def raw_execute(sql, name, binds = [], prepare: false, async: false, allow_retry: false, materialize_transactions: true, batch: false)
96
111
  log(sql, name, async: async) do
97
112
  with_raw_connection(allow_retry: allow_retry, materialize_transactions: materialize_transactions) do |conn|
98
113
  result = conn.execute(sql)
Binary file
@@ -61,8 +61,7 @@ module ArJdbc
61
61
 
62
62
  properties["connectionCollation"] ||= config[:collation] if config[:collation]
63
63
 
64
- reconnect = config[:reconnect]
65
- properties["autoReconnect"] ||= reconnect.to_s unless reconnect.nil?
64
+ properties["autoReconnect"] ||= reconnect.to_s unless config[:reconnect].nil?
66
65
 
67
66
  properties["noDatetimeStringSync"] = true unless properties.key?("noDatetimeStringSync")
68
67
 
@@ -219,6 +219,10 @@ module ArJdbc
219
219
  true
220
220
  end
221
221
 
222
+ def supports_native_partitioning?
223
+ database_version >= 100_000
224
+ end
225
+
222
226
  def supports_insert_returning?
223
227
  true
224
228
  end
@@ -953,7 +957,6 @@ module ActiveRecord::ConnectionAdapters
953
957
  FEATURE_NOT_SUPPORTED = "0A000" # :nodoc:
954
958
 
955
959
  def execute_and_clear(sql, name, binds, prepare: false, async: false)
956
- sql = transform_query(sql)
957
960
  check_if_write_query(sql)
958
961
 
959
962
  if !prepare || without_prepared_statement?(binds)
@@ -6,6 +6,23 @@ module ArJdbc
6
6
  ForeignKeyDefinition = ActiveRecord::ConnectionAdapters::ForeignKeyDefinition
7
7
  Utils = ActiveRecord::ConnectionAdapters::PostgreSQL::Utils
8
8
 
9
+ def decode_string_array(value)
10
+ return value if value.is_a?(Array)
11
+ _arjdbc_array_parser.parse_pg_array(value)
12
+ end
13
+
14
+ private
15
+
16
+ def _arjdbc_array_parser
17
+ @_arjdbc_array_parser ||= begin
18
+ obj = Object.new
19
+ obj.extend(ActiveRecord::ConnectionAdapters::PostgreSQL::ArrayParser)
20
+ obj
21
+ end
22
+ end
23
+
24
+ public
25
+
9
26
  def foreign_keys(table_name)
10
27
  scope = quoted_scope(table_name)
11
28
  fk_info = internal_exec_query(<<~SQL, "SCHEMA", allow_retry: true, materialize_transactions: false)
@@ -223,17 +223,29 @@ module ArJdbc
223
223
 
224
224
  # REFERENTIAL INTEGRITY ====================================
225
225
 
226
+ def execute_batch(statements, name = nil, **kwargs)
227
+ if statements.is_a?(Array)
228
+ # SQLite JDBC doesn't support multiple statements in one execute
229
+ # Execute each statement separately
230
+ statements.each do |sql|
231
+ raw_execute(sql, name, **kwargs.merge(batch: true))
232
+ end
233
+ else
234
+ raw_execute(statements, name, batch: true, **kwargs)
235
+ end
236
+ end
237
+
226
238
  def disable_referential_integrity # :nodoc:
227
239
  old_foreign_keys = query_value("PRAGMA foreign_keys")
228
240
  old_defer_foreign_keys = query_value("PRAGMA defer_foreign_keys")
229
241
 
230
242
  begin
231
- execute("PRAGMA defer_foreign_keys = ON")
232
- execute("PRAGMA foreign_keys = OFF")
243
+ raw_execute("PRAGMA defer_foreign_keys = ON", "SCHEMA", allow_retry: false, materialize_transactions: false)
244
+ raw_execute("PRAGMA foreign_keys = OFF", "SCHEMA", allow_retry: false, materialize_transactions: false)
233
245
  yield
234
246
  ensure
235
- execute("PRAGMA defer_foreign_keys = #{old_defer_foreign_keys}")
236
- execute("PRAGMA foreign_keys = #{old_foreign_keys}")
247
+ raw_execute("PRAGMA defer_foreign_keys = #{old_defer_foreign_keys}", "SCHEMA", allow_retry: false, materialize_transactions: false)
248
+ raw_execute("PRAGMA foreign_keys = #{old_foreign_keys}", "SCHEMA", allow_retry: false, materialize_transactions: false)
237
249
  end
238
250
  end
239
251
 
@@ -388,6 +400,24 @@ module ArJdbc
388
400
  end
389
401
  end
390
402
 
403
+ # Returns a list of defined virtual tables (for Rails 8 compatibility)
404
+ VIRTUAL_TABLE_REGEX = /USING\s+(\w+)(?:\s*\((.*)\))?/im
405
+ def virtual_tables
406
+ query = <<~SQL
407
+ SELECT name, sql FROM sqlite_master
408
+ WHERE type = 'table' AND sql LIKE 'CREATE VIRTUAL TABLE%';
409
+ SQL
410
+
411
+ exec_query(query, "SCHEMA").cast_values.each_with_object({}) do |(name, sql), memo|
412
+ match = sql.match(VIRTUAL_TABLE_REGEX)
413
+ next unless match
414
+
415
+ module_name = match[1]
416
+ arguments = match[2] || ""
417
+ memo[name] = [module_name, arguments.strip]
418
+ end.to_a
419
+ end
420
+
391
421
  def build_insert_sql(insert) # :nodoc:
392
422
  sql = +"INSERT #{insert.into} #{insert.values_list}"
393
423
 
@@ -441,12 +471,17 @@ module ArJdbc
441
471
 
442
472
  rowid = is_column_the_rowid?(field, definitions)
443
473
 
444
- ActiveRecord::ConnectionAdapters::SQLite3Column.new(
445
- field["name"],
474
+ column_args = [field["name"]]
475
+ column_args << lookup_cast_type(field["type"])
476
+ column_args.push(
446
477
  default_value,
447
478
  type_metadata,
448
479
  field["notnull"].to_i == 0,
449
- default_function,
480
+ default_function
481
+ )
482
+
483
+ ActiveRecord::ConnectionAdapters::SQLite3Column.new(
484
+ *column_args,
450
485
  collation: field["collation"],
451
486
  auto_increment: field["auto_increment"],
452
487
  rowid: rowid,
@@ -579,7 +614,7 @@ module ArJdbc
579
614
  column_options[:stored] = column.virtual_stored?
580
615
  column_options[:type] = column.type
581
616
  elsif column.has_default?
582
- type = lookup_cast_type_from_column(column)
617
+ type = column.fetch_cast_type(self)
583
618
  default = type.deserialize(column.default)
584
619
  default = -> { column.default_function } if default.nil?
585
620
 
@@ -791,7 +826,17 @@ module ArJdbc
791
826
  DEFAULT_PRAGMAS.merge(pragmas).each do |pragma, value|
792
827
  if ::SQLite3::Pragmas.respond_to?(pragma)
793
828
  stmt = ::SQLite3::Pragmas.public_send(pragma, value)
794
- raw_execute(stmt, "SCHEMA")
829
+ # Skip pragma execution if we're inside a transaction and it's not allowed
830
+ begin
831
+ raw_execute(stmt, "SCHEMA")
832
+ rescue => e
833
+ if e.message.include?("Safety level may not be changed inside a transaction")
834
+ # Log warning and skip this pragma
835
+ warn "Cannot set pragma '#{pragma}' inside a transaction, skipping"
836
+ else
837
+ raise
838
+ end
839
+ end
795
840
  else
796
841
  warn "Unknown SQLite pragma: #{pragma}"
797
842
  end
@@ -830,6 +875,10 @@ module ActiveRecord::ConnectionAdapters
830
875
  def jdbc_connection_class
831
876
  ::ActiveRecord::ConnectionAdapters::SQLite3JdbcConnection
832
877
  end
878
+
879
+ def native_database_types # :nodoc:
880
+ ArJdbc::SQLite3::NATIVE_DATABASE_TYPES
881
+ end
833
882
  end
834
883
 
835
884
  # NOTE: include these modules before all then override some methods with the
@@ -845,7 +894,7 @@ module ActiveRecord::ConnectionAdapters
845
894
  include ArJdbc::Abstract::ConnectionManagement
846
895
  include ArJdbc::Abstract::DatabaseStatements
847
896
  include ArJdbc::Abstract::StatementCache
848
- include ArJdbc::Abstract::TransactionSupport
897
+ # Don't include TransactionSupport - use Rails' SQLite3::DatabaseStatements instead
849
898
 
850
899
 
851
900
  ##
@@ -954,7 +1003,8 @@ module ActiveRecord::ConnectionAdapters
954
1003
 
955
1004
  # because the JDBC driver doesn't like multiple SQL statements in one JDBC statement
956
1005
  def combine_multi_statements(total_sql)
957
- total_sql
1006
+ # For Rails 8 compatibility - join multiple statements with semicolon
1007
+ total_sql.is_a?(Array) ? total_sql.join(";\n") : total_sql
958
1008
  end
959
1009
 
960
1010
  def type_map
@@ -9,7 +9,7 @@ module ActiveRecord::ConnectionAdapters
9
9
  super
10
10
 
11
11
  @auto_increment = auto_increment
12
- @default = nil if default =~ /NULL/
12
+ @default = nil if default.is_a?(String) && default.match?(/NULL/)
13
13
  @rowid = rowid
14
14
  @generated_type = generated_type
15
15
  end
@@ -1,3 +1,3 @@
1
1
  module ArJdbc
2
- VERSION = '72.1'
2
+ VERSION = '81.0.pre1'
3
3
  end
data/pom.xml CHANGED
@@ -12,7 +12,7 @@
12
12
  <url>http://github.com/jruby/activerecord-jdbc-adapter/wiki</url>
13
13
 
14
14
  <properties>
15
- <jruby.version>9.2.6.0</jruby.version>
15
+ <jruby.version>10.0.0.1</jruby.version>
16
16
  </properties>
17
17
 
18
18
  <issueManagement>
@@ -103,8 +103,8 @@
103
103
  <artifactId>maven-compiler-plugin</artifactId>
104
104
  <version>2.5.1</version>
105
105
  <configuration>
106
- <source>1.8</source>
107
- <target>1.8</target>
106
+ <source>21</source>
107
+ <target>21</target>
108
108
  </configuration>
109
109
  </plugin>
110
110
  </plugins>
data/rakelib/db.rake CHANGED
@@ -39,7 +39,7 @@ GRANT ALL PRIVILEGES ON `test\_%`.* TO #{MYSQL_CONFIG[:username]}@localhost;
39
39
  task :postgresql do
40
40
  require File.expand_path('../../test/shared_helper', __FILE__)
41
41
  fail 'could not create test database: psql executable not found' unless psql = which('psql')
42
- fail 'could not create test database: missing "postgres" role' unless PostgresHelper.postgres_role?
42
+ fail 'could not create test database: missing "arjdbc" role' unless PostgresHelper.postgres_role?
43
43
 
44
44
  load 'test/db/postgres_config.rb' # rescue nil
45
45
  puts POSTGRES_CONFIG.inspect if $VERBOSE
@@ -53,11 +53,13 @@ CREATE DATABASE #{POSTGRES_CONFIG[:database]} OWNER #{POSTGRES_CONFIG[:username]
53
53
  ENCODING '#{POSTGRES_CONFIG[:encoding]}' LC_COLLATE '#{POSTGRES_CONFIG[:collate]}' LC_CTYPE '#{POSTGRES_CONFIG[:collate]}';
54
54
  SQL
55
55
 
56
- params = { '-U' => ENV['PSQL_USER'] || 'postgres' }
56
+ params = { '-U' => ENV['PGUSER'] || 'arjdbc', '-d' => 'postgres' }
57
+ params['-h'] = ENV['PGHOST'] if ENV['PGHOST']
58
+ params['-p'] = ENV['PGPORT'] if ENV['PGPORT']
57
59
  params['-q'] = nil unless $VERBOSE
58
60
 
59
61
  puts "Creating PostgreSQL (test) database: #{POSTGRES_CONFIG[:database]}"
60
- sh "cat #{script.path} | #{psql} #{params.to_a.join(' ')}", verbose: $VERBOSE
62
+ sh "PGPASSWORD=#{ENV['PGPASSWORD'] || 'arjdbc'} cat #{script.path} | #{psql} #{params.to_a.join(' ')}", verbose: $VERBOSE
61
63
  end
62
64
  task postgres: :postgresql
63
65
 
data/rakelib/rails.rake CHANGED
@@ -52,7 +52,6 @@ namespace :rails do
52
52
  ruby_opts_string += " -C \"#{ar_path}\""
53
53
  ruby_opts_string += " -rbundler/setup"
54
54
  ruby_opts_string += " -rminitest -rminitest/excludes" unless ENV['NO_EXCLUDES'].eql?('true')
55
- ruby_opts_string += " -rmonkey_patches"
56
55
  file_list = ENV["TEST"] ? FileList[ ENV["TEST"].split(',') ] : test_files_finder.call
57
56
  file_list_string = file_list.map { |fn| "\"#{fn}\"" }.join(' ')
58
57
  # test_loader_code = "-e \"ARGV.each{|f| require f}\"" # :direct
@@ -43,6 +43,9 @@ import org.jruby.util.ByteList;
43
43
 
44
44
  import arjdbc.jdbc.RubyJdbcConnection;
45
45
  import static arjdbc.jdbc.RubyJdbcConnection.getJdbcConnection;
46
+ import static org.jruby.api.Access.getModule;
47
+ import static org.jruby.api.Access.objectClass;
48
+ import static org.jruby.api.Create.allocArray;
46
49
 
47
50
  /**
48
51
  * ::ArJdbc
@@ -52,9 +55,10 @@ import static arjdbc.jdbc.RubyJdbcConnection.getJdbcConnection;
52
55
  public class ArJdbcModule {
53
56
 
54
57
  public static RubyModule load(final Ruby runtime) {
55
- final RubyModule arJdbc = runtime.getOrCreateModule("ArJdbc");
56
- arJdbc.defineAnnotatedMethods( ArJdbcModule.class );
57
- return arJdbc;
58
+ var context = runtime.getCurrentContext();
59
+ return objectClass(context).
60
+ defineModuleUnder(context, "ArJdbc").
61
+ defineMethods(context, ArJdbcModule.class);
58
62
  }
59
63
 
60
64
  public static RubyModule get(final Ruby runtime) {
@@ -142,7 +146,7 @@ public class ArJdbcModule {
142
146
  catch (NoSuchMethodException e) {
143
147
  // "old" e.g. MySQLRubyJdbcConnection.createMySQLJdbcConnectionClass(runtime, jdbcConnection)
144
148
  connection.getMethod("create" + moduleName + "JdbcConnectionClass", Ruby.class, RubyClass.class).
145
- invoke(null, runtime, getJdbcConnection(runtime));
149
+ invoke(null, runtime, getJdbcConnection(context));
146
150
  }
147
151
  }
148
152
  }
@@ -162,20 +166,19 @@ public class ArJdbcModule {
162
166
  */
163
167
  @JRubyMethod(name = "modules", meta = true)
164
168
  public static IRubyObject modules(final ThreadContext context, final IRubyObject self) {
165
- final Ruby runtime = context.getRuntime();
166
169
  final RubyModule arJdbc = (RubyModule) self;
167
170
 
168
171
  final Collection<String> constants = arJdbc.getConstantNames();
169
- final RubyArray modules = runtime.newArray( constants.size() );
172
+ final RubyArray modules = allocArray(context, constants.size());
170
173
 
171
174
  for ( final String name : constants ) {
172
- final IRubyObject constant = arJdbc.getConstant(name, false);
175
+ final IRubyObject constant = arJdbc.getConstant(context, name, false);
173
176
  // isModule: return false for Ruby Classes
174
177
  if ( constant != null && constant.isModule() ) {
175
178
  if ( "Util".equals(name) ) continue;
176
179
  if ( "SerializedAttributesHelper".equals(name) ) continue; // deprecated
177
180
  if ( "Version".equals(name) ) continue; // deprecated
178
- modules.append( constant );
181
+ modules.append(context, constant);
179
182
  }
180
183
  }
181
184
  return modules;
@@ -230,9 +233,9 @@ public class ArJdbcModule {
230
233
  return null;
231
234
  }
232
235
 
233
- final RubyModule jdbc = runtime.getModule("Jdbc");
236
+ final RubyModule jdbc = getModule(context, "Jdbc");
234
237
  if ( jdbc != null ) { // Jdbc::MySQL
235
- final RubyModule constant = (RubyModule) jdbc.getConstantAt(constName);
238
+ final RubyModule constant = jdbc.getModule(context, constName);
236
239
  if ( constant != null ) { // ::Jdbc::MySQL.load_driver :
237
240
  if ( constant.respondsTo("load_driver") ) {
238
241
  IRubyObject result = constant.callMethod("load_driver");
@@ -26,6 +26,7 @@ package arjdbc.db2;
26
26
  import static arjdbc.util.QuotingUtils.BYTES_0;
27
27
  import static arjdbc.util.QuotingUtils.BYTES_1;
28
28
  import static arjdbc.util.QuotingUtils.quoteSingleQuotesWithFallback;
29
+ import static org.jruby.api.Create.newString;
29
30
 
30
31
  import org.jruby.Ruby;
31
32
  import org.jruby.RubyModule;
@@ -42,9 +43,8 @@ import org.jruby.runtime.builtin.IRubyObject;
42
43
  public class DB2Module {
43
44
 
44
45
  public static RubyModule load(final RubyModule arJdbc) {
45
- RubyModule db2 = arJdbc.defineModuleUnder("DB2");
46
- db2.defineAnnotatedMethods( DB2Module.class );
47
- return db2;
46
+ var context = arJdbc.getRuntime().getCurrentContext();
47
+ return arJdbc.defineModuleUnder(context, "DB2").defineMethods(context, DB2Module.class);
48
48
  }
49
49
 
50
50
  public static RubyModule load(final Ruby runtime) {
@@ -63,7 +63,7 @@ public class DB2Module {
63
63
  public static IRubyObject quoted_true(
64
64
  final ThreadContext context,
65
65
  final IRubyObject self) {
66
- return RubyString.newString(context.runtime, BYTES_1);
66
+ return newString(context, BYTES_1);
67
67
  }
68
68
 
69
69
  @JRubyMethod(name = "quoted_false", required = 0, frame = false)
@@ -54,17 +54,16 @@ public class DB2RubyJdbcConnection extends RubyJdbcConnection {
54
54
  super(runtime, metaClass);
55
55
  }
56
56
 
57
- public static RubyClass createDB2JdbcConnectionClass(Ruby runtime, RubyClass jdbcConnection) {
58
- RubyClass clazz = getConnectionAdapters(runtime).
59
- defineClassUnder("DB2JdbcConnection", jdbcConnection, ALLOCATOR);
60
- clazz.defineAnnotatedMethods(DB2RubyJdbcConnection.class);
61
-
62
- return clazz;
57
+ public static RubyClass createDB2JdbcConnectionClass(ThreadContext context, RubyClass jdbcConnection) {
58
+ return getConnectionAdapters(context).
59
+ defineClassUnder(context, "DB2JdbcConnection", jdbcConnection, ALLOCATOR).
60
+ defineMethods(context, DB2RubyJdbcConnection.class);
63
61
  }
64
62
 
65
63
  public static RubyClass load(final Ruby runtime) {
66
- RubyClass jdbcConnection = getJdbcConnection(runtime);
67
- return createDB2JdbcConnectionClass(runtime, jdbcConnection);
64
+ var context = runtime.getCurrentContext();
65
+ RubyClass jdbcConnection = getJdbcConnection(context);
66
+ return createDB2JdbcConnectionClass(context, jdbcConnection);
68
67
  }
69
68
 
70
69
  protected static ObjectAllocator ALLOCATOR = new ObjectAllocator() {
@@ -112,7 +111,7 @@ public class DB2RubyJdbcConnection extends RubyJdbcConnection {
112
111
  try {
113
112
  statement = connection.prepareStatement("VALUES IDENTITY_VAL_LOCAL()");
114
113
  genKeys = statement.executeQuery();
115
- return doMapGeneratedKeys(context.runtime, genKeys, true);
114
+ return doMapGeneratedKeys(context, genKeys, true);
116
115
  }
117
116
  catch (final SQLException e) {
118
117
  debugMessage(context.runtime, "failed to get generated keys: ", e);
@@ -37,7 +37,8 @@ import org.jruby.RubyModule;
37
37
  public class H2Module {
38
38
 
39
39
  public static RubyModule load(final RubyModule arJdbc) {
40
- RubyModule h2 = arJdbc.defineModuleUnder("H2");
40
+ var context = arJdbc.getRuntime().getCurrentContext();
41
+ RubyModule h2 = arJdbc.defineModuleUnder(context, "H2");
41
42
  // NOTE: currently no Java implemented Ruby methods
42
43
  // h2.defineAnnotatedMethods( H2Module.class );
43
44
  return h2;
@@ -28,9 +28,11 @@ package arjdbc.h2;
28
28
  import java.sql.Connection;
29
29
  import java.sql.SQLException;
30
30
 
31
+ import arjdbc.db2.DB2RubyJdbcConnection;
31
32
  import org.jruby.Ruby;
32
33
  import org.jruby.RubyClass;
33
34
  import org.jruby.runtime.ObjectAllocator;
35
+ import org.jruby.runtime.ThreadContext;
34
36
  import org.jruby.runtime.builtin.IRubyObject;
35
37
 
36
38
  /**
@@ -45,16 +47,15 @@ public class H2RubyJdbcConnection extends arjdbc.jdbc.RubyJdbcConnection {
45
47
  super(runtime, metaClass);
46
48
  }
47
49
 
48
- public static RubyClass createH2JdbcConnectionClass(Ruby runtime, RubyClass jdbcConnection) {
49
- RubyClass clazz = getConnectionAdapters(runtime).
50
- defineClassUnder("H2JdbcConnection", jdbcConnection, ALLOCATOR);
51
- clazz.defineAnnotatedMethods(H2RubyJdbcConnection.class);
52
- return clazz;
50
+ public static RubyClass createH2JdbcConnectionClass(ThreadContext context, RubyClass jdbcConnection) {
51
+ return getConnectionAdapters(context).
52
+ defineClassUnder(context, "H2JdbcConnection", jdbcConnection, ALLOCATOR).
53
+ defineMethods(context, H2RubyJdbcConnection.class);
53
54
  }
54
55
 
55
56
  public static RubyClass load(final Ruby runtime) {
56
- RubyClass jdbcConnection = getJdbcConnection(runtime);
57
- return createH2JdbcConnectionClass(runtime, jdbcConnection);
57
+ var context = runtime.getCurrentContext();
58
+ return createH2JdbcConnectionClass(context, getJdbcConnection(context));
58
59
  }
59
60
 
60
61
  protected static ObjectAllocator ALLOCATOR = new ObjectAllocator() {
@@ -28,10 +28,10 @@ package arjdbc.hsqldb;
28
28
  import static arjdbc.util.QuotingUtils.BYTES_0;
29
29
  import static arjdbc.util.QuotingUtils.BYTES_1;
30
30
  import static arjdbc.util.QuotingUtils.quoteSingleQuotesWithFallback;
31
+ import static org.jruby.api.Create.newString;
31
32
 
32
33
  import org.jruby.Ruby;
33
34
  import org.jruby.RubyModule;
34
- import org.jruby.RubyString;
35
35
  import org.jruby.anno.JRubyMethod;
36
36
  import org.jruby.runtime.ThreadContext;
37
37
  import org.jruby.runtime.builtin.IRubyObject;
@@ -39,9 +39,8 @@ import org.jruby.runtime.builtin.IRubyObject;
39
39
  public class HSQLDBModule {
40
40
 
41
41
  public static RubyModule load(final RubyModule arJdbc) {
42
- RubyModule hsqldb = arJdbc.defineModuleUnder("HSQLDB");
43
- hsqldb.defineAnnotatedMethods( HSQLDBModule.class );
44
- return hsqldb;
42
+ var context = arJdbc.getRuntime().getCurrentContext();
43
+ return arJdbc.defineModuleUnder(context, "HSQLDB").defineMethods(context, HSQLDBModule.class);
45
44
  }
46
45
 
47
46
  public static RubyModule load(final Ruby runtime) {
@@ -60,14 +59,14 @@ public class HSQLDBModule {
60
59
  public static IRubyObject quoted_true(
61
60
  final ThreadContext context,
62
61
  final IRubyObject self) {
63
- return RubyString.newString(context.getRuntime(), BYTES_1);
62
+ return newString(context, BYTES_1);
64
63
  }
65
64
 
66
65
  @JRubyMethod(name = "quoted_false", required = 0, frame = false)
67
66
  public static IRubyObject quoted_false(
68
67
  final ThreadContext context,
69
68
  final IRubyObject self) {
70
- return RubyString.newString(context.getRuntime(), BYTES_0);
69
+ return newString(context, BYTES_0);
71
70
  }
72
71
 
73
72
  }
@@ -36,6 +36,7 @@ import org.jruby.util.SafePropertyAccessor;
36
36
 
37
37
  import static arjdbc.jdbc.RubyJdbcConnection.getConnectionNotEstablished;
38
38
  import static arjdbc.jdbc.RubyJdbcConnection.wrapException;
39
+ import static org.jruby.api.Access.runtimeErrorClass;
39
40
 
40
41
  /**
41
42
  *
@@ -103,7 +104,7 @@ final class DataSourceConnectionFactory implements ConnectionFactory {
103
104
  if ( ! ( bound instanceof DataSource ) ) {
104
105
  if ( bound == null ) throw new NameNotFoundException(); // unlikely to happen
105
106
  final String msg = "bound object at '" + name + "' is not a " + DataSource.class.getName() + " but a " + bound.getClass().getName() + "\n" + bound;
106
- throw wrapException(context, getConnectionNotEstablished(context.runtime), new ClassCastException(msg), msg);
107
+ throw wrapException(context, getConnectionNotEstablished(context), new ClassCastException(msg), msg);
107
108
  }
108
109
  return (DataSource) bound;
109
110
  }
@@ -124,10 +125,10 @@ final class DataSourceConnectionFactory implements ConnectionFactory {
124
125
  else {
125
126
  message = "unable to lookup data source - name: '" + name + "' not found";
126
127
  }
127
- throw wrapException(context, getConnectionNotEstablished(context.runtime), e, message);
128
+ throw wrapException(context, getConnectionNotEstablished(context), e, message);
128
129
  }
129
130
  catch (NamingException e) {
130
- throw wrapException(context, context.runtime.getRuntimeError(), e);
131
+ throw wrapException(context, runtimeErrorClass(context), e);
131
132
  }
132
133
  }
133
134
 
@@ -23,6 +23,7 @@
23
23
  */
24
24
  package arjdbc.jdbc;
25
25
 
26
+ import java.lang.reflect.InvocationTargetException;
26
27
  import java.sql.Connection;
27
28
  import java.sql.Driver;
28
29
  import java.sql.SQLException;
@@ -45,7 +46,7 @@ public class DriverWrapper {
45
46
  private final Properties properties;
46
47
 
47
48
  DriverWrapper(final Ruby runtime, final String name, final Properties properties)
48
- throws ClassCastException, InstantiationException, IllegalAccessException {
49
+ throws ClassCastException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
49
50
  this.driver = allocateDriver( loadDriver(runtime, name) );
50
51
  this.properties = properties == null ? new Properties() : properties;
51
52
  }
@@ -59,18 +60,22 @@ public class DriverWrapper {
59
60
  }
60
61
 
61
62
  private Driver allocateDriver(final Class<? extends Driver> driverClass)
62
- throws InstantiationException, IllegalAccessException {
63
- return driverClass.newInstance();
63
+ throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
64
+ return driverClass.getDeclaredConstructor().newInstance();
64
65
  }
65
66
 
66
67
  protected static Class<? extends Driver> loadDriver(final Ruby runtime, final String name)
67
68
  throws ClassCastException {
68
- @SuppressWarnings("unchecked")
69
- Class<? extends Driver> klass = runtime.getJavaSupport().loadJavaClassVerbose(name);
70
- if ( ! Driver.class.isAssignableFrom(klass) ) {
71
- throw new ClassCastException(klass + " is not assignable from " + Driver.class);
69
+ try {
70
+ @SuppressWarnings("unchecked")
71
+ Class<? extends Driver> klass = (Class<? extends Driver>) runtime.getJavaSupport().loadJavaClass(name);
72
+ if ( ! Driver.class.isAssignableFrom(klass) ) {
73
+ throw new ClassCastException(klass + " is not assignable from " + Driver.class);
74
+ }
75
+ return klass;
76
+ } catch (ClassNotFoundException e) {
77
+ throw new RuntimeException("Cannot load driver class: " + name, e);
72
78
  }
73
- return klass;
74
79
  }
75
80
 
76
81
  public Connection connect(final String url, final String user, final String pass)