activerecord-jdbc-alt-adapter 52.4.0-java → 61.0.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/.nvimlog +0 -0
  4. data/.travis.yml +63 -39
  5. data/Gemfile +11 -4
  6. data/README.md +55 -35
  7. data/Rakefile +1 -1
  8. data/Rakefile.jdbc +8 -1
  9. data/activerecord-jdbc-adapter.gemspec +6 -9
  10. data/activerecord-jdbc-alt-adapter.gemspec +9 -12
  11. data/lib/arel/visitors/postgresql_jdbc.rb +1 -1
  12. data/lib/arel/visitors/sqlserver.rb +49 -23
  13. data/lib/arjdbc/abstract/connection_management.rb +7 -0
  14. data/lib/arjdbc/abstract/core.rb +17 -23
  15. data/lib/arjdbc/abstract/database_statements.rb +30 -2
  16. data/lib/arjdbc/abstract/statement_cache.rb +2 -5
  17. data/lib/arjdbc/abstract/transaction_support.rb +22 -7
  18. data/lib/arjdbc/db2/column.rb +0 -39
  19. data/lib/arjdbc/derby/adapter.rb +1 -20
  20. data/lib/arjdbc/firebird/adapter.rb +0 -21
  21. data/lib/arjdbc/h2/adapter.rb +0 -15
  22. data/lib/arjdbc/hsqldb/adapter.rb +0 -14
  23. data/lib/arjdbc/informix/adapter.rb +0 -23
  24. data/lib/arjdbc/jdbc/adapter.rb +3 -1
  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.rb +3 -1
  40. data/lib/arjdbc/mssql/adapter.rb +114 -36
  41. data/lib/arjdbc/mssql/column.rb +19 -1
  42. data/lib/arjdbc/mssql/connection_methods.rb +10 -2
  43. data/lib/arjdbc/mssql/database_limits.rb +9 -0
  44. data/lib/arjdbc/mssql/database_statements.rb +44 -6
  45. data/lib/arjdbc/mssql/errors.rb +2 -0
  46. data/lib/arjdbc/mssql/explain_support.rb +3 -1
  47. data/lib/arjdbc/mssql/extensions/attribute_methods.rb +6 -2
  48. data/lib/arjdbc/mssql/extensions/calculations.rb +2 -0
  49. data/lib/arjdbc/mssql/quoting.rb +38 -0
  50. data/lib/arjdbc/mssql/schema_creation.rb +25 -3
  51. data/lib/arjdbc/mssql/schema_definitions.rb +10 -0
  52. data/lib/arjdbc/mssql/schema_dumper.rb +2 -0
  53. data/lib/arjdbc/mssql/schema_statements.rb +92 -22
  54. data/lib/arjdbc/mssql/transaction.rb +2 -0
  55. data/lib/arjdbc/mssql/types.rb +2 -0
  56. data/lib/arjdbc/mssql/types/binary_types.rb +2 -0
  57. data/lib/arjdbc/mssql/types/date_and_time_types.rb +2 -0
  58. data/lib/arjdbc/mssql/types/deprecated_types.rb +2 -0
  59. data/lib/arjdbc/mssql/types/numeric_types.rb +2 -0
  60. data/lib/arjdbc/mssql/types/string_types.rb +2 -0
  61. data/lib/arjdbc/mssql/utils.rb +2 -0
  62. data/lib/arjdbc/mysql/adapter.rb +59 -21
  63. data/lib/arjdbc/mysql/connection_methods.rb +6 -1
  64. data/lib/arjdbc/postgresql/adapter.rb +257 -219
  65. data/lib/arjdbc/postgresql/base/array_decoder.rb +2 -0
  66. data/lib/arjdbc/postgresql/base/array_encoder.rb +4 -2
  67. data/lib/arjdbc/postgresql/base/array_parser.rb +4 -2
  68. data/lib/arjdbc/postgresql/base/pgconn.rb +2 -0
  69. data/lib/arjdbc/postgresql/column.rb +6 -4
  70. data/lib/arjdbc/postgresql/connection_methods.rb +1 -0
  71. data/lib/arjdbc/postgresql/name.rb +2 -0
  72. data/lib/arjdbc/postgresql/oid_types.rb +7 -4
  73. data/lib/arjdbc/sqlite3/adapter.rb +266 -221
  74. data/lib/arjdbc/sqlite3/connection_methods.rb +26 -4
  75. data/lib/arjdbc/tasks/databases.rake +21 -13
  76. data/lib/arjdbc/tasks/mssql_database_tasks.rb +126 -25
  77. data/lib/arjdbc/util/quoted_cache.rb +3 -1
  78. data/lib/arjdbc/util/serialized_attributes.rb +3 -1
  79. data/lib/arjdbc/util/table_copier.rb +3 -1
  80. data/lib/arjdbc/version.rb +3 -1
  81. data/pom.xml +4 -4
  82. data/rakelib/01-tomcat.rake +2 -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 +549 -691
  87. data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +88 -0
  88. data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +13 -23
  89. data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +125 -53
  90. data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +97 -103
  91. data/src/java/arjdbc/util/DateTimeUtils.java +12 -4
  92. metadata +10 -18
