activerecord-jdbc-alt-adapter 52.5.1-java → 60.2.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.nvimlog +0 -0
  4. data/.travis.yml +61 -37
  5. data/Gemfile +10 -3
  6. data/README.md +44 -28
  7. data/Rakefile +1 -1
  8. data/Rakefile.jdbc +8 -1
  9. data/activerecord-jdbc-adapter.gemspec +5 -8
  10. data/activerecord-jdbc-alt-adapter.gemspec +5 -8
  11. data/lib/arel/visitors/sqlserver.rb +33 -23
  12. data/lib/arjdbc/abstract/connection_management.rb +7 -0
  13. data/lib/arjdbc/abstract/core.rb +16 -23
  14. data/lib/arjdbc/abstract/database_statements.rb +24 -0
  15. data/lib/arjdbc/abstract/statement_cache.rb +2 -5
  16. data/lib/arjdbc/abstract/transaction_support.rb +5 -3
  17. data/lib/arjdbc/db2/column.rb +0 -39
  18. data/lib/arjdbc/derby/adapter.rb +1 -20
  19. data/lib/arjdbc/firebird/adapter.rb +0 -21
  20. data/lib/arjdbc/h2/adapter.rb +0 -15
  21. data/lib/arjdbc/hsqldb/adapter.rb +0 -14
  22. data/lib/arjdbc/informix/adapter.rb +0 -23
  23. data/lib/arjdbc/jdbc/adapter.rb +3 -1
  24. data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
  25. data/lib/arjdbc/jdbc/adapter_require.rb +3 -1
  26. data/lib/arjdbc/jdbc/base_ext.rb +3 -1
  27. data/lib/arjdbc/jdbc/callbacks.rb +2 -0
  28. data/lib/arjdbc/jdbc/column.rb +2 -0
  29. data/lib/arjdbc/jdbc/connection.rb +2 -0
  30. data/lib/arjdbc/jdbc/connection_methods.rb +2 -0
  31. data/lib/arjdbc/jdbc/error.rb +2 -0
  32. data/lib/arjdbc/jdbc/extension.rb +2 -0
  33. data/lib/arjdbc/jdbc/java.rb +3 -1
  34. data/lib/arjdbc/jdbc/railtie.rb +3 -1
  35. data/lib/arjdbc/jdbc/rake_tasks.rb +3 -1
  36. data/lib/arjdbc/jdbc/serialized_attributes_helper.rb +3 -1
  37. data/lib/arjdbc/jdbc/type_cast.rb +2 -0
  38. data/lib/arjdbc/jdbc/type_converter.rb +2 -0
  39. data/lib/arjdbc/mssql/adapter.rb +105 -36
  40. data/lib/arjdbc/mssql/column.rb +5 -1
  41. data/lib/arjdbc/mssql/connection_methods.rb +8 -2
  42. data/lib/arjdbc/mssql/database_limits.rb +2 -0
  43. data/lib/arjdbc/mssql/database_statements.rb +43 -5
  44. data/lib/arjdbc/mssql/errors.rb +2 -0
  45. data/lib/arjdbc/mssql/explain_support.rb +3 -1
  46. data/lib/arjdbc/mssql/extensions/attribute_methods.rb +5 -1
  47. data/lib/arjdbc/mssql/extensions/calculations.rb +2 -0
  48. data/lib/arjdbc/mssql/quoting.rb +38 -0
  49. data/lib/arjdbc/mssql/schema_creation.rb +24 -2
  50. data/lib/arjdbc/mssql/schema_definitions.rb +10 -0
  51. data/lib/arjdbc/mssql/schema_dumper.rb +2 -0
  52. data/lib/arjdbc/mssql/schema_statements.rb +63 -21
  53. data/lib/arjdbc/mssql/transaction.rb +2 -0
  54. data/lib/arjdbc/mssql/types/binary_types.rb +2 -0
  55. data/lib/arjdbc/mssql/types/date_and_time_types.rb +2 -0
  56. data/lib/arjdbc/mssql/types/deprecated_types.rb +2 -0
  57. data/lib/arjdbc/mssql/types/numeric_types.rb +2 -0
  58. data/lib/arjdbc/mssql/types/string_types.rb +2 -0
  59. data/lib/arjdbc/mssql/types.rb +2 -0
  60. data/lib/arjdbc/mssql/utils.rb +2 -0
  61. data/lib/arjdbc/mssql.rb +3 -1
  62. data/lib/arjdbc/mysql/adapter.rb +47 -18
  63. data/lib/arjdbc/postgresql/adapter.rb +240 -214
  64. data/lib/arjdbc/postgresql/base/array_decoder.rb +2 -0
  65. data/lib/arjdbc/postgresql/base/array_encoder.rb +4 -2
  66. data/lib/arjdbc/postgresql/base/array_parser.rb +4 -2
  67. data/lib/arjdbc/postgresql/base/pgconn.rb +2 -0
  68. data/lib/arjdbc/postgresql/column.rb +6 -4
  69. data/lib/arjdbc/postgresql/name.rb +2 -0
  70. data/lib/arjdbc/postgresql/oid_types.rb +3 -1
  71. data/lib/arjdbc/sqlite3/adapter.rb +188 -180
  72. data/lib/arjdbc/sqlite3/connection_methods.rb +15 -4
  73. data/lib/arjdbc/tasks/databases.rake +13 -10
  74. data/lib/arjdbc/tasks/mssql_database_tasks.rb +49 -5
  75. data/lib/arjdbc/util/quoted_cache.rb +3 -1
  76. data/lib/arjdbc/util/serialized_attributes.rb +3 -1
  77. data/lib/arjdbc/util/table_copier.rb +3 -1
  78. data/lib/arjdbc/version.rb +1 -1
  79. data/pom.xml +4 -4
  80. data/rakelib/01-tomcat.rake +2 -2
  81. data/src/java/arjdbc/ArJdbcModule.java +5 -5
  82. data/src/java/arjdbc/jdbc/DriverWrapper.java +1 -9
  83. data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +406 -629
  84. data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +88 -0
  85. data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +13 -23
  86. data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +56 -30
  87. data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +94 -99
  88. data/src/java/arjdbc/util/DateTimeUtils.java +12 -4
  89. metadata +7 -16
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # This implements a basic encoder to work around ActiveRecord's dependence on the pg gem
2
4
  module ActiveRecord::ConnectionAdapters::PostgreSQL::OID
