activerecord-jdbc-alt-adapter 52.2.3-java → 60.1.0-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 (92) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/.travis.yml +80 -52
  4. data/Gemfile +10 -3
  5. data/README.md +55 -37
  6. data/Rakefile +31 -5
  7. data/Rakefile.jdbc +8 -1
  8. data/activerecord-jdbc-adapter.gemspec +6 -9
  9. data/activerecord-jdbc-alt-adapter.gemspec +6 -9
  10. data/lib/arel/visitors/sqlserver.rb +33 -23
  11. data/lib/arjdbc/abstract/connection_management.rb +7 -0
  12. data/lib/arjdbc/abstract/core.rb +17 -24
  13. data/lib/arjdbc/abstract/database_statements.rb +31 -20
  14. data/lib/arjdbc/abstract/statement_cache.rb +2 -5
  15. data/lib/arjdbc/abstract/transaction_support.rb +5 -3
  16. data/lib/arjdbc/db2/column.rb +0 -39
  17. data/lib/arjdbc/derby/adapter.rb +1 -20
  18. data/lib/arjdbc/firebird/adapter.rb +0 -21
  19. data/lib/arjdbc/h2/adapter.rb +0 -15
  20. data/lib/arjdbc/hsqldb/adapter.rb +0 -14
  21. data/lib/arjdbc/informix/adapter.rb +0 -23
  22. data/lib/arjdbc/jdbc.rb +0 -4
  23. data/lib/arjdbc/jdbc/adapter.rb +3 -1
  24. data/lib/arjdbc/jdbc/adapter_require.rb +3 -1
  25. data/lib/arjdbc/jdbc/base_ext.rb +3 -1
  26. data/lib/arjdbc/jdbc/callbacks.rb +2 -0
  27. data/lib/arjdbc/jdbc/column.rb +3 -5
  28. data/lib/arjdbc/jdbc/connection.rb +2 -0
  29. data/lib/arjdbc/jdbc/connection_methods.rb +2 -0
  30. data/lib/arjdbc/jdbc/error.rb +2 -0
  31. data/lib/arjdbc/jdbc/extension.rb +2 -0
  32. data/lib/arjdbc/jdbc/java.rb +3 -1
  33. data/lib/arjdbc/jdbc/railtie.rb +3 -1
  34. data/lib/arjdbc/jdbc/rake_tasks.rb +3 -1
  35. data/lib/arjdbc/jdbc/serialized_attributes_helper.rb +3 -1
  36. data/lib/arjdbc/jdbc/type_cast.rb +2 -0
  37. data/lib/arjdbc/jdbc/type_converter.rb +2 -0
  38. data/lib/arjdbc/mssql.rb +3 -1
  39. data/lib/arjdbc/mssql/adapter.rb +112 -46
  40. data/lib/arjdbc/mssql/column.rb +5 -1
  41. data/lib/arjdbc/mssql/connection_methods.rb +13 -2
  42. data/lib/arjdbc/mssql/database_limits.rb +2 -0
  43. data/lib/arjdbc/mssql/database_statements.rb +44 -6
  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.rb +2 -0
  55. data/lib/arjdbc/mssql/types/binary_types.rb +2 -0
  56. data/lib/arjdbc/mssql/types/date_and_time_types.rb +2 -0
  57. data/lib/arjdbc/mssql/types/deprecated_types.rb +2 -0
  58. data/lib/arjdbc/mssql/types/numeric_types.rb +2 -0
  59. data/lib/arjdbc/mssql/types/string_types.rb +2 -0
  60. data/lib/arjdbc/mssql/utils.rb +2 -0
  61. data/lib/arjdbc/mysql/adapter.rb +47 -18
  62. data/lib/arjdbc/mysql/connection_methods.rb +13 -7
  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 +11 -6
  69. data/lib/arjdbc/postgresql/connection_methods.rb +3 -1
  70. data/lib/arjdbc/postgresql/name.rb +2 -0
  71. data/lib/arjdbc/postgresql/oid_types.rb +3 -1
  72. data/lib/arjdbc/sqlite3/adapter.rb +188 -180
  73. data/lib/arjdbc/sqlite3/connection_methods.rb +16 -4
  74. data/lib/arjdbc/tasks/databases.rake +13 -10
  75. data/lib/arjdbc/tasks/mssql_database_tasks.rb +49 -5
  76. data/lib/arjdbc/util/quoted_cache.rb +3 -1
  77. data/lib/arjdbc/util/serialized_attributes.rb +3 -1
  78. data/lib/arjdbc/util/table_copier.rb +3 -1
  79. data/lib/arjdbc/version.rb +1 -1
  80. data/pom.xml +4 -4
  81. data/rakelib/01-tomcat.rake +2 -2
  82. data/rakelib/02-test.rake +0 -2
  83. data/rakelib/rails.rake +1 -1
  84. data/src/java/arjdbc/ArJdbcModule.java +5 -5
  85. data/src/java/arjdbc/jdbc/DriverWrapper.java +1 -9
  86. data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +468 -637
  87. data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +319 -38
  88. data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +13 -23
  89. data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +44 -31
  90. data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +94 -99
  91. data/src/java/arjdbc/util/DateTimeUtils.java +34 -12
  92. metadata +7 -17
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # This implements a basic decoder to work around ActiveRecord's dependence on the pg gem
2
4
  module ActiveRecord::ConnectionAdapters::PostgreSQL::OID
3
5
  class Array < ActiveModel::Type::Value
@@ -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
 
@@ -15,18 +17,18 @@ module ArJdbc
15
17
  end
16
18
 
17
19
  # Extracts the value from a PostgreSQL column default definition.
18
- def extract_value_from_default(default) # :nodoc:
20
+ def extract_value_from_default(default)
19
21
  case default
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/
@@ -41,10 +43,13 @@ module ArJdbc
41
43
  end
42
44
  end
43
45
 
44
- def extract_default_function(default_value, default) # :nodoc:
45
- default if ! default_value && ( %r{\w+\(.*\)|\(.*\)::\w+} === default )
46
+ def extract_default_function(default_value, default)
47
+ default if has_default_function?(default_value, default)
46
48
  end
47
49
 
50
+ def has_default_function?(default_value, default)
51
+ !default_value && %r{\w+\(.*\)|\(.*\)::\w+|CURRENT_DATE|CURRENT_TIMESTAMP}.match?(default)
52
+ end
48
53
  end
49
54
 
50
55
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  ArJdbc::ConnectionMethods.module_eval do
3
3
  def postgresql_connection(config)
4
+ config = config.deep_dup
4
5
  # NOTE: this isn't "really" necessary but Rails (in tests) assumes being able to :
5
6
  # ActiveRecord::Base.postgresql_connection ActiveRecord::Base.configurations['arunit'].merge(:insert_returning => false)
6
7
  # ... while using symbols by default but than configurations returning string keys ;(
@@ -16,7 +17,8 @@ ArJdbc::ConnectionMethods.module_eval do
16
17
  ::Jdbc::Postgres.load_driver(:require) if defined?(::Jdbc::Postgres.load_driver)
17
18
  rescue LoadError # assuming driver.jar is on the class-path
18
19
  end
19
- driver = config[:driver] ||= 'org.postgresql.Driver'
20
+ driver = (config[:driver] ||=
21
+ defined?(::Jdbc::Postgres.driver_name) ? ::Jdbc::Postgres.driver_name : 'org.postgresql.Driver')
20
22
 
21
23
  host = config[:host] ||= ( config[:hostaddr] || ENV['PGHOST'] || 'localhost' )
22
24
  port = config[:port] ||= ( ENV['PGPORT'] || 5432 )
@@ -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