@@ -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
 
@@ -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 && default && %r{\w+\(.*\)|\(.*\)::\w+|CURRENT_DATE|CURRENT_TIMESTAMP}.match?(default)
50
52
  end
51
53
  end
52
54
 
@@ -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 ;(
@@ -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
@@ -143,7 +145,7 @@ module ArJdbc
143
145
  m.register_type 'uuid', OID::Uuid.new
144
146
  m.register_type 'xml', OID::Xml.new
145
147
  m.register_type 'tsvector', OID::SpecializedString.new(:tsvector)
146
- m.register_type 'macaddr', OID::SpecializedString.new(:macaddr)
148
+ m.register_type 'macaddr', OID::Macaddr.new
147
149
  m.register_type 'citext', OID::SpecializedString.new(:citext)
148
150
  m.register_type 'ltree', OID::SpecializedString.new(:ltree)
149
151
  m.register_type 'line', OID::SpecializedString.new(:line)
@@ -153,9 +155,9 @@ module ArJdbc
153
155
  m.register_type 'polygon', OID::SpecializedString.new(:polygon)
154
156
  m.register_type 'circle', OID::SpecializedString.new(:circle)
155
157
 
156
- m.register_type 'interval' do |_, _, sql_type|
158
+ m.register_type 'interval' do |*args, sql_type|
157
159
  precision = extract_precision(sql_type)
158
- OID::SpecializedString.new(:interval, precision: precision)
160
+ OID::Interval.new(precision: precision)
159
161
  end
160
162
 
161
163
  register_class_with_precision m, 'time', Type::Time
@@ -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
@@ -242,6 +244,7 @@ module ArJdbc
242
244
  ActiveRecord::Type.register(:enum, OID::Enum, adapter: :postgresql)
243
245
  ActiveRecord::Type.register(:hstore, OID::Hstore, adapter: :postgresql)
244
246
  ActiveRecord::Type.register(:inet, OID::Inet, adapter: :postgresql)
247
+ ActiveRecord::Type.register(:interval, OID::Interval, adapter: :postgresql)
245
248
  ActiveRecord::Type.register(:json, Type::Json, adapter: :postgresql)
246
249
  ActiveRecord::Type.register(:jsonb, OID::Jsonb, adapter: :postgresql)
247
250
  ActiveRecord::Type.register(:money, OID::Money, adapter: :postgresql)
@@ -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"
@@ -14,6 +16,33 @@ require "active_record/connection_adapters/sqlite3/schema_dumper"
14
16
  require "active_record/connection_adapters/sqlite3/schema_statements"
15
17
  require "active_support/core_ext/class/attribute"
16
18
 
19
+ module SQLite3
20
+ module Constants
21
+ module Open
22
+ READONLY = 0x00000001
23
+ READWRITE = 0x00000002
24
+ CREATE = 0x00000004
25
+ DELETEONCLOSE = 0x00000008
26
+ EXCLUSIVE = 0x00000010
27
+ AUTOPROXY = 0x00000020
28
+ URI = 0x00000040
29
+ MEMORY = 0x00000080
30
+ MAIN_DB = 0x00000100
31
+ TEMP_DB = 0x00000200
32
+ TRANSIENT_DB = 0x00000400
33
+ MAIN_JOURNAL = 0x00000800
34
+ TEMP_JOURNAL = 0x00001000
35
+ SUBJOURNAL = 0x00002000
36
+ MASTER_JOURNAL = 0x00004000
37
+ NOMUTEX = 0x00008000
38
+ FULLMUTEX = 0x00010000
39
+ SHAREDCACHE = 0x00020000
40
+ PRIVATECACHE = 0x00040000
41
+ WAL = 0x00080000
42
+ end
43
+ end
44
+ end
45
+
17
46
  module ArJdbc
18
47
  # All the code in this module is a copy of ConnectionAdapters::SQLite3Adapter from active_record 5.
19
48
  # The constants at the front of this file are to allow the rest of the file to remain with no modifications
@@ -30,7 +59,7 @@ module ArJdbc
30
59
  SchemaCreation = ConnectionAdapters::SQLite3::SchemaCreation
31
60
  SQLite3Adapter = ConnectionAdapters::AbstractAdapter
32
61
 
33
- ADAPTER_NAME = 'SQLite'.freeze
62
+ ADAPTER_NAME = 'SQLite'
34
63
 
35
64
  # DIFFERENCE: FQN
36
65
  include ::ActiveRecord::ConnectionAdapters::SQLite3::Quoting
@@ -54,20 +83,8 @@ module ArJdbc
54
83
  # DIFFERENCE: class_attribute in original adapter is moved down to our section which is a class
55
84
  # since we cannot define it here in the module (original source this is a class).
56
85
 
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
86
  def initialize(connection, logger, connection_options, config)
66
87
  super(connection, logger, config)
67
-
68
- @active = true
69
- @statements = StatementPool.new(self.class.type_cast_config_to_integer(config[:statement_limit]))
70
-
71
88
  configure_connection
72
89
  end
73
90
 
@@ -79,16 +96,28 @@ module ArJdbc
79
96
  true
80
97
  end
81
98
 
99
+ def supports_transaction_isolation?
100
+ true
101
+ end
102
+
82
103
  def supports_partial_index?
83
- sqlite_version >= "3.8.0"
104
+ database_version >= "3.9.0"
105
+ end
106
+
107
+ def supports_expression_index?
108
+ database_version >= "3.9.0"
84
109
  end
85
110
 
86
111
  def requires_reloading?
87
112
  true
88
113
  end
89
114
 
90
- def supports_foreign_keys_in_create?
91
- sqlite_version >= "3.6.19"
115
+ def supports_foreign_keys?
116
+ true
117
+ end
118
+
119
+ def supports_check_constraints?
120
+ true
92
121
  end
93
122
 
94
123
  def supports_views?
@@ -99,38 +128,27 @@ module ArJdbc
99
128
  true
100
129
  end
101
130
 
102
- def supports_multi_insert?
103
- sqlite_version >= "3.7.11"
131
+ def supports_json?
132
+ true
104
133
  end
105
134
 
106
- def active?
107
- @active
135
+ def supports_common_table_expressions?
136
+ database_version >= "3.8.3"
108
137
  end
109
138
 
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
139
+ def supports_insert_on_conflict?
140
+ database_version >= "3.24.0"
116
141
  end
142
+ alias supports_insert_on_duplicate_skip? supports_insert_on_conflict?
143
+ alias supports_insert_on_duplicate_update? supports_insert_on_conflict?
144
+ alias supports_insert_conflict_target? supports_insert_on_conflict?
117
145
 
118
- # Clears the prepared statements cache.
119
- def clear_cache!
120
- @statements.clear
121
- end
146
+ # DIFFERENCE: active?, reconnect!, disconnect! handles by arjdbc core
122
147
 
123
148
  def supports_index_sort_order?
124
149
  true
125
150
  end
126
151
 
127
- # Returns 62. SQLite supports index names up to 64
128
- # characters. The rest is used by Rails internally to perform
129
- # temporary rename operations
130
- def allowed_index_name_length
131
- index_name_length - 2
132
- end
133
-
134
152
  def native_database_types #:nodoc:
135
153
  NATIVE_DATABASE_TYPES
136
154
  end
@@ -144,90 +162,68 @@ module ArJdbc
144
162
  true
145
163
  end
146
164
 
165
+ def supports_lazy_transactions?
166
+ true
167
+ end
168
+
147
169
  # REFERENTIAL INTEGRITY ====================================
148
170
 
149
171
  def disable_referential_integrity # :nodoc:
150
- old = query_value("PRAGMA foreign_keys")
172
+ old_foreign_keys = query_value("PRAGMA foreign_keys")
173
+ old_defer_foreign_keys = query_value("PRAGMA defer_foreign_keys")
151
174
 
152
175
  begin
176
+ execute("PRAGMA defer_foreign_keys = ON")
153
177
  execute("PRAGMA foreign_keys = OFF")
154
178
  yield
155
179
  ensure
156
- execute("PRAGMA foreign_keys = #{old}")
180
+ execute("PRAGMA defer_foreign_keys = #{old_defer_foreign_keys}")
181
+ execute("PRAGMA foreign_keys = #{old_foreign_keys}")
157
182
  end
158
183
  end
159
-
184
+
160
185
  #--
161
186
  # DATABASE STATEMENTS ======================================
162
187
  #++
163
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
+
164
198
  def explain(arel, binds = [])
165
199
  sql = "EXPLAIN QUERY PLAN #{to_sql(arel, binds)}"
166
200
  # DIFFERENCE: FQN
167
201
  ::ActiveRecord::ConnectionAdapters::SQLite3::ExplainPrettyPrinter.new.pp(exec_query(sql, "EXPLAIN", []))
168
202
  end
169
203
 
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
204
+ # DIFFERENCE: implemented in ArJdbc::Abstract::DatabaseStatements
205
+ #def exec_query(sql, name = nil, binds = [], prepare: false)
202
206
 
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
207
+ # DIFFERENCE: implemented in ArJdbc::Abstract::DatabaseStatements
208
+ #def exec_delete(sql, name = "SQL", binds = [])
208
209
 
209
210
  def last_inserted_id(result)
210
211
  @connection.last_insert_row_id
211
212
  end
212
213
 
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
214
+ # DIFFERENCE: implemented in ArJdbc::Abstract::DatabaseStatements
215
+ #def execute(sql, name = nil) #:nodoc:
220
216
 
221
217
  def begin_db_transaction #:nodoc:
222
- log("begin transaction",nil) { @connection.transaction }
218
+ log("begin transaction", 'TRANSACTION') { @connection.transaction }
223
219
  end
224
220
 
225
221
  def commit_db_transaction #:nodoc:
226
- log("commit transaction",nil) { @connection.commit }
222
+ log("commit transaction", 'TRANSACTION') { @connection.commit }
227
223
  end
228
224
 
229
225
  def exec_rollback_db_transaction #:nodoc:
230
- log("rollback transaction",nil) { @connection.rollback }
226
+ log("rollback transaction", 'TRANSACTION') { @connection.rollback }
231
227
  end
232
228
 
233
229
  # SCHEMA STATEMENTS ========================================
@@ -237,8 +233,11 @@ module ArJdbc
237
233
  pks.sort_by { |f| f["pk"] }.map { |f| f["name"] }
238
234
  end
239
235
 
240
- def remove_index(table_name, options = {}) #:nodoc:
241
- index_name = index_name_for_remove(table_name, options)
236
+ def remove_index(table_name, column_name = nil, **options) # :nodoc:
237
+ return if options[:if_exists] && !index_exists?(table_name, column_name, **options)
238
+
239
+ index_name = index_name_for_remove(table_name, column_name, options)
240
+
242
241
  exec_query "DROP INDEX #{quote_column_name(index_name)}"
243
242
  end
244
243
 
@@ -247,30 +246,28 @@ module ArJdbc
247
246
  # Example:
248
247
  # rename_table('octopuses', 'octopi')
249
248
  def rename_table(table_name, new_name)
249
+ schema_cache.clear_data_source_cache!(table_name.to_s)
250
+ schema_cache.clear_data_source_cache!(new_name.to_s)
250
251
  exec_query "ALTER TABLE #{quote_table_name(table_name)} RENAME TO #{quote_table_name(new_name)}"
251
252
  rename_table_indexes(table_name, new_name)
252
253
  end
253
254
 
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
- def add_column(table_name, column_name, type, options = {}) #:nodoc:
255
+ def add_column(table_name, column_name, type, **options) #:nodoc:
262
256
  if invalid_alter_table_type?(type, options)
263
257
  alter_table(table_name) do |definition|
264
- definition.column(column_name, type, options)
258
+ definition.column(column_name, type, **options)
265
259
  end
266
260
  else
267
261
  super
268
262
  end
269
263
  end
270
264
 
271
- def remove_column(table_name, column_name, type = nil, options = {}) #:nodoc:
265
+ def remove_column(table_name, column_name, type = nil, **options) #:nodoc:
272
266
  alter_table(table_name) do |definition|
273
267
  definition.remove_column column_name
268
+ definition.foreign_keys.delete_if do |_, fk_options|
269
+ fk_options[:column] == column_name.to_s
270
+ end
274
271
  end
275
272
  end
276
273
 
@@ -291,16 +288,11 @@ module ArJdbc
291
288
  end
292
289
  end
293
290
 
294
- def change_column(table_name, column_name, type, options = {}) #:nodoc:
291
+ def change_column(table_name, column_name, type, **options) #:nodoc:
295
292
  alter_table(table_name) do |definition|
296
293
  definition[column_name].instance_eval do
297
294
  self.type = type
298
- self.limit = options[:limit] if options.include?(:limit)
299
- self.default = options[:default] if options.include?(:default)
300
- self.null = options[:null] if options.include?(:null)
301
- self.precision = options[:precision] if options.include?(:precision)
302
- self.scale = options[:scale] if options.include?(:scale)
303
- self.collation = options[:collation] if options.include?(:collation)
295
+ self.options.merge!(options)
304
296
  end
305
297
  end
306
298
  end
@@ -330,14 +322,6 @@ module ArJdbc
330
322
  end
331
323
  end
332
324
 
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
325
  def insert_fixtures_set(fixture_set, tables_to_delete = [])
342
326
  disable_referential_integrity do
343
327
  transaction(requires_new: true) do
@@ -349,11 +333,44 @@ module ArJdbc
349
333
  end
350
334
  end
351
335
  end
352
-
336
+
337
+ def build_insert_sql(insert) # :nodoc:
338
+ sql = +"INSERT #{insert.into} #{insert.values_list}"
339
+
340
+ if insert.skip_duplicates?
341
+ sql << " ON CONFLICT #{insert.conflict_target} DO NOTHING"
342
+ elsif insert.update_duplicates?
343
+ 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(",")
346
+ end
347
+
348
+ sql
349
+ end
350
+
351
+ def shared_cache?
352
+ config[:properties] && config[:properties][:shared_cache] == true
353
+ end
354
+
355
+ 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)}"
361
+ end
362
+
363
+ def check_version
364
+ if database_version < "3.8.0"
365
+ raise "Your version of SQLite (#{database_version}) is too old. Active Record supports SQLite >= 3.8."
366
+ end
367
+ end
368
+
353
369
  private