3
5
  class Array < ActiveModel::Type::Value
@@ -6,10 +8,10 @@ module ActiveRecord::ConnectionAdapters::PostgreSQL::OID
6
8
  class Array
7
9
 
8
10
  def initialize(name:, delimiter:)
9
- @type = if name == 'string[]'.freeze
11
+ @type = if name == 'string[]'
10
12
  'text'.freeze
11
13
  else
12
- base_type = name.chomp('[]'.freeze).to_sym
14
+ base_type = name.chomp('[]').to_sym
13
15
  ActiveRecord::Base.connection.native_database_types[base_type][:name]
14
16
  end
15
17
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # based on active_record/connection_adapters/postgresql/array_parser.rb
2
4
  # until it's some day shareable with Rails ... this is not public API !
3
5
  module ActiveRecord
@@ -33,7 +35,7 @@ module ActiveRecord
33
35
  is_escaping = false
34
36
  is_quoted = false
35
37
  was_quoted = false
36
- current_item = ''
38
+ current_item = ''.dup
37
39
 
38
40
  local_index = index
39
41
  while local_index
@@ -58,7 +60,7 @@ module ActiveRecord
58
60
  is_escaping = true
59
61
  when COMMA
60
62
  add_item_to_array(array, current_item, was_quoted)
61
- current_item = ''
63
+ current_item = ''.dup
62
64
  was_quoted = false
63
65
  when DOUBLE_QUOTE
64
66
  is_quoted = true
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord::ConnectionAdapters::PostgreSQL::OID
2
4
  class Bytea < ActiveModel::Type::Binary
3
5
  module PG
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ArJdbc
2
4
  module PostgreSQL
3
5
 
@@ -20,13 +22,13 @@ module ArJdbc
20
22
  # Quoted types
