activerecord-jdbc-alt-adapter 61.2.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.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +273 -0
  3. data/.gitignore +1 -0
  4. data/.travis.yml +3 -4
  5. data/Gemfile +8 -6
  6. data/README.md +2 -1
  7. data/Rakefile +1 -1
  8. data/activerecord-jdbc-adapter.gemspec +2 -2
  9. data/activerecord-jdbc-alt-adapter.gemspec +2 -2
  10. data/lib/arel/visitors/compat.rb +5 -33
  11. data/lib/arel/visitors/h2.rb +1 -13
  12. data/lib/arel/visitors/hsqldb.rb +1 -21
  13. data/lib/arel/visitors/sql_server.rb +2 -103
  14. data/lib/arjdbc/abstract/core.rb +8 -9
  15. data/lib/arjdbc/abstract/database_statements.rb +4 -4
  16. data/lib/arjdbc/discover.rb +0 -67
  17. data/lib/arjdbc/hsqldb/adapter.rb +2 -2
  18. data/lib/arjdbc/jdbc/adapter.rb +3 -3
  19. data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
  20. data/lib/arjdbc/jdbc/adapter_require.rb +3 -1
  21. data/lib/arjdbc/jdbc/column.rb +1 -26
  22. data/lib/arjdbc/jdbc/type_cast.rb +2 -2
  23. data/lib/arjdbc/jdbc.rb +0 -7
  24. data/lib/arjdbc/mssql/adapter.rb +134 -105
  25. data/lib/arjdbc/mssql/connection_methods.rb +0 -3
  26. data/lib/arjdbc/mssql/quoting.rb +26 -27
  27. data/lib/arjdbc/mssql/schema_creation.rb +1 -1
  28. data/lib/arjdbc/mssql/schema_definitions.rb +32 -17
  29. data/lib/arjdbc/mssql/schema_dumper.rb +13 -1
  30. data/lib/arjdbc/mssql/schema_statements.rb +61 -36
  31. data/lib/arjdbc/mssql/transaction.rb +2 -2
  32. data/lib/arjdbc/mssql/types/date_and_time_types.rb +6 -6
  33. data/lib/arjdbc/mssql/types/numeric_types.rb +2 -2
  34. data/lib/arjdbc/mssql.rb +1 -1
  35. data/lib/arjdbc/mysql/adapter.rb +2 -1
  36. data/lib/arjdbc/oracle/adapter.rb +4 -23
  37. data/lib/arjdbc/postgresql/adapter.rb +64 -1
  38. data/lib/arjdbc/postgresql/oid_types.rb +68 -47
  39. data/lib/arjdbc/sqlite3/adapter.rb +132 -88
  40. data/lib/arjdbc/tasks/database_tasks.rb +0 -12
  41. data/lib/arjdbc/util/serialized_attributes.rb +0 -22
  42. data/lib/arjdbc/util/table_copier.rb +2 -1
  43. data/lib/arjdbc/version.rb +1 -1
  44. data/rakelib/02-test.rake +3 -18
  45. data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +17 -2
  46. data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +33 -0
  47. metadata +8 -40
  48. data/lib/active_record/connection_adapters/as400_adapter.rb +0 -2
  49. data/lib/active_record/connection_adapters/db2_adapter.rb +0 -1
  50. data/lib/active_record/connection_adapters/derby_adapter.rb +0 -1
  51. data/lib/active_record/connection_adapters/informix_adapter.rb +0 -1
  52. data/lib/arel/visitors/db2.rb +0 -137
  53. data/lib/arel/visitors/derby.rb +0 -112
  54. data/lib/arel/visitors/firebird.rb +0 -79
  55. data/lib/arjdbc/db2/adapter.rb +0 -808
  56. data/lib/arjdbc/db2/as400.rb +0 -142
  57. data/lib/arjdbc/db2/column.rb +0 -131
  58. data/lib/arjdbc/db2/connection_methods.rb +0 -48
  59. data/lib/arjdbc/db2.rb +0 -4
  60. data/lib/arjdbc/derby/active_record_patch.rb +0 -13
  61. data/lib/arjdbc/derby/adapter.rb +0 -521
  62. data/lib/arjdbc/derby/connection_methods.rb +0 -20
  63. data/lib/arjdbc/derby/schema_creation.rb +0 -15
  64. data/lib/arjdbc/derby.rb +0 -3
  65. data/lib/arjdbc/firebird/adapter.rb +0 -413
  66. data/lib/arjdbc/firebird/connection_methods.rb +0 -23
  67. data/lib/arjdbc/firebird.rb +0 -4
  68. data/lib/arjdbc/informix/adapter.rb +0 -139
  69. data/lib/arjdbc/informix/connection_methods.rb +0 -9
  70. data/lib/arjdbc/sybase/adapter.rb +0 -47
  71. data/lib/arjdbc/sybase.rb +0 -2
  72. data/lib/arjdbc/tasks/db2_database_tasks.rb +0 -104
  73. data/lib/arjdbc/tasks/derby_database_tasks.rb +0 -95
  74. data/src/java/arjdbc/derby/DerbyModule.java +0 -178
  75. data/src/java/arjdbc/derby/DerbyRubyJdbcConnection.java +0 -152
  76. data/src/java/arjdbc/firebird/FirebirdRubyJdbcConnection.java +0 -174
  77. 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
- # DIFFERENCE: class_attribute in original adapter is moved down to our section which is a class
84
- # since we cannot define it here in the module (original source this is a class).
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
- database_version >= "3.9.0"
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
- # DATABASE STATEMENTS ======================================
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
- def remove_index(table_name, column_name = nil, **options) # :nodoc:
237
- return if options[:if_exists] && !index_exists?(table_name, column_name, **options)
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 do |_, fk_options|
269
- fk_options[:column] == column_name.to_s
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 = type
295
- self.options.merge!(options)
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
- sql << insert.touch_model_timestamps_unless { |column| "#{column} IS excluded.#{column}" }
345
- sql << insert.updatable_columns.map { |column| "#{column}=excluded.#{column}" }.join(",")
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[:properties] && config[:properties][:shared_cache] == true
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: column.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
- when /column(s)? .* (is|are) not unique/, /UNIQUE constraint failed: .*/
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
- when /.* may not be NULL/, /NOT NULL constraint failed: .*/
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
- when /FOREIGN KEY constraint failed/i
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 = exec_query(sql, "SCHEMA").first
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["sql"].split("(", 2).last
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
- if total_sql.length == 1
724
- total_sql.first
725
- else
726
- total_sql
727
- end
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 http://git.io/P7tFQA
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.
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ArJdbc
4
- VERSION = '61.2.0'
4
+ VERSION = '70.0.0.rc1'
5
5
  end
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 :test_derby, :test_hsqldb, :test_h2
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, :DB2, :Informix, :CacheDB ].each do |adapter|
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' << 'jdbc-derby/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 RubyClass base = getBase(context.runtime);
2646
- return default_timezone.call(context, base, base).asJavaString(); // :utc (or :local)
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
@@ -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,