354
- def initialize_type_map(m = type_map)
355
- super
356
- register_class_with_limit m, %r(int)i, SQLite3Integer
370
+ # See https://www.sqlite.org/limits.html,
371
+ # the default value is 999 when not configured.
372
+ def bind_params_length
373
+ 999
357
374
  end
358
375
 
359
376
  def table_structure(table_name)
@@ -366,17 +383,40 @@ module ArJdbc
366
383
  # See: https://www.sqlite.org/lang_altertable.html
367
384
  # SQLite has an additional restriction on the ALTER TABLE statement
368
385
  def invalid_alter_table_type?(type, options)
369
- type.to_sym == :primary_key || options[:primary_key]
386
+ type.to_sym == :primary_key || options[:primary_key] ||
387
+ options[:null] == false && options[:default].nil?
370
388
  end
371
389
 
372
- def alter_table(table_name, options = {}) #:nodoc:
390
+ def alter_table(
391
+ table_name,
392
+ foreign_keys = foreign_keys(table_name),
393
+ check_constraints = check_constraints(table_name),
394
+ **options
395
+ )
373
396
  altered_table_name = "a#{table_name}"
374
- caller = lambda { |definition| yield definition if block_given? }
397
+
398
+ caller = lambda do |definition|
399
+ rename = options[:rename] || {}
400
+ foreign_keys.each do |fk|
401
+ if column = rename[fk.options[:column]]
402
+ fk.options[:column] = column
403
+ end
404
+ to_table = strip_table_name_prefix_and_suffix(fk.to_table)
405
+ definition.foreign_key(to_table, **fk.options)
406
+ end
407
+
408
+ check_constraints.each do |chk|
409
+ definition.check_constraint(chk.expression, **chk.options)
410
+ end
411
+
412
+ yield definition if block_given?
413
+ end
375
414
 
