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.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +129 -24
- data/.mise.toml +3 -0
- data/Gemfile +42 -47
- data/README.md +4 -2
- data/RUNNING_TESTS.md +9 -1
- data/Rakefile +63 -15
- data/activerecord-jdbc-adapter.gemspec +2 -2
- data/lib/arjdbc/abstract/core.rb +1 -1
- data/lib/arjdbc/abstract/database_statements.rb +22 -7
- data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
- data/lib/arjdbc/mysql/adapter_hash_config.rb +1 -2
- data/lib/arjdbc/postgresql/adapter.rb +4 -1
- data/lib/arjdbc/postgresql/schema_statements.rb +17 -0
- data/lib/arjdbc/sqlite3/adapter.rb +61 -11
- data/lib/arjdbc/sqlite3/column.rb +1 -1
- data/lib/arjdbc/version.rb +1 -1
- data/pom.xml +3 -3
- data/rakelib/db.rake +5 -3
- data/rakelib/rails.rake +0 -1
- data/src/java/arjdbc/ArJdbcModule.java +13 -10
- data/src/java/arjdbc/db2/DB2Module.java +4 -4
- data/src/java/arjdbc/db2/DB2RubyJdbcConnection.java +8 -9
- data/src/java/arjdbc/h2/H2Module.java +2 -1
- data/src/java/arjdbc/h2/H2RubyJdbcConnection.java +8 -7
- data/src/java/arjdbc/hsqldb/HSQLDBModule.java +5 -6
- data/src/java/arjdbc/jdbc/DataSourceConnectionFactory.java +4 -3
- data/src/java/arjdbc/jdbc/DriverWrapper.java +13 -8
- data/src/java/arjdbc/jdbc/JdbcResult.java +10 -7
- data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +168 -154
- data/src/java/arjdbc/mssql/MSSQLModule.java +3 -3
- data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +13 -9
- data/src/java/arjdbc/mysql/MySQLModule.java +3 -3
- data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +30 -24
- data/src/java/arjdbc/oracle/OracleModule.java +2 -3
- data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +22 -18
- data/src/java/arjdbc/postgresql/PostgreSQLModule.java +2 -3
- data/src/java/arjdbc/postgresql/PostgreSQLResult.java +24 -12
- data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +16 -12
- data/src/java/arjdbc/sqlite3/SQLite3Module.java +2 -3
- data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +78 -29
- data/src/java/arjdbc/util/DateTimeUtils.java +7 -5
- data/src/java/arjdbc/util/ObjectSupport.java +2 -2
- data/src/java/arjdbc/util/StringHelper.java +1 -1
- metadata +6 -6
- data/.travis.yml +0 -128
|
@@ -9,9 +9,18 @@ module ArJdbc
|
|
|
9
9
|
|
|
10
10
|
NO_BINDS = [].freeze
|
|
11
11
|
|
|
12
|
-
def
|
|
13
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
232
|
-
|
|
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
|
-
|
|
236
|
-
|
|
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
|
-
|
|
445
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
data/lib/arjdbc/version.rb
CHANGED
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>
|
|
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>
|
|
107
|
-
<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 "
|
|
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['
|
|
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
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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(
|
|
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 =
|
|
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 =
|
|
236
|
+
final RubyModule jdbc = getModule(context, "Jdbc");
|
|
234
237
|
if ( jdbc != null ) { // Jdbc::MySQL
|
|
235
|
-
final RubyModule constant =
|
|
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
|
-
|
|
46
|
-
|
|
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
|
|
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(
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
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
|
-
|
|
67
|
-
|
|
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
|
|
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
|
-
|
|
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(
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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
|
-
|
|
57
|
-
return createH2JdbcConnectionClass(
|
|
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
|
-
|
|
43
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
128
|
+
throw wrapException(context, getConnectionNotEstablished(context), e, message);
|
|
128
129
|
}
|
|
129
130
|
catch (NamingException e) {
|
|
130
|
-
throw wrapException(context, context
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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)
|