21
23
  when /\A[\(B]?'(.*)'.*::"?([\w. ]+)"?(?:\[\])?\z/m
22
24
  # The default 'now'::date is CURRENT_DATE
23
- if $1 == "now".freeze && $2 == "date".freeze
25
+ if $1 == "now" && $2 == "date"
24
26
  nil
25
27
  else
26
- $1.gsub("''".freeze, "'".freeze)
28
+ $1.gsub("''", "'")
27
29
  end
28
30
  # Boolean types
29
- when 'true'.freeze, 'false'.freeze
31
+ when 'true', 'false'
30
32
  default
31
33
  # Numeric types
32
34
  when /\A\(?(-?\d+(\.\d*)?)\)?(::bigint)?\z/
@@ -46,7 +48,7 @@ module ArJdbc
46
48
  end
47
49
 
48
50
  def has_default_function?(default_value, default)
49
- !default_value && %r{\w+\(.*\)|\(.*\)::\w+|CURRENT_DATE|CURRENT_TIMESTAMP} === default
51
+ !default_value && %r{\w+\(.*\)|\(.*\)::\w+|CURRENT_DATE|CURRENT_TIMESTAMP}.match?(default)
50
52
  end
51
53
  end
52
54
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # This patches the Name class so that it doesn't use pg gem specific quoting
2
4
  module ActiveRecord
3
5
  module ConnectionAdapters
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'thread'
2
4
 
3
5
  module ArJdbc
@@ -211,7 +213,7 @@ module ArJdbc
211
213
  if oid
212
214
  if oid.is_a? Numeric || oid.match(/^\d+$/)
213
215
  # numeric OID
214
- query += "WHERE t.oid::integer = %s" % oid
216
+ query += "WHERE t.oid = %s" % oid
215
217
 
216
218
  elsif m = oid.match(/"?(\w+)"?\."?(\w+)"?/)
217
219
  # namespace and type name
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ArJdbc.load_java_part :SQLite3
2
4
 
3
5
  require "arjdbc/abstract/core"
@@ -30,7 +32,7 @@ module ArJdbc
30
32
  SchemaCreation = ConnectionAdapters::SQLite3::SchemaCreation
31
33
  SQLite3Adapter = ConnectionAdapters::AbstractAdapter
32
34
 
33
- ADAPTER_NAME = 'SQLite'.freeze
35
+ ADAPTER_NAME = 'SQLite'
34
36
 
35
37
  # DIFFERENCE: FQN
36
38
  include ::ActiveRecord::ConnectionAdapters::SQLite3::Quoting
@@ -54,20 +56,8 @@ module ArJdbc
54
56
  # DIFFERENCE: class_attribute in original adapter is moved down to our section which is a class
55
57
  # since we cannot define it here in the module (original source this is a class).
56
58
 
57
- class StatementPool < ConnectionAdapters::StatementPool
58
- private
59
-
60
- def dealloc(stmt)
61
- stmt[:stmt].close unless stmt[:stmt].closed?
62
- end
63
- end
64
-
65
59
  def initialize(connection, logger, connection_options, config)
66
60
  super(connection, logger, config)
67
-
68
- @active = true
69
- @statements = StatementPool.new(self.class.type_cast_config_to_integer(config[:statement_limit]))
70
-
71
61
  configure_connection
72
62
  end
73
63
 
@@ -80,15 +70,19 @@ module ArJdbc
80
70
  end
81
71
 
82
72
  def supports_partial_index?
83
- sqlite_version >= "3.8.0"
73
+ database_version >= "3.9.0"
74
+ end
75
+
76
+ def supports_expression_index?
77
+ database_version >= "3.9.0"
84
78
  end
85
79
 
86
80
  def requires_reloading?
87
81
  true
88
82
  end
89
83
 
90
- def supports_foreign_keys_in_create?
91
- sqlite_version >= "3.6.19"
84
+ def supports_foreign_keys?
85
+ true
92
86
  end
93
87
 
94
88
  def supports_views?
@@ -99,26 +93,22 @@ module ArJdbc
99
93
  true
100
94
  end
101
95
 
102
- def supports_multi_insert?
103
- sqlite_version >= "3.7.11"
96
+ def supports_json?
97
+ true
104
98
  end
105
99
 
106
- def active?
107
- @active
100
+ def supports_common_table_expressions?
101
+ database_version >= "3.8.3"
108
102
  end
109
103
 
110
- # Disconnects from the database if already connected. Otherwise, this
111
- # method does nothing.
112
- def disconnect!
113
- super
114
- @active = false
115
- @connection.close rescue nil
104
+ def supports_insert_on_conflict?
105
+ database_version >= "3.24.0"
116
106
  end
107
+ alias supports_insert_on_duplicate_skip? supports_insert_on_conflict?
108
+ alias supports_insert_on_duplicate_update? supports_insert_on_conflict?
109
+ alias supports_insert_conflict_target? supports_insert_on_conflict?
117
110
 
118
- # Clears the prepared statements cache.
119
- def clear_cache!
120
- @statements.clear
121
- end
111
+ # DIFFERENCE: active?, reconnect!, disconnect! handles by arjdbc core
122
112
 
123
113
  def supports_index_sort_order?
124
114
  true
@@ -144,90 +134,68 @@ module ArJdbc
144
134
  true
145
135
  end
146
136
 
137
+ def supports_lazy_transactions?
138
+ true
139
+ end
140
+
147
141
  # REFERENTIAL INTEGRITY ====================================
148
142
 
149
143
  def disable_referential_integrity # :nodoc:
150
- old = query_value("PRAGMA foreign_keys")
144
+ old_foreign_keys = query_value("PRAGMA foreign_keys")
145
+ old_defer_foreign_keys = query_value("PRAGMA defer_foreign_keys")
151
146
 
152
147
  begin
148
+ execute("PRAGMA defer_foreign_keys = ON")
153
149
  execute("PRAGMA foreign_keys = OFF")
154
150
  yield
155
151
  ensure
156
- execute("PRAGMA foreign_keys = #{old}")
152
+ execute("PRAGMA defer_foreign_keys = #{old_defer_foreign_keys}")
153
+ execute("PRAGMA foreign_keys = #{old_foreign_keys}")
157
154
  end
158
155
  end
159
-
156
+
160
157
  #--
161
158
  # DATABASE STATEMENTS ======================================
162
159
  #++
163
160
 
161
+ READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(
162
+ :begin, :commit, :explain, :select, :pragma, :release, :savepoint, :rollback, :with
163
+ ) # :nodoc:
164
+ private_constant :READ_QUERY
165
+
166
+ def write_query?(sql) # :nodoc:
167
+ !READ_QUERY.match?(sql)
168
+ end
169
+
164
170
  def explain(arel, binds = [])
165
171
  sql = "EXPLAIN QUERY PLAN #{to_sql(arel, binds)}"
166
172
  # DIFFERENCE: FQN
167
173
  ::ActiveRecord::ConnectionAdapters::SQLite3::ExplainPrettyPrinter.new.pp(exec_query(sql, "EXPLAIN", []))
168
174
  end
169
175
 
170
- def exec_query(sql, name = nil, binds = [], prepare: false)
171
- type_casted_binds = type_casted_binds(binds)
172
-
173
- log(sql, name, binds, type_casted_binds) do
174
- ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
175
- # Don't cache statements if they are not prepared
176
- unless prepare
177
- stmt = @connection.prepare(sql)
178
- begin
179
- cols = stmt.columns
180
- unless without_prepared_statement?(binds)
181
- stmt.bind_params(type_casted_binds)
182
- end
183
- records = stmt.to_a
184
- ensure
185
- stmt.close
186
- end
187
- else
188
- cache = @statements[sql] ||= {
189
- stmt: @connection.prepare(sql)
190
- }
191
- stmt = cache[:stmt]
192
- cols = cache[:cols] ||= stmt.columns
193
- stmt.reset!
194
- stmt.bind_params(type_casted_binds)
195
- records = stmt.to_a
196
- end
197
-
198
- ActiveRecord::Result.new(cols, records)
199
- end
200
- end
201
- end
176
+ # DIFFERENCE: implemented in ArJdbc::Abstract::DatabaseStatements
177
+ #def exec_query(sql, name = nil, binds = [], prepare: false)
202
178
 
203
- def exec_delete(sql, name = 'SQL', binds = [])
204
- exec_query(sql, name, binds)
205
- @connection.changes
206
- end
207
- alias :exec_update :exec_delete
179
+ # DIFFERENCE: implemented in ArJdbc::Abstract::DatabaseStatements
180
+ #def exec_delete(sql, name = "SQL", binds = [])
208
181
 
209
182
  def last_inserted_id(result)
210
183
  @connection.last_insert_row_id
211
184
  end
212
185
 
213
- def execute(sql, name = nil) #:nodoc:
214
- log(sql, name) do
215
- ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
216
- @connection.execute(sql)
217
- end
218
- end
219
- end
186
+ # DIFFERENCE: implemented in ArJdbc::Abstract::DatabaseStatements
187
+ #def execute(sql, name = nil) #:nodoc:
220
188
 
221
189
  def begin_db_transaction #:nodoc:
222
- log("begin transaction",nil) { @connection.transaction }
190
+ log("begin transaction", nil) { @connection.transaction }
223
191
  end
224
192
 
225
193
  def commit_db_transaction #:nodoc:
226
- log("commit transaction",nil) { @connection.commit }
194
+ log("commit transaction", nil) { @connection.commit }
227
195
  end
228
196
 
229
197
  def exec_rollback_db_transaction #:nodoc:
230
- log("rollback transaction",nil) { @connection.rollback }
198
+ log("rollback transaction", nil) { @connection.rollback }
231
199
  end
232
200
 
233
201
  # SCHEMA STATEMENTS ========================================
@@ -251,13 +219,6 @@ module ArJdbc
251
219
  rename_table_indexes(table_name, new_name)
252
220
  end
253
221
 
254
- # DIFFERENCE: deprecated causes a JRuby 9.1 bug where "super" calls itself -> do inline
255
- def valid_alter_table_type?(type, options = {})
256
- ActiveSupport::Deprecation.deprecation_warning(__method__)
257
- !invalid_alter_table_type?(type, options)
258
- end
259
- #deprecate :valid_alter_table_type?
260
-
261
222
  def add_column(table_name, column_name, type, options = {}) #:nodoc:
262
223
  if invalid_alter_table_type?(type, options)
263
224
  alter_table(table_name) do |definition|
@@ -268,9 +229,12 @@ module ArJdbc
268
229
  end
269
230
  end
270
231
 
271
- def remove_column(table_name, column_name, type = nil, options = {}) #:nodoc:
232
+ def remove_column(table_name, column_name, type = nil, **options) #:nodoc:
272
233
  alter_table(table_name) do |definition|
273
234
  definition.remove_column column_name
235
+ definition.foreign_keys.delete_if do |_, fk_options|
236
+ fk_options[:column] == column_name.to_s
237
+ end
274
238
  end
275
239
  end
276
240
 
@@ -330,14 +294,6 @@ module ArJdbc
330
294
  end
331
295
  end
332
296
 
333
- def insert_fixtures(rows, table_name)
334
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
335
- `insert_fixtures` is deprecated and will be removed in the next version of Rails.
336
- Consider using `insert_fixtures_set` for performance improvement.
337
- MSG
338
- insert_fixtures_set(table_name => rows)
339
- end
340
-
341
297
  def insert_fixtures_set(fixture_set, tables_to_delete = [])
342
298
  disable_referential_integrity do
343
299
  transaction(requires_new: true) do
@@ -349,8 +305,50 @@ module ArJdbc
349
305
  end
350
306
  end
351
307
  end
352
-
308
+
309
+ def build_insert_sql(insert) # :nodoc:
310
+ sql = +"INSERT #{insert.into} #{insert.values_list}"
311
+
312
+ if insert.skip_duplicates?
313
+ sql << " ON CONFLICT #{insert.conflict_target} DO NOTHING"
314
+ elsif insert.update_duplicates?
315
+ sql << " ON CONFLICT #{insert.conflict_target} DO UPDATE SET "
316
+ sql << insert.updatable_columns.map { |column| "#{column}=excluded.#{column}" }.join(",")
317
+ end
318
+
319
+ sql
320
+ end
321
+
322
+ def get_database_version # :nodoc:
323
+ SQLite3Adapter::Version.new(query_value("SELECT sqlite_version(*)"))
324
+ end
325
+
326
+ def build_truncate_statement(table_name)
327
+ "DELETE FROM #{quote_table_name(table_name)}"
328
+ end
329
+
330
+ def build_truncate_statements(*table_names)
331
+ table_names.flatten.map { |table_name| build_truncate_statement table_name }
332
+ end
333
+
334
+ def truncate(table_name, name = nil)
335
+ ActiveRecord::Base.clear_query_caches_for_current_thread if @query_cache_enabled
336
+ execute(build_truncate_statement(table_name), name)
337
+ end
338
+
339
+ def check_version
340
+ if database_version < "3.8.0"
341
+ raise "Your version of SQLite (#{database_version}) is too old. Active Record supports SQLite >= 3.8."
342
+ end
343
+ end
344
+
353
345
  private
346
+ # See https://www.sqlite.org/limits.html,
347
+ # the default value is 999 when not configured.
348
+ def bind_params_length
349
+ 999
350
+ end
351
+
354
352
  def initialize_type_map(m = type_map)
355
353
  super
356
354
  register_class_with_limit m, %r(int)i, SQLite3Integer
@@ -366,17 +364,31 @@ module ArJdbc
366
364
  # See: https://www.sqlite.org/lang_altertable.html
367
365
  # SQLite has an additional restriction on the ALTER TABLE statement
368
366
  def invalid_alter_table_type?(type, options)
369
- type.to_sym == :primary_key || options[:primary_key]
367
+ type.to_sym == :primary_key || options[:primary_key] ||
368
+ options[:null] == false && options[:default].nil?
370
369
  end
371
370
 
372
- def alter_table(table_name, options = {}) #:nodoc:
371
+ def alter_table(table_name, foreign_keys = foreign_keys(table_name), **options)
373
372
  altered_table_name = "a#{table_name}"
374
- caller = lambda { |definition| yield definition if block_given? }
373
+
374
+ caller = lambda do |definition|
375
+ rename = options[:rename] || {}
376
+ foreign_keys.each do |fk|
377
+ if column = rename[fk.options[:column]]
378
+ fk.options[:column] = column
379
+ end
380
+ to_table = strip_table_name_prefix_and_suffix(fk.to_table)
381
+ definition.foreign_key(to_table, fk.options)
382
+ end
383
+
384
+ yield definition if block_given?
385
+ end
375
386
 
376
387
  transaction do
377
- move_table(table_name, altered_table_name,
378
- options.merge(temporary: true))
379
- move_table(altered_table_name, table_name, &caller)
388
+ disable_referential_integrity do
389
+ move_table(table_name, altered_table_name, options.merge(temporary: true))
390
+ move_table(altered_table_name, table_name, &caller)
391
+ end
380
392
  end
381
393
  end
382
394
 
@@ -395,23 +407,24 @@ module ArJdbc
395
407
  end
396
408
  columns(from).each do |column|
397
409
  column_name = options[:rename] ?
398
- (options[:rename][column.name] ||
399
- options[:rename][column.name.to_sym] ||
400
- column.name) : column.name
410
+ (options[:rename][column.name] ||
411
+ options[:rename][column.name.to_sym] ||
412
+ column.name) : column.name
401
413
 
402
414
  @definition.column(column_name, column.type,
403
- limit: column.limit, default: column.default,
404
- precision: column.precision, scale: column.scale,
405
- null: column.null, collation: column.collation,
406
- primary_key: column_name == from_primary_key
415
+ limit: column.limit, default: column.default,
416
+ precision: column.precision, scale: column.scale,
417
+ null: column.null, collation: column.collation,
418
+ primary_key: column_name == from_primary_key
407
419
  )
408
420
  end
421
+
409
422
  yield @definition if block_given?
410
423
  end
411
424
  copy_table_indexes(from, to, options[:rename] || {})
412
425
  copy_table_contents(from, to,
413
- @definition.columns.map(&:name),
414
- options[:rename] || {})
426
+ @definition.columns.map(&:name),
427
+ options[:rename] || {})
415
428
  end