376
415
  transaction do
377
- move_table(table_name, altered_table_name,
378
- options.merge(temporary: true))
379
- move_table(altered_table_name, table_name, &caller)
416
+ disable_referential_integrity do
417
+ move_table(table_name, altered_table_name, options.merge(temporary: true))
418
+ move_table(altered_table_name, table_name, &caller)
419
+ end
380
420
  end
381
421
  end
382
422
 
@@ -388,30 +428,32 @@ module ArJdbc
388
428
  def copy_table(from, to, options = {})
389
429
  from_primary_key = primary_key(from)
390
430
  options[:id] = false
391
- create_table(to, options) do |definition|
431
+ create_table(to, **options) do |definition|
392
432
  @definition = definition
393
433
  if from_primary_key.is_a?(Array)
394
434
  @definition.primary_keys from_primary_key
395
435
  end
436
+
396
437
  columns(from).each do |column|
397
438
  column_name = options[:rename] ?
398
- (options[:rename][column.name] ||
399
- options[:rename][column.name.to_sym] ||
400
- column.name) : column.name
439
+ (options[:rename][column.name] ||
440
+ options[:rename][column.name.to_sym] ||
441
+ column.name) : column.name
401
442
 
402
443
  @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
444
+ limit: column.limit, default: column.default,
445
+ precision: column.precision, scale: column.scale,
446
+ null: column.null, collation: column.collation,
447
+ primary_key: column_name == from_primary_key
407
448
  )
