activerecord-jdbc-alt-adapter 61.0.0-java → 70.0.0.rc1-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 +273 -0
- data/.gitignore +1 -0
- data/Gemfile +8 -6
- data/README.md +2 -1
- data/Rakefile +1 -1
- data/activerecord-jdbc-adapter.gemspec +2 -2
- data/activerecord-jdbc-alt-adapter.gemspec +2 -2
- data/lib/arel/visitors/compat.rb +5 -33
- data/lib/arel/visitors/h2.rb +1 -13
- data/lib/arel/visitors/hsqldb.rb +1 -21
- data/lib/arel/visitors/sql_server.rb +2 -103
- data/lib/arjdbc/abstract/core.rb +8 -9
- data/lib/arjdbc/abstract/database_statements.rb +4 -4
- data/lib/arjdbc/discover.rb +0 -67
- data/lib/arjdbc/hsqldb/adapter.rb +2 -2
- data/lib/arjdbc/jdbc/adapter.rb +3 -3
- data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
- data/lib/arjdbc/jdbc/adapter_require.rb +3 -1
- data/lib/arjdbc/jdbc/column.rb +1 -26
- data/lib/arjdbc/jdbc/type_cast.rb +2 -2
- data/lib/arjdbc/jdbc.rb +0 -7
- data/lib/arjdbc/mssql/adapter.rb +134 -105
- data/lib/arjdbc/mssql/quoting.rb +26 -27
- data/lib/arjdbc/mssql/schema_creation.rb +1 -1
- data/lib/arjdbc/mssql/schema_definitions.rb +32 -17
- data/lib/arjdbc/mssql/schema_dumper.rb +13 -1
- data/lib/arjdbc/mssql/schema_statements.rb +61 -36
- data/lib/arjdbc/mssql/transaction.rb +2 -2
- data/lib/arjdbc/mssql/types/date_and_time_types.rb +6 -6
- data/lib/arjdbc/mssql/types/numeric_types.rb +2 -2
- data/lib/arjdbc/mssql.rb +1 -1
- data/lib/arjdbc/mysql/adapter.rb +2 -1
- data/lib/arjdbc/oracle/adapter.rb +4 -23
- data/lib/arjdbc/postgresql/adapter.rb +64 -1
- data/lib/arjdbc/postgresql/oid_types.rb +68 -47
- data/lib/arjdbc/sqlite3/adapter.rb +132 -88
- data/lib/arjdbc/tasks/database_tasks.rb +0 -12
- data/lib/arjdbc/util/serialized_attributes.rb +0 -22
- data/lib/arjdbc/util/table_copier.rb +2 -1
- data/lib/arjdbc/version.rb +1 -1
- data/rakelib/02-test.rake +3 -18
- data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +17 -2
- data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +14 -1
- data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +33 -0
- metadata +8 -40
- data/lib/active_record/connection_adapters/as400_adapter.rb +0 -2
- data/lib/active_record/connection_adapters/db2_adapter.rb +0 -1
- data/lib/active_record/connection_adapters/derby_adapter.rb +0 -1
- data/lib/active_record/connection_adapters/informix_adapter.rb +0 -1
- data/lib/arel/visitors/db2.rb +0 -137
- data/lib/arel/visitors/derby.rb +0 -112
- data/lib/arel/visitors/firebird.rb +0 -79
- data/lib/arjdbc/db2/adapter.rb +0 -808
- data/lib/arjdbc/db2/as400.rb +0 -142
- data/lib/arjdbc/db2/column.rb +0 -131
- data/lib/arjdbc/db2/connection_methods.rb +0 -48
- data/lib/arjdbc/db2.rb +0 -4
- data/lib/arjdbc/derby/active_record_patch.rb +0 -13
- data/lib/arjdbc/derby/adapter.rb +0 -521
- data/lib/arjdbc/derby/connection_methods.rb +0 -20
- data/lib/arjdbc/derby/schema_creation.rb +0 -15
- data/lib/arjdbc/derby.rb +0 -3
- data/lib/arjdbc/firebird/adapter.rb +0 -413
- data/lib/arjdbc/firebird/connection_methods.rb +0 -23
- data/lib/arjdbc/firebird.rb +0 -4
- data/lib/arjdbc/informix/adapter.rb +0 -139
- data/lib/arjdbc/informix/connection_methods.rb +0 -9
- data/lib/arjdbc/sybase/adapter.rb +0 -47
- data/lib/arjdbc/sybase.rb +0 -2
- data/lib/arjdbc/tasks/db2_database_tasks.rb +0 -104
- data/lib/arjdbc/tasks/derby_database_tasks.rb +0 -95
- data/src/java/arjdbc/derby/DerbyModule.java +0 -178
- data/src/java/arjdbc/derby/DerbyRubyJdbcConnection.java +0 -152
- data/src/java/arjdbc/firebird/FirebirdRubyJdbcConnection.java +0 -174
- data/src/java/arjdbc/informix/InformixRubyJdbcConnection.java +0 -75
@@ -10,6 +10,7 @@ require "active_record/connection_adapters/abstract_adapter"
|
|
10
10
|
require "active_record/connection_adapters/statement_pool"
|
11
11
|
require "active_record/connection_adapters/sqlite3/explain_pretty_printer"
|
12
12
|
require "active_record/connection_adapters/sqlite3/quoting"
|
13
|
+
require "active_record/connection_adapters/sqlite3/database_statements"
|
13
14
|
require "active_record/connection_adapters/sqlite3/schema_creation"
|
14
15
|
require "active_record/connection_adapters/sqlite3/schema_definitions"
|
15
16
|
require "active_record/connection_adapters/sqlite3/schema_dumper"
|
@@ -64,6 +65,7 @@ module ArJdbc
|
|
64
65
|
# DIFFERENCE: FQN
|
65
66
|
include ::ActiveRecord::ConnectionAdapters::SQLite3::Quoting
|
66
67
|
include ::ActiveRecord::ConnectionAdapters::SQLite3::SchemaStatements
|
68
|
+
include ::ActiveRecord::ConnectionAdapters::SQLite3::DatabaseStatements
|
67
69
|
|
68
70
|
NATIVE_DATABASE_TYPES = {
|
69
71
|
primary_key: "integer PRIMARY KEY AUTOINCREMENT NOT NULL",
|
@@ -79,15 +81,30 @@ module ArJdbc
|
|
79
81
|
boolean: { name: "boolean" },
|
80
82
|
json: { name: "json" },
|
81
83
|
}
|
82
|
-
|
83
|
-
|
84
|
-
|
84
|
+
|
85
|
+
class StatementPool < ConnectionAdapters::StatementPool # :nodoc:
|
86
|
+
private
|
87
|
+
def dealloc(stmt)
|
88
|
+
stmt.close unless stmt.closed?
|
89
|
+
end
|
90
|
+
end
|
85
91
|
|
86
92
|
def initialize(connection, logger, connection_options, config)
|
93
|
+
@memory_database = config[:database] == ":memory:"
|
87
94
|
super(connection, logger, config)
|
88
95
|
configure_connection
|
89
96
|
end
|
90
97
|
|
98
|
+
def self.database_exists?(config)
|
99
|
+
config = config.symbolize_keys
|
100
|
+
if config[:database] == ":memory:"
|
101
|
+
true
|
102
|
+
else
|
103
|
+
database_file = defined?(Rails.root) ? File.expand_path(config[:database], Rails.root) : config[:database]
|
104
|
+
File.exist?(database_file)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
91
108
|
def supports_ddl_transactions?
|
92
109
|
true
|
93
110
|
end
|
@@ -101,7 +118,7 @@ module ArJdbc
|
|
101
118
|
end
|
102
119
|
|
103
120
|
def supports_partial_index?
|
104
|
-
|
121
|
+
true
|
105
122
|
end
|
106
123
|
|
107
124
|
def supports_expression_index?
|
@@ -144,6 +161,25 @@ module ArJdbc
|
|
144
161
|
alias supports_insert_conflict_target? supports_insert_on_conflict?
|
145
162
|
|
146
163
|
# DIFFERENCE: active?, reconnect!, disconnect! handles by arjdbc core
|
164
|
+
def supports_concurrent_connections?
|
165
|
+
!@memory_database
|
166
|
+
end
|
167
|
+
|
168
|
+
def active?
|
169
|
+
!@raw_connection.closed?
|
170
|
+
end
|
171
|
+
|
172
|
+
def reconnect!
|
173
|
+
super
|
174
|
+
connect if @connection.closed?
|
175
|
+
end
|
176
|
+
|
177
|
+
# Disconnects from the database if already connected. Otherwise, this
|
178
|
+
# method does nothing.
|
179
|
+
def disconnect!
|
180
|
+
super
|
181
|
+
@connection.close rescue nil
|
182
|
+
end
|
147
183
|
|
148
184
|
def supports_index_sort_order?
|
149
185
|
true
|
@@ -182,48 +218,8 @@ module ArJdbc
|
|
182
218
|
end
|
183
219
|
end
|
184
220
|
|
185
|
-
|
186
|
-
|
187
|
-
#++
|
188
|
-
|
189
|
-
READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(
|
190
|
-
:pragma
|
191
|
-
) # :nodoc:
|
192
|
-
private_constant :READ_QUERY
|
193
|
-
|
194
|
-
def write_query?(sql) # :nodoc:
|
195
|
-
!READ_QUERY.match?(sql)
|
196
|
-
end
|
197
|
-
|
198
|
-
def explain(arel, binds = [])
|
199
|
-
sql = "EXPLAIN QUERY PLAN #{to_sql(arel, binds)}"
|
200
|
-
# DIFFERENCE: FQN
|
201
|
-
::ActiveRecord::ConnectionAdapters::SQLite3::ExplainPrettyPrinter.new.pp(exec_query(sql, "EXPLAIN", []))
|
202
|
-
end
|
203
|
-
|
204
|
-
# DIFFERENCE: implemented in ArJdbc::Abstract::DatabaseStatements
|
205
|
-
#def exec_query(sql, name = nil, binds = [], prepare: false)
|
206
|
-
|
207
|
-
# DIFFERENCE: implemented in ArJdbc::Abstract::DatabaseStatements
|
208
|
-
#def exec_delete(sql, name = "SQL", binds = [])
|
209
|
-
|
210
|
-
def last_inserted_id(result)
|
211
|
-
@connection.last_insert_row_id
|
212
|
-
end
|
213
|
-
|
214
|
-
# DIFFERENCE: implemented in ArJdbc::Abstract::DatabaseStatements
|
215
|
-
#def execute(sql, name = nil) #:nodoc:
|
216
|
-
|
217
|
-
def begin_db_transaction #:nodoc:
|
218
|
-
log("begin transaction", 'TRANSACTION') { @connection.transaction }
|
219
|
-
end
|
220
|
-
|
221
|
-
def commit_db_transaction #:nodoc:
|
222
|
-
log("commit transaction", 'TRANSACTION') { @connection.commit }
|
223
|
-
end
|
224
|
-
|
225
|
-
def exec_rollback_db_transaction #:nodoc:
|
226
|
-
log("rollback transaction", 'TRANSACTION') { @connection.rollback }
|
221
|
+
def all_foreign_keys_valid? # :nodoc:
|
222
|
+
execute("PRAGMA foreign_key_check").blank?
|
227
223
|
end
|
228
224
|
|
229
225
|
# SCHEMA STATEMENTS ========================================
|
@@ -233,14 +229,15 @@ module ArJdbc
|
|
233
229
|
pks.sort_by { |f| f["pk"] }.map { |f| f["name"] }
|
234
230
|
end
|
235
231
|
|
236
|
-
|
237
|
-
|
232
|
+
def remove_index(table_name, column_name = nil, **options) # :nodoc:
|
233
|
+
return if options[:if_exists] && !index_exists?(table_name, column_name, **options)
|
238
234
|
|
239
235
|
index_name = index_name_for_remove(table_name, column_name, options)
|
240
236
|
|
241
237
|
exec_query "DROP INDEX #{quote_column_name(index_name)}"
|
242
238
|
end
|
243
239
|
|
240
|
+
|
244
241
|
# Renames a table.
|
245
242
|
#
|
246
243
|
# Example:
|
@@ -265,9 +262,17 @@ module ArJdbc
|
|
265
262
|
def remove_column(table_name, column_name, type = nil, **options) #:nodoc:
|
266
263
|
alter_table(table_name) do |definition|
|
267
264
|
definition.remove_column column_name
|
268
|
-
definition.foreign_keys.delete_if
|
269
|
-
|
265
|
+
definition.foreign_keys.delete_if { |fk| fk.column == column_name.to_s }
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
def remove_columns(table_name, *column_names, type: nil, **options) # :nodoc:
|
270
|
+
alter_table(table_name) do |definition|
|
271
|
+
column_names.each do |column_name|
|
272
|
+
definition.remove_column column_name
|
270
273
|
end
|
274
|
+
column_names = column_names.map(&:to_s)
|
275
|
+
definition.foreign_keys.delete_if { |fk| column_names.include?(fk.column) }
|
271
276
|
end
|
272
277
|
end
|
273
278
|
|
@@ -291,8 +296,8 @@ module ArJdbc
|
|
291
296
|
def change_column(table_name, column_name, type, **options) #:nodoc:
|
292
297
|
alter_table(table_name) do |definition|
|
293
298
|
definition[column_name].instance_eval do
|
294
|
-
self.type
|
295
|
-
|
299
|
+
self.type = aliased_types(type.to_s, type)
|
300
|
+
self.options.merge!(options)
|
296
301
|
end
|
297
302
|
end
|
298
303
|
end
|
@@ -322,18 +327,6 @@ module ArJdbc
|
|
322
327
|
end
|
323
328
|
end
|
324
329
|
|
325
|
-
def insert_fixtures_set(fixture_set, tables_to_delete = [])
|
326
|
-
disable_referential_integrity do
|
327
|
-
transaction(requires_new: true) do
|
328
|
-
tables_to_delete.each { |table| delete "DELETE FROM #{quote_table_name(table)}", "Fixture Delete" }
|
329
|
-
|
330
|
-
fixture_set.each do |table_name, rows|
|
331
|
-
rows.each { |row| insert_fixture(row, table_name) }
|
332
|
-
end
|
333
|
-
end
|
334
|
-
end
|
335
|
-
end
|
336
|
-
|
337
330
|
def build_insert_sql(insert) # :nodoc:
|
338
331
|
sql = +"INSERT #{insert.into} #{insert.values_list}"
|
339
332
|
|
@@ -341,23 +334,23 @@ module ArJdbc
|
|
341
334
|
sql << " ON CONFLICT #{insert.conflict_target} DO NOTHING"
|
342
335
|
elsif insert.update_duplicates?
|
343
336
|
sql << " ON CONFLICT #{insert.conflict_target} DO UPDATE SET "
|
344
|
-
|
345
|
-
|
337
|
+
if insert.raw_update_sql?
|
338
|
+
sql << insert.raw_update_sql
|
339
|
+
else
|
340
|
+
sql << insert.touch_model_timestamps_unless { |column| "#{column} IS excluded.#{column}" }
|
341
|
+
sql << insert.updatable_columns.map { |column| "#{column}=excluded.#{column}" }.join(",")
|
342
|
+
end
|
346
343
|
end
|
347
344
|
|
348
345
|
sql
|
349
346
|
end
|
350
347
|
|
351
|
-
def shared_cache?
|
352
|
-
config
|
348
|
+
def shared_cache? # :nodoc:
|
349
|
+
@config.fetch(:flags, 0).anybits?(::SQLite3::Constants::Open::SHAREDCACHE)
|
353
350
|
end
|
354
351
|
|
355
352
|
def get_database_version # :nodoc:
|
356
|
-
SQLite3Adapter::Version.new(query_value("SELECT sqlite_version(*)"))
|
357
|
-
end
|
358
|
-
|
359
|
-
def build_truncate_statement(table_name)
|
360
|
-
"DELETE FROM #{quote_table_name(table_name)}"
|
353
|
+
SQLite3Adapter::Version.new(query_value("SELECT sqlite_version(*)", "SCHEMA"))
|
361
354
|
end
|
362
355
|
|
363
356
|
def check_version
|
@@ -380,6 +373,34 @@ module ArJdbc
|
|
380
373
|
end
|
381
374
|
alias column_definitions table_structure
|
382
375
|
|
376
|
+
def extract_value_from_default(default)
|
377
|
+
case default
|
378
|
+
when /^null$/i
|
379
|
+
nil
|
380
|
+
# Quoted types
|
381
|
+
when /^'(.*)'$/m
|
382
|
+
$1.gsub("''", "'")
|
383
|
+
# Quoted types
|
384
|
+
when /^"(.*)"$/m
|
385
|
+
$1.gsub('""', '"')
|
386
|
+
# Numeric types
|
387
|
+
when /\A-?\d+(\.\d*)?\z/
|
388
|
+
$&
|
389
|
+
else
|
390
|
+
# Anything else is blank or some function
|
391
|
+
# and we can't know the value of that, so return nil.
|
392
|
+
nil
|
393
|
+
end
|
394
|
+
end
|
395
|
+
|
396
|
+
def extract_default_function(default_value, default)
|
397
|
+
default if has_default_function?(default_value, default)
|
398
|
+
end
|
399
|
+
|
400
|
+
def has_default_function?(default_value, default)
|
401
|
+
!default_value && %r{\w+\(.*\)|CURRENT_TIME|CURRENT_DATE|CURRENT_TIMESTAMP}.match?(default)
|
402
|
+
end
|
403
|
+
|
383
404
|
# See: https://www.sqlite.org/lang_altertable.html
|
384
405
|
# SQLite has an additional restriction on the ALTER TABLE statement
|
385
406
|
def invalid_alter_table_type?(type, options)
|
@@ -440,8 +461,13 @@ module ArJdbc
|
|
440
461
|
options[:rename][column.name.to_sym] ||
|
441
462
|
column.name) : column.name
|
442
463
|
|
464
|
+
if column.has_default?
|
465
|
+
type = lookup_cast_type_from_column(column)
|
466
|
+
default = type.deserialize(column.default)
|
467
|
+
end
|
468
|
+
|
443
469
|
@definition.column(column_name, column.type,
|
444
|
-
limit: column.limit, default:
|
470
|
+
limit: column.limit, default: default,
|
445
471
|
precision: column.precision, scale: column.scale,
|
446
472
|
null: column.null, collation: column.collation,
|
447
473
|
primary_key: column_name == from_primary_key
|
@@ -459,9 +485,6 @@ module ArJdbc
|
|
459
485
|
def copy_table_indexes(from, to, rename = {})
|
460
486
|
indexes(from).each do |index|
|
461
487
|
name = index.name
|
462
|
-
# indexes sqlite creates for internal use start with `sqlite_` and
|
463
|
-
# don't need to be copied
|
464
|
-
next if name.start_with?("sqlite_")
|
465
488
|
if to == "a#{from}"
|
466
489
|
name = "t#{name}"
|
467
490
|
elsif from == "a#{to}"
|
@@ -481,6 +504,7 @@ module ArJdbc
|
|
481
504
|
options = { name: name.gsub(/(^|_)(#{from})_/, "\\1#{to}_"), internal: true }
|
482
505
|
options[:unique] = true if index.unique
|
483
506
|
options[:where] = index.where if index.where
|
507
|
+
options[:order] = index.orders if index.orders
|
484
508
|
add_index(to, columns, **options)
|
485
509
|
end
|
486
510
|
end
|
@@ -500,20 +524,22 @@ module ArJdbc
|
|
500
524
|
end
|
501
525
|
|
502
526
|
def translate_exception(exception, message:, sql:, binds:)
|
503
|
-
case exception.message
|
504
527
|
# SQLite 3.8.2 returns a newly formatted error message:
|
505
528
|
# UNIQUE constraint failed: *table_name*.*column_name*
|
506
529
|
# Older versions of SQLite return:
|
507
530
|
# column *column_name* is not unique
|
508
|
-
|
531
|
+
if exception.message.match?(/(column(s)? .* (is|are) not unique|UNIQUE constraint failed: .*)/i)
|
509
532
|
# DIFFERENCE: FQN
|
510
533
|
::ActiveRecord::RecordNotUnique.new(message, sql: sql, binds: binds)
|
511
|
-
|
534
|
+
elsif exception.message.match?(/(.* may not be NULL|NOT NULL constraint failed: .*)/i)
|
512
535
|
# DIFFERENCE: FQN
|
513
536
|
::ActiveRecord::NotNullViolation.new(message, sql: sql, binds: binds)
|
514
|
-
|
537
|
+
elsif exception.message.match?(/FOREIGN KEY constraint failed/i)
|
515
538
|
# DIFFERENCE: FQN
|
516
539
|
::ActiveRecord::InvalidForeignKey.new(message, sql: sql, binds: binds)
|
540
|
+
elsif exception.message.match?(/called on a closed database/i)
|
541
|
+
# DIFFERENCE: FQN
|
542
|
+
::ActiveRecord::ConnectionNotEstablished.new(exception)
|
517
543
|
else
|
518
544
|
super
|
519
545
|
end
|
@@ -533,12 +559,12 @@ module ArJdbc
|
|
533
559
|
# Result will have following sample string
|
534
560
|
# CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
535
561
|
# "password_digest" varchar COLLATE "NOCASE");
|
536
|
-
result =
|
562
|
+
result = query_value(sql, "SCHEMA")
|
537
563
|
|
538
564
|
if result
|
539
565
|
# Splitting with left parentheses and discarding the first part will return all
|
540
566
|
# columns separated with comma(,).
|
541
|
-
columns_string = result
|
567
|
+
columns_string = result.split("(", 2).last
|
542
568
|
|
543
569
|
columns_string.split(",").each do |column_string|
|
544
570
|
# This regex will match the column name and collation type and will save
|
@@ -564,7 +590,21 @@ module ArJdbc
|
|
564
590
|
Arel::Visitors::SQLite.new(self)
|
565
591
|
end
|
566
592
|
|
593
|
+
def build_statement_pool
|
594
|
+
StatementPool.new(self.class.type_cast_config_to_integer(@config[:statement_limit]))
|
595
|
+
end
|
596
|
+
|
597
|
+
def connect
|
598
|
+
@connection = ::SQLite3::Database.new(
|
599
|
+
@config[:database].to_s,
|
600
|
+
@config.merge(results_as_hash: true)
|
601
|
+
)
|
602
|
+
end
|
603
|
+
|
567
604
|
def configure_connection
|
605
|
+
# FIXME: missing from adapter
|
606
|
+
# @connection.busy_timeout(self.class.type_cast_config_to_integer(@config[:timeout])) if @config[:timeout]
|
607
|
+
|
568
608
|
execute("PRAGMA foreign_keys = ON", "SCHEMA")
|
569
609
|
end
|
570
610
|
|
@@ -720,11 +760,15 @@ module ActiveRecord::ConnectionAdapters
|
|
720
760
|
|
721
761
|
# because the JDBC driver doesn't like multiple SQL statements in one JDBC statement
|
722
762
|
def combine_multi_statements(total_sql)
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
763
|
+
total_sql
|
764
|
+
end
|
765
|
+
|
766
|
+
# combine
|
767
|
+
def write_query?(sql) # :nodoc:
|
768
|
+
return sql.any? { |stmt| super(stmt) } if sql.kind_of? Array
|
769
|
+
!READ_QUERY.match?(sql)
|
770
|
+
rescue ArgumentError # Invalid encoding
|
771
|
+
!READ_QUERY.match?(sql.b)
|
728
772
|
end
|
729
773
|
|
730
774
|
def initialize_type_map(m = type_map)
|
@@ -11,18 +11,6 @@ module ArJdbc
|
|
11
11
|
require 'arjdbc/tasks/jdbc_database_tasks'
|
12
12
|
require 'arjdbc/tasks/sqlite_database_tasks_patch'
|
13
13
|
require 'arjdbc/tasks/mssql_database_tasks'
|
14
|
-
#require 'arjdbc/tasks/db2_database_tasks'
|
15
|
-
#require 'arjdbc/tasks/derby_database_tasks'
|
16
|
-
#require 'arjdbc/tasks/h2_database_tasks'
|
17
|
-
#require 'arjdbc/tasks/hsqldb_database_tasks'
|
18
|
-
|
19
|
-
# re-invent built-in (but deprecated on 4.0) tasks :
|
20
|
-
# tasks for custom (JDBC) adapters :
|
21
|
-
#register_tasks(/db2/, DB2DatabaseTasks)
|
22
|
-
#register_tasks(/derby/, DerbyDatabaseTasks)
|
23
|
-
#register_tasks(/h2/, H2DatabaseTasks)
|
24
|
-
#register_tasks(/hsqldb/, HSQLDBDatabaseTasks)
|
25
|
-
# (default) generic JDBC task :
|
26
14
|
register_tasks(/^jdbc$/, JdbcDatabaseTasks)
|
27
15
|
register_tasks(/sqlserver/, MSSQLDatabaseTasks)
|
28
16
|
|
@@ -31,33 +31,11 @@ module ArJdbc
|
|
31
31
|
SerializedAttributes.dump_column_value(self, column)
|
32
32
|
end
|
33
33
|
|
34
|
-
if defined? ActiveRecord::Type::Serialized # ArJdbc::AR42
|
35
|
-
|
36
34
|
def self.dump_column_value(record, column)
|
37
35
|
value = record[ column.name.to_s ]
|
38
36
|
column.cast_type.type_cast_for_database(value)
|
39
37
|
end
|
40
38
|
|
41
|
-
else
|
42
|
-
|
43
|
-
def self.dump_column_value(record, column)
|
44
|
-
value = record[ name = column.name.to_s ]
|
45
|
-
if record.class.respond_to?(:serialized_attributes)
|
46
|
-
if coder = record.class.serialized_attributes[name]
|
47
|
-
value = coder.respond_to?(:dump) ? coder.dump(value) : value.to_yaml
|
48
|
-
end
|
49
|
-
else
|
50
|
-
if record.respond_to?(:unserializable_attribute?)
|
51
|
-
value = value.to_yaml if record.unserializable_attribute?(name, column)
|
52
|
-
else
|
53
|
-
value = value.to_yaml if value.is_a?(Hash)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
value
|
57
|
-
end
|
58
|
-
|
59
|
-
end
|
60
|
-
|
61
39
|
def self.setup(lob_type = nil, after_save_alias = nil)
|
62
40
|
ActiveRecord::Base.send :include, self # include SerializedAttributes
|
63
41
|
ActiveRecord::Base.lob_type = lob_type unless lob_type.nil?
|
@@ -4,7 +4,8 @@ module ArJdbc
|
|
4
4
|
module Util
|
5
5
|
module TableCopier
|
6
6
|
|
7
|
-
# taken from SQLite adapter, code loosely based on
|
7
|
+
# taken from SQLite adapter, code loosely based on
|
8
|
+
# https://github.com/rails/rails/blob/d3e5118/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
|
8
9
|
|
9
10
|
# Performs changes for table by first copying (and preserving contents)
|
10
11
|
# into another (temporary) table, than alters and copies all data back.
|
data/lib/arjdbc/version.rb
CHANGED
data/rakelib/02-test.rake
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
|
2
2
|
test_tasks = [ 'test_mysql', 'test_sqlite3', 'test_postgresql_with_hint' ]
|
3
3
|
if defined?(JRUBY_VERSION)
|
4
|
-
test_tasks.push :
|
4
|
+
test_tasks.push :test_hsqldb, :test_h2
|
5
5
|
test_tasks.push :test_jndi, :test_jdbc
|
6
6
|
end
|
7
7
|
|
@@ -55,7 +55,6 @@ def test_task_for(adapter, options = {})
|
|
55
55
|
test_task
|
56
56
|
end
|
57
57
|
|
58
|
-
test_task_for :Derby, :desc => 'Run tests against (embedded) DerbyDB'
|
59
58
|
test_task_for :H2, :desc => 'Run tests against H2 database engine'
|
60
59
|
test_task_for :HSQLDB, :desc => 'Run tests against HyperSQL (Java) database'
|
61
60
|
test_task_for :MSSQL, :driver => :jtds, :database_name => 'MS-SQL (SQLServer)'
|
@@ -65,29 +64,22 @@ test_task_for :PostgreSQL, :driver => ENV['JDBC_POSTGRES_VERSION'] || 'postgres'
|
|
65
64
|
task :test_postgres => :test_postgresql # alias
|
66
65
|
test_task_for :SQLite3, :driver => ENV['JDBC_SQLITE_VERSION']
|
67
66
|
task :test_sqlite => :test_sqlite3 # alias
|
68
|
-
test_task_for :Firebird
|
69
67
|
|
70
68
|
test_task_for :MariaDB, :files => FileList["test/db/mysql/*_test.rb"] do |test_task| #, :prereqs => 'db:mysql'
|
71
69
|
test_task.ruby_opts << '-rdb/mariadb_config'
|
72
70
|
end
|
73
71
|
|
74
72
|
# ensure driver for these DBs is on your class-path
|
75
|
-
[ :Oracle
|
73
|
+
[ :Oracle ].each do |adapter|
|
76
74
|
test_task_for adapter, :desc => "Run tests against #{adapter} (ensure driver is on class-path)"
|
77
75
|
end
|
78
76
|
|
79
|
-
test_task_for :AS400, :desc => "Run tests against AS400 (DB2) (ensure driver is on class-path)",
|
80
|
-
:files => FileList["test/db2*_test.rb"] + FileList["test/db/db2/*_test.rb"]
|
81
|
-
|
82
|
-
#task :test_jdbc => [ :test_jdbc_mysql, :test_jdbc_derby ] if defined?(JRUBY_VERSION)
|
83
|
-
|
84
77
|
test_task_for 'JDBC', :desc => 'Run tests against plain JDBC adapter (uses MySQL and Derby)',
|
85
78
|
:prereqs => [ 'db:mysql' ], :files => FileList['test/*jdbc_*test.rb'] do |test_task|
|
86
|
-
test_task.libs << 'jdbc-mysql/lib'
|
79
|
+
test_task.libs << 'jdbc-mysql/lib'
|
87
80
|
end
|
88
81
|
|
89
82
|
# TODO since Derby AR 5.x support is not implemented we only run JNDI with MySQL :
|
90
|
-
#task :test_jndi => [ :test_jndi_mysql, :test_jndi_derby ] if defined?(JRUBY_VERSION)
|
91
83
|
task :test_jndi => [ :test_jndi_mysql ] if defined?(JRUBY_VERSION)
|
92
84
|
|
93
85
|
jndi_classpath = [ 'test/jars/tomcat-juli.jar', 'test/jars/tomcat-catalina.jar' ]
|
@@ -101,13 +93,6 @@ get_jndi_classpath_opt = lambda do
|
|
101
93
|
"-J-cp \"#{cp.join(File::PATH_SEPARATOR)}\""
|
102
94
|
end
|
103
95
|
|
104
|
-
test_task_for 'JNDI_Derby', :desc => 'Run tests against a Derby JNDI connection',
|
105
|
-
:prereqs => jndi_classpath, :files => FileList['test/*jndi_derby*test.rb'] do |test_task|
|
106
|
-
test_task.libs << 'jdbc-derby/lib'
|
107
|
-
test_task.ruby_opts << get_jndi_classpath_opt.call
|
108
|
-
#test_task.verbose = true
|
109
|
-
end
|
110
|
-
|
111
96
|
test_task_for 'JNDI_MySQL', :desc => 'Run tests against a MySQL JNDI connection',
|
112
97
|
:prereqs => [ 'db:mysql' ] + jndi_classpath, :files => FileList['test/*jndi_mysql*test.rb'] do |test_task|
|
113
98
|
test_task.libs << 'jdbc-mysql/lib'
|
@@ -720,6 +720,21 @@ public class RubyJdbcConnection extends RubyObject {
|
|
720
720
|
}
|
721
721
|
}
|
722
722
|
|
723
|
+
@JRubyMethod(name = "closed?")
|
724
|
+
public IRubyObject closed_p(ThreadContext context) {
|
725
|
+
try {
|
726
|
+
final Connection connection = getConnectionInternal(false);
|
727
|
+
|
728
|
+
if (connection == null) return context.fals;
|
729
|
+
|
730
|
+
// NOTE: isClosed method generally cannot be called to determine
|
731
|
+
// whether a connection to a database is valid or invalid ...
|
732
|
+
return context.runtime.newBoolean(connection.isClosed());
|
733
|
+
} catch (SQLException e) {
|
734
|
+
return handleException(context, e);
|
735
|
+
}
|
736
|
+
}
|
737
|
+
|
723
738
|
@JRubyMethod(name = "close")
|
724
739
|
public IRubyObject close(final ThreadContext context) {
|
725
740
|
final Connection connection = getConnection(false);
|
@@ -2642,8 +2657,8 @@ public class RubyJdbcConnection extends RubyObject {
|
|
2642
2657
|
}
|
2643
2658
|
|
2644
2659
|
private String default_timezone(final ThreadContext context) {
|
2645
|
-
final
|
2646
|
-
return default_timezone.call(context,
|
2660
|
+
final RubyModule activeRecord = ActiveRecord(context);
|
2661
|
+
return default_timezone.call(context, activeRecord, activeRecord).asJavaString(); // :utc (or :local)
|
2647
2662
|
}
|
2648
2663
|
|
2649
2664
|
// ActiveRecord::Base.default_timezone
|
@@ -387,7 +387,20 @@ public class PostgreSQLRubyJdbcConnection extends arjdbc.jdbc.RubyJdbcConnection
|
|
387
387
|
RubyDate rubyDate = (RubyDate) value;
|
388
388
|
DateTime dt = rubyDate.getDateTime();
|
389
389
|
// pgjdbc needs adjustment for default JVM timezone
|
390
|
-
|
390
|
+
//
|
391
|
+
// If the date is a day when Daylight savings starts (2am changed to 3am),
|
392
|
+
// And we are in a positive GMT timezone (Australia/Melbourne)
|
393
|
+
// Then removing milliseconds equal to the TimeZone (+11 GMT),
|
394
|
+
// will result in the date being the previous day 23:00, because of the missing hour.
|
395
|
+
// So we check if the date after the shift is outside of daylight time and remove an hours worth of milliseconds.
|
396
|
+
final long dateMillis = dt.getMillis();
|
397
|
+
long offset = TZ_DEFAULT.getOffset(dt.getMillis());
|
398
|
+
if (TZ_DEFAULT.inDaylightTime(new Date(dt.getMillis())) && !TZ_DEFAULT.inDaylightTime(new Date(dateMillis - offset))) {
|
399
|
+
offset -= 3600000; // 1 hour
|
400
|
+
}
|
401
|
+
Date utcShiftedDate = new Date(dateMillis - offset);
|
402
|
+
|
403
|
+
statement.setDate(index, utcShiftedDate);
|
391
404
|
return;
|
392
405
|
}
|
393
406
|
|
@@ -402,6 +402,11 @@ public class SQLite3RubyJdbcConnection extends RubyJdbcConnection {
|
|
402
402
|
finally { close(statement); }
|
403
403
|
}
|
404
404
|
|
405
|
+
@JRubyMethod
|
406
|
+
public IRubyObject filename(ThreadContext context) {
|
407
|
+
return getConfigValue(context, "database");
|
408
|
+
}
|
409
|
+
|
405
410
|
@Override
|
406
411
|
@JRubyMethod(name = "rollback_savepoint", required = 1)
|
407
412
|
public IRubyObject rollback_savepoint(final ThreadContext context, final IRubyObject name) {
|
@@ -460,6 +465,34 @@ public class SQLite3RubyJdbcConnection extends RubyJdbcConnection {
|
|
460
465
|
return context.runtime.newBoolean(connection.isReadOnly());
|
461
466
|
}
|
462
467
|
|
468
|
+
// note: sqlite3 cext uses this same method but we do not combine all our statements
|
469
|
+
// into a single ; delimited string but leave it as an array of statements. This is
|
470
|
+
// because the JDBC way of handling batches is to use addBatch().
|
471
|
+
@JRubyMethod(name = "execute_batch2")
|
472
|
+
public IRubyObject execute_batch2(ThreadContext context, IRubyObject statementsArg) {
|
473
|
+
// Assume we will only call this with an array.
|
474
|
+
final RubyArray statements = (RubyArray) statementsArg;
|
475
|
+
return withConnection(context, connection -> {
|
476
|
+
Statement statement = null;
|
477
|
+
try {
|
478
|
+
statement = createStatement(context, connection);
|
479
|
+
|
480
|
+
int length = statements.getLength();
|
481
|
+
for (int i = 0; i < length; i++) {
|
482
|
+
statement.addBatch(sqlString(statements.eltOk(i)));
|
483
|
+
}
|
484
|
+
statement.executeBatch();
|
485
|
+
return context.nil;
|
486
|
+
} catch (final SQLException e) {
|
487
|
+
// Generate list semicolon list of statements which should match AR error formatting more.
|
488
|
+
debugErrorSQL(context, sqlString(statements.join(context, context.runtime.newString(";\n"))));
|
489
|
+
throw e;
|
490
|
+
} finally {
|
491
|
+
close(statement);
|
492
|
+
}
|
493
|
+
});
|
494
|
+
}
|
495
|
+
|
463
496
|
@Override
|
464
497
|
protected void setDecimalParameter(final ThreadContext context,
|
465
498
|
final Connection connection, final PreparedStatement statement,
|