416
429
 
417
430
  def copy_table_indexes(from, to, rename = {})
@@ -426,9 +439,12 @@ module ArJdbc
426
439
  name = name[1..-1]
427
440
  end
428
441
 
429
- to_column_names = columns(to).map(&:name)
430
- columns = index.columns.map { |c| rename[c] || c }.select do |column|
431
- to_column_names.include?(column)
442
+ columns = index.columns
443
+ if columns.is_a?(Array)
444
+ to_column_names = columns(to).map(&:name)
445
+ columns = columns.map { |c| rename[c] || c }.select do |column|
446
+ to_column_names.include?(column)
447
+ end
432
448
  end
433
449
 
434
450
  unless columns.empty?
@@ -454,27 +470,23 @@ module ArJdbc
454
470
  SELECT #{quoted_from_columns} FROM #{quote_table_name(from)}")
455
471
  end
456
472
 
457
- def sqlite_version
458
- @sqlite_version ||= SQLite3Adapter::Version.new(select_value("select sqlite_version(*)"))
459
- end
460
-
461
- def translate_exception(exception, message)
473
+ def translate_exception(exception, message:, sql:, binds:)
462
474
  case exception.message
463
- # SQLite 3.8.2 returns a newly formatted error message:
464
- # UNIQUE constraint failed: *table_name*.*column_name*
465
- # Older versions of SQLite return:
466
- # column *column_name* is not unique
467
- when /column(s)? .* (is|are) not unique/, /UNIQUE constraint failed: .*/
468
- # DIFFERENCE: FQN
469
- ::ActiveRecord::RecordNotUnique.new(message)
470
- when /.* may not be NULL/, /NOT NULL constraint failed: .*/
471
- # DIFFERENCE: FQN
472
- ::ActiveRecord::NotNullViolation.new(message)
473
- when /FOREIGN KEY constraint failed/i
474
- # DIFFERENCE: FQN
475
- ::ActiveRecord::InvalidForeignKey.new(message)
476
- else
477
- super
475
+ # SQLite 3.8.2 returns a newly formatted error message:
476
+ # UNIQUE constraint failed: *table_name*.*column_name*
477
+ # Older versions of SQLite return:
478
+ # column *column_name* is not unique
479
+ when /column(s)? .* (is|are) not unique/, /UNIQUE constraint failed: .*/
480
+ # DIFFERENCE: FQN
481
+ ::ActiveRecord::RecordNotUnique.new(message, sql: sql, binds: binds)
482
+ when /.* may not be NULL/, /NOT NULL constraint failed: .*/
483
+ # DIFFERENCE: FQN
484
+ ::ActiveRecord::NotNullViolation.new(message, sql: sql, binds: binds)
485
+ when /FOREIGN KEY constraint failed/i
486
+ # DIFFERENCE: FQN
487
+ ::ActiveRecord::InvalidForeignKey.new(message, sql: sql, binds: binds)
488
+ else
489
+ super
478
490
  end