408
449
  end
450
+
409
451
  yield @definition if block_given?
410
452
  end
411
453
  copy_table_indexes(from, to, options[:rename] || {})
412
454
  copy_table_contents(from, to,
413
- @definition.columns.map(&:name),
414
- options[:rename] || {})
455
+ @definition.columns.map(&:name),
456
+ options[:rename] || {})
415
457
  end
416
458
 
417
459
  def copy_table_indexes(from, to, rename = {})
@@ -419,24 +461,27 @@ module ArJdbc
419
461
  name = index.name
420
462
  # indexes sqlite creates for internal use start with `sqlite_` and
421
463
  # don't need to be copied
422
- next if name.starts_with?("sqlite_")
464
+ next if name.start_with?("sqlite_")
423
465
  if to == "a#{from}"
424
466
  name = "t#{name}"
425
467
  elsif from == "a#{to}"
426
468
  name = name[1..-1]
427
469
  end
428
470
 
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)
471
+ columns = index.columns
472
+ if columns.is_a?(Array)
473
+ to_column_names = columns(to).map(&:name)
474
+ columns = columns.map { |c| rename[c] || c }.select do |column|
475
+ to_column_names.include?(column)
476
+ end
432
477
  end
433
478
 
434
479
  unless columns.empty?
435
480
  # index name can't be the same