479
491
  end
480
492
 
@@ -482,11 +494,11 @@ module ArJdbc
482
494
 
483
495
  def table_structure_with_collation(table_name, basic_structure)
484
496
  collation_hash = {}
485
- sql = <<-SQL
486
- SELECT sql FROM
487
- (SELECT * FROM sqlite_master UNION ALL
488
- SELECT * FROM sqlite_temp_master)
489
- WHERE type = 'table' AND name = #{quote(table_name)}
497
+ sql = <<~SQL
498
+ SELECT sql FROM
499
+ (SELECT * FROM sqlite_master UNION ALL
500
+ SELECT * FROM sqlite_temp_master)
501
+ WHERE type = 'table' AND name = #{quote(table_name)}
490
502
  SQL
491
503
 
492
504
  # Result will have following sample string
@@ -495,9 +507,9 @@ module ArJdbc
495
507
  result = exec_query(sql, "SCHEMA").first
496
508
 
497
509
  if result
498
- # Splitting with left parentheses and picking up last will return all
510
+ # Splitting with left parentheses and discarding the first part will return all
499
511
  # columns separated with comma(,).
500
- columns_string = result["sql"].split("(").last
512
+ columns_string = result["sql"].split("(", 2).last
501
513
 
502
514
  columns_string.split(",").each do |column_string|
503
515
  # This regex will match the column name and collation type and will save
@@ -515,7 +527,7 @@ module ArJdbc
515
527
  column
516
528
  end
517
529
  else
518
- basic_structure.to_hash
530
+ basic_structure.to_a
519
531
  end
520
532
  end
521
533
 
@@ -597,24 +609,6 @@ module ActiveRecord::ConnectionAdapters
597
609
 
598
610
  private
599
611
 
600
- # @override {ActiveRecord::ConnectionAdapters::Column#simplified_type}
601
- def simplified_type(field_type)
602
- case field_type
603
- when /boolean/i then :boolean
604
- when /text/i then :text
605
- when /varchar/i then :string
606
- when /int/i then :integer
607
- when /float/i then :float
608
- when /real|decimal/i then
609
- extract_scale(field_type) == 0 ? :integer : :decimal
610
- when /datetime/i then :datetime
611
- when /date/i then :date
612
- when /time/i then :time
613
- when /blob/i then :binary
614
- else super
615
- end
616
- end
617
-
618
612
  # @override {ActiveRecord::ConnectionAdapters::Column#extract_limit}
619
613
  def extract_limit(sql_type)
620
614
  return nil if sql_type =~ /^(real)\(\d+/i
@@ -646,28 +640,31 @@ module ActiveRecord::ConnectionAdapters
646
640
  class SQLite3Adapter < AbstractAdapter
647
641
  include ArJdbc::Abstract::Core
648
642
  include ArJdbc::SQLite3
643
+ include ArJdbc::Abstract::ConnectionManagement
649
644
  include ArJdbc::Abstract::DatabaseStatements
650
645
  include ArJdbc::Abstract::StatementCache
651
646
  include ArJdbc::Abstract::TransactionSupport
652
647
 
653
- # Note: This is part of original AR sqlite3_adapter.rb and not an override by us. This is to just
654
- # work around our copy of Sqlite3Adapter being a module above and not a class.
655
- ##
656
- # :singleton-method:
657
- # Indicates whether boolean values are stored in sqlite3 databases as 1
658
- # and 0 or 't' and 'f'. Leaving <tt>ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer</tt>
659
- # set to false is deprecated. SQLite databases have used 't' and 'f' to
660
- # serialize boolean values and must have old data converted to 1 and 0
661
- # (its native boolean serialization) before setting this flag to true.
662
- # Conversion can be accomplished by setting up a rake task which runs
663
- #
664
- # ExampleModel.where("boolean_column = 't'").update_all(boolean_column: 1)
665
- # ExampleModel.where("boolean_column = 'f'").update_all(boolean_column: 0)
666
- # for all models and all boolean columns, after which the flag must be set
667
- # to true by adding the following to your <tt>application.rb</tt> file:
668
- #
669
- # Rails.application.config.active_record.sqlite3.represent_boolean_as_integer = true
670
- class_attribute :represent_boolean_as_integer, default: false
648
+ def self.represent_boolean_as_integer=(value) # :nodoc:
649
+ if value == false
650
+ raise "`.represent_boolean_as_integer=` is now always true, so make sure your application can work with it and remove this settings."
651
+ end
652
+
653
+ ActiveSupport::Deprecation.warn(
654
+ "`.represent_boolean_as_integer=` is now always true, so setting this is deprecated and will be removed in Rails 6.1."
655
+ )
656
+ end
657
+
658
+ def self.database_exists?(config)
659
+ config = config.symbolize_keys
660
+ if config[:database] == ":memory:"
661
+ return true
662
+ else
663
+ database_file = defined?(Rails.root) ? File.expand_path(config[:database], Rails.root) : config[:database]
664
+ File.exist?(database_file)
665
+ end
666
+ end
667
+
671
668
 
672
669
  def supports_transaction_isolation?
673
670
  false
@@ -676,7 +673,7 @@ module ActiveRecord::ConnectionAdapters
676
673
  def begin_isolated_db_transaction(isolation)
677
674
  raise ActiveRecord::TransactionIsolationError, 'adapter does not support setting transaction isolation'
678
675
  end
679
-
676
+
680
677
  # SQLite driver doesn't support all types of insert statements with executeUpdate so
681
678
  # make it act like a regular query and the ids will be returned from #last_inserted_id
682
679
  # example: INSERT INTO "aircraft" DEFAULT VALUES
@@ -699,5 +696,16 @@ module ActiveRecord::ConnectionAdapters
699
696
 
700
697
  # Note: This is not an override of ours but a moved line from AR Sqlite3Adapter to register ours vs our copied module (which would be their class).
701
698
  # ActiveSupport.run_load_hooks(:active_record_sqlite3adapter, SQLite3Adapter)
699
+
700
+ private
701
+
702
+ # because the JDBC driver doesn't like multiple SQL statements in one JDBC statement
703
+ def combine_multi_statements(total_sql)
704
+ if total_sql.length == 1
705
+ total_sql.first
706
+ else
707
+ total_sql
708
+ end
709
+ end
702
710
  end
703
711
  end