436
- opts = { name: name.gsub(/(^|_)(#{from})_/, "\\1#{to}_"), internal: true }
437
- opts[:unique] = true if index.unique
438
- opts[:where] = index.where if index.where
439
- add_index(to, columns, opts)
481
+ options = { name: name.gsub(/(^|_)(#{from})_/, "\\1#{to}_"), internal: true }
482
+ options[:unique] = true if index.unique
483
+ options[:where] = index.where if index.where
484
+ add_index(to, columns, **options)
440
485
  end
441
486
  end
442
487
  end
@@ -454,27 +499,23 @@ module ArJdbc
454
499
  SELECT #{quoted_from_columns} FROM #{quote_table_name(from)}")
455
500
  end
456
501
 
457
- def sqlite_version
458
- @sqlite_version ||= SQLite3Adapter::Version.new(select_value("select sqlite_version(*)"))
459
- end
460
-
461
- def translate_exception(exception, message)
502
+ def translate_exception(exception, message:, sql:, binds:)
462
503
  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
504
+ # SQLite 3.8.2 returns a newly formatted error message:
505
+ # UNIQUE constraint failed: *table_name*.*column_name*
506
+ # Older versions of SQLite return:
507
+ # column *column_name* is not unique
508
+ when /column(s)? .* (is|are) not unique/, /UNIQUE constraint failed: .*/
509
+ # DIFFERENCE: FQN
510
+ ::ActiveRecord::RecordNotUnique.new(message, sql: sql, binds: binds)
511
+ when /.* may not be NULL/, /NOT NULL constraint failed: .*/
512
+ # DIFFERENCE: FQN
513
+ ::ActiveRecord::NotNullViolation.new(message, sql: sql, binds: binds)
514
+ when /FOREIGN KEY constraint failed/i
515
+ # DIFFERENCE: FQN
516
+ ::ActiveRecord::InvalidForeignKey.new(message, sql: sql, binds: binds)
517
+ else
518
+ super
478
519
  end
479
520
  end
480
521
 
@@ -482,11 +523,11 @@ module ArJdbc
482
523
 
483
524
  def table_structure_with_collation(table_name, basic_structure)
484
525
  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)}
526
+ sql = <<~SQL
527
+ SELECT sql FROM
528
+ (SELECT * FROM sqlite_master UNION ALL
529
+ SELECT * FROM sqlite_temp_master)
530
+ WHERE type = 'table' AND name = #{quote(table_name)}
490
531
  SQL
491
532
 
492
533
  # Result will have following sample string
@@ -495,9 +536,9 @@ module ArJdbc
495
536
  result = exec_query(sql, "SCHEMA").first
496
537
 
497
538
  if result
498
- # Splitting with left parentheses and picking up last will return all
539
+ # Splitting with left parentheses and discarding the first part will return all
499
540
  # columns separated with comma(,).
500
- columns_string = result["sql"].split("(").last
541
+ columns_string = result["sql"].split("(", 2).last
501
542
 
502
543
  columns_string.split(",").each do |column_string|
503
544
  # This regex will match the column name and collation type and will save
@@ -505,7 +546,7 @@ module ArJdbc
505
546
  collation_hash[$1] = $2 if COLLATE_REGEX =~ column_string
506
547
  end
507
548
 
508
- basic_structure.map! do |column|
549
+ basic_structure.map do |column|
509
550
  column_name = column["name"]
510
551
 
511
552
  if collation_hash.has_key? column_name
@@ -515,7 +556,7 @@ module ArJdbc
515
556
  column
516
557
  end
517
558
  else
518
- basic_structure.to_hash
559
+ basic_structure.to_a
519
560
  end
520
561
  end
521
562
 
@@ -527,18 +568,6 @@ module ArJdbc
527
568
  execute("PRAGMA foreign_keys = ON", "SCHEMA")
528
569
  end
529
570
 
530
- # DIFFERENCE: FQN
531
- class SQLite3Integer < ::ActiveRecord::Type::Integer # :nodoc:
532
- private
533
- def _limit
534
- # INTEGER storage class can be stored 8 bytes value.
535
- # See https://www.sqlite.org/datatype3.html#storage_classes_and_datatypes
536
- limit || 8
537
- end
538
- end
539
-
540
- # DIFFERENCE: FQN
541
- ::ActiveRecord::Type.register(:integer, SQLite3Integer, adapter: :sqlite3)
542
571
  end
543
572
  # DIFFERENCE: A registration here is moved down to concrete class so we are not registering part of an adapter.
544
573
  end
@@ -597,24 +626,6 @@ module ActiveRecord::ConnectionAdapters
597
626
 
598
627
  private
599
628
 
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
629
  # @override {ActiveRecord::ConnectionAdapters::Column#extract_limit}
619
630
  def extract_limit(sql_type)
620
631
  return nil if sql_type =~ /^(real)\(\d+/i
@@ -646,37 +657,42 @@ module ActiveRecord::ConnectionAdapters
646
657
  class SQLite3Adapter < AbstractAdapter
647
658
  include ArJdbc::Abstract::Core
648
659
  include ArJdbc::SQLite3
660
+ include ArJdbc::Abstract::ConnectionManagement
649
661
  include ArJdbc::Abstract::DatabaseStatements
650
662
  include ArJdbc::Abstract::StatementCache
651
663
  include ArJdbc::Abstract::TransactionSupport
652
664
 
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
665
+ def self.represent_boolean_as_integer=(value) # :nodoc:
666
+ if value == false
667
+ raise "`.represent_boolean_as_integer=` is now always true, so make sure your application can work with it and remove this settings."
668
+ end
669
+
670
+ ActiveSupport::Deprecation.warn(
671
+ "`.represent_boolean_as_integer=` is now always true, so setting this is deprecated and will be removed in Rails 6.1."
672
+ )
673
+ end
674
+
675
+ def self.database_exists?(config)
676
+ config = config.symbolize_keys
677
+ if config[:database] == ":memory:"
678
+ return true
679
+ else
680
+ database_file = defined?(Rails.root) ? File.expand_path(config[:database], Rails.root) : config[:database]
681
+ File.exist?(database_file)
682
+ end
683
+ end
684
+
671
685
 
672
686
  def supports_transaction_isolation?
673
687
  false
674
688
  end
675
689
 
676
690
  def begin_isolated_db_transaction(isolation)
677
- raise ActiveRecord::TransactionIsolationError, 'adapter does not support setting transaction isolation'
691
+ raise ActiveRecord::TransactionIsolationError, "SQLite3 only supports the `read_uncommitted` transaction isolation level" if isolation != :read_uncommitted
692
+ raise StandardError, "You need to enable the shared-cache mode in SQLite mode before attempting to change the transaction isolation level" unless shared_cache?
693
+ super
678
694
  end
679
-
695
+
680
696
  # SQLite driver doesn't support all types of insert statements with executeUpdate so
681
697
  # make it act like a regular query and the ids will be returned from #last_inserted_id
682
698
  # example: INSERT INTO "aircraft" DEFAULT VALUES
@@ -699,5 +715,34 @@ module ActiveRecord::ConnectionAdapters
699
715
 
700
716
  # 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
717
  # ActiveSupport.run_load_hooks(:active_record_sqlite3adapter, SQLite3Adapter)
718
+
719
+ private
720
+
721
+ # because the JDBC driver doesn't like multiple SQL statements in one JDBC statement
722
+ def combine_multi_statements(total_sql)
723
+ if total_sql.length == 1
724
+ total_sql.first
725
+ else
726
+ total_sql
727
+ end
728
+ end
729
+
730
+ def initialize_type_map(m = type_map)
731
+ super
732
+ register_class_with_limit m, %r(int)i, SQLite3Integer
733
+ end
734
+
735
+ # DIFFERENCE: FQN
736
+ class SQLite3Integer < ::ActiveRecord::Type::Integer # :nodoc:
737
+ private
738
+ def _limit
739
+ # INTEGER storage class can be stored 8 bytes value.
740
+ # See https://www.sqlite.org/datatype3.html#storage_classes_and_datatypes
741
+ limit || 8
742
+ end
743
+ end
744
+
745
+ # DIFFERENCE: FQN
746
+ ::ActiveRecord::Type.register(:integer, SQLite3Integer, adapter: :sqlite3)
702
747
  end
703
748
  end