activerecord 6.1.6 → 7.0.4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (243) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1314 -975
  3. data/README.rdoc +1 -1
  4. data/lib/active_record/aggregations.rb +1 -1
  5. data/lib/active_record/association_relation.rb +0 -10
  6. data/lib/active_record/associations/association.rb +33 -17
  7. data/lib/active_record/associations/association_scope.rb +1 -3
  8. data/lib/active_record/associations/belongs_to_association.rb +15 -4
  9. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
  10. data/lib/active_record/associations/builder/association.rb +8 -2
  11. data/lib/active_record/associations/builder/belongs_to.rb +19 -6
  12. data/lib/active_record/associations/builder/collection_association.rb +10 -3
  13. data/lib/active_record/associations/builder/has_many.rb +3 -2
  14. data/lib/active_record/associations/builder/has_one.rb +2 -1
  15. data/lib/active_record/associations/builder/singular_association.rb +2 -2
  16. data/lib/active_record/associations/collection_association.rb +19 -21
  17. data/lib/active_record/associations/collection_proxy.rb +10 -5
  18. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  19. data/lib/active_record/associations/has_many_association.rb +8 -5
  20. data/lib/active_record/associations/has_many_through_association.rb +2 -1
  21. data/lib/active_record/associations/has_one_association.rb +10 -7
  22. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  23. data/lib/active_record/associations/join_dependency.rb +23 -15
  24. data/lib/active_record/associations/preloader/association.rb +186 -52
  25. data/lib/active_record/associations/preloader/batch.rb +48 -0
  26. data/lib/active_record/associations/preloader/branch.rb +147 -0
  27. data/lib/active_record/associations/preloader/through_association.rb +49 -13
  28. data/lib/active_record/associations/preloader.rb +39 -113
  29. data/lib/active_record/associations/singular_association.rb +8 -2
  30. data/lib/active_record/associations/through_association.rb +3 -3
  31. data/lib/active_record/associations.rb +124 -95
  32. data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
  33. data/lib/active_record/attribute_assignment.rb +1 -1
  34. data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
  35. data/lib/active_record/attribute_methods/dirty.rb +49 -16
  36. data/lib/active_record/attribute_methods/primary_key.rb +2 -2
  37. data/lib/active_record/attribute_methods/query.rb +2 -2
  38. data/lib/active_record/attribute_methods/read.rb +7 -5
  39. data/lib/active_record/attribute_methods/serialization.rb +57 -19
  40. data/lib/active_record/attribute_methods/time_zone_conversion.rb +8 -3
  41. data/lib/active_record/attribute_methods/write.rb +7 -10
  42. data/lib/active_record/attribute_methods.rb +14 -15
  43. data/lib/active_record/attributes.rb +24 -35
  44. data/lib/active_record/autosave_association.rb +8 -23
  45. data/lib/active_record/base.rb +19 -1
  46. data/lib/active_record/callbacks.rb +2 -2
  47. data/lib/active_record/coders/yaml_column.rb +10 -2
  48. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +292 -0
  49. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +209 -0
  50. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +76 -0
  51. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +47 -561
  52. data/lib/active_record/connection_adapters/abstract/database_limits.rb +0 -17
  53. data/lib/active_record/connection_adapters/abstract/database_statements.rb +46 -22
  54. data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -12
  55. data/lib/active_record/connection_adapters/abstract/quoting.rb +42 -72
  56. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -17
  57. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +38 -13
  58. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
  59. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +80 -24
  60. data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -22
  61. data/lib/active_record/connection_adapters/abstract_adapter.rb +149 -74
  62. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +105 -81
  63. data/lib/active_record/connection_adapters/column.rb +4 -0
  64. data/lib/active_record/connection_adapters/mysql/database_statements.rb +36 -24
  65. data/lib/active_record/connection_adapters/mysql/quoting.rb +37 -21
  66. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +7 -1
  67. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +20 -1
  68. data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
  69. data/lib/active_record/connection_adapters/pool_config.rb +7 -7
  70. data/lib/active_record/connection_adapters/postgresql/column.rb +17 -1
  71. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +19 -12
  72. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  73. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  74. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  75. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
  76. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  77. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  78. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  79. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  80. data/lib/active_record/connection_adapters/postgresql/quoting.rb +51 -51
  81. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +34 -0
  82. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +21 -1
  83. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +22 -1
  84. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +25 -0
  85. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +37 -19
  86. data/lib/active_record/connection_adapters/postgresql_adapter.rb +208 -107
  87. data/lib/active_record/connection_adapters/schema_cache.rb +39 -38
  88. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +25 -19
  89. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +28 -16
  90. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +17 -15
  91. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +96 -32
  92. data/lib/active_record/connection_adapters.rb +6 -5
  93. data/lib/active_record/connection_handling.rb +49 -55
  94. data/lib/active_record/core.rb +124 -134
  95. data/lib/active_record/database_configurations/connection_url_resolver.rb +2 -1
  96. data/lib/active_record/database_configurations/database_config.rb +12 -9
  97. data/lib/active_record/database_configurations/hash_config.rb +63 -5
  98. data/lib/active_record/database_configurations/url_config.rb +2 -2
  99. data/lib/active_record/database_configurations.rb +15 -32
  100. data/lib/active_record/delegated_type.rb +53 -12
  101. data/lib/active_record/destroy_association_async_job.rb +1 -1
  102. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  103. data/lib/active_record/dynamic_matchers.rb +1 -1
  104. data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
  105. data/lib/active_record/encryption/cipher.rb +53 -0
  106. data/lib/active_record/encryption/config.rb +44 -0
  107. data/lib/active_record/encryption/configurable.rb +67 -0
  108. data/lib/active_record/encryption/context.rb +35 -0
  109. data/lib/active_record/encryption/contexts.rb +72 -0
  110. data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
  111. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  112. data/lib/active_record/encryption/encryptable_record.rb +206 -0
  113. data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
  114. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  115. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  116. data/lib/active_record/encryption/encryptor.rb +155 -0
  117. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  118. data/lib/active_record/encryption/errors.rb +15 -0
  119. data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
  120. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  121. data/lib/active_record/encryption/key.rb +28 -0
  122. data/lib/active_record/encryption/key_generator.rb +42 -0
  123. data/lib/active_record/encryption/key_provider.rb +46 -0
  124. data/lib/active_record/encryption/message.rb +33 -0
  125. data/lib/active_record/encryption/message_serializer.rb +90 -0
  126. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  127. data/lib/active_record/encryption/properties.rb +76 -0
  128. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  129. data/lib/active_record/encryption/scheme.rb +99 -0
  130. data/lib/active_record/encryption.rb +55 -0
  131. data/lib/active_record/enum.rb +50 -43
  132. data/lib/active_record/errors.rb +67 -4
  133. data/lib/active_record/explain_registry.rb +11 -6
  134. data/lib/active_record/fixture_set/file.rb +15 -1
  135. data/lib/active_record/fixture_set/table_row.rb +41 -6
  136. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  137. data/lib/active_record/fixtures.rb +20 -23
  138. data/lib/active_record/future_result.rb +139 -0
  139. data/lib/active_record/gem_version.rb +4 -4
  140. data/lib/active_record/inheritance.rb +55 -17
  141. data/lib/active_record/insert_all.rb +80 -14
  142. data/lib/active_record/integration.rb +4 -3
  143. data/lib/active_record/internal_metadata.rb +1 -5
  144. data/lib/active_record/legacy_yaml_adapter.rb +2 -39
  145. data/lib/active_record/locking/optimistic.rb +10 -9
  146. data/lib/active_record/locking/pessimistic.rb +10 -4
  147. data/lib/active_record/log_subscriber.rb +23 -7
  148. data/lib/active_record/middleware/database_selector/resolver.rb +6 -10
  149. data/lib/active_record/middleware/database_selector.rb +18 -6
  150. data/lib/active_record/middleware/shard_selector.rb +60 -0
  151. data/lib/active_record/migration/command_recorder.rb +7 -7
  152. data/lib/active_record/migration/compatibility.rb +84 -2
  153. data/lib/active_record/migration/join_table.rb +1 -1
  154. data/lib/active_record/migration.rb +114 -83
  155. data/lib/active_record/model_schema.rb +58 -59
  156. data/lib/active_record/nested_attributes.rb +13 -12
  157. data/lib/active_record/no_touching.rb +3 -3
  158. data/lib/active_record/null_relation.rb +2 -6
  159. data/lib/active_record/persistence.rb +228 -60
  160. data/lib/active_record/query_cache.rb +2 -2
  161. data/lib/active_record/query_logs.rb +138 -0
  162. data/lib/active_record/querying.rb +16 -6
  163. data/lib/active_record/railtie.rb +136 -22
  164. data/lib/active_record/railties/controller_runtime.rb +1 -1
  165. data/lib/active_record/railties/databases.rake +78 -136
  166. data/lib/active_record/readonly_attributes.rb +11 -0
  167. data/lib/active_record/reflection.rb +73 -50
  168. data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
  169. data/lib/active_record/relation/batches.rb +6 -6
  170. data/lib/active_record/relation/calculations.rb +43 -38
  171. data/lib/active_record/relation/delegation.rb +7 -7
  172. data/lib/active_record/relation/finder_methods.rb +31 -35
  173. data/lib/active_record/relation/merger.rb +20 -13
  174. data/lib/active_record/relation/predicate_builder.rb +1 -6
  175. data/lib/active_record/relation/query_attribute.rb +5 -11
  176. data/lib/active_record/relation/query_methods.rb +276 -67
  177. data/lib/active_record/relation/record_fetch_warning.rb +7 -9
  178. data/lib/active_record/relation/spawn_methods.rb +2 -2
  179. data/lib/active_record/relation/where_clause.rb +10 -19
  180. data/lib/active_record/relation.rb +189 -88
  181. data/lib/active_record/result.rb +17 -7
  182. data/lib/active_record/runtime_registry.rb +9 -13
  183. data/lib/active_record/sanitization.rb +17 -12
  184. data/lib/active_record/schema.rb +38 -23
  185. data/lib/active_record/schema_dumper.rb +25 -19
  186. data/lib/active_record/schema_migration.rb +4 -4
  187. data/lib/active_record/scoping/default.rb +60 -13
  188. data/lib/active_record/scoping/named.rb +3 -11
  189. data/lib/active_record/scoping.rb +64 -34
  190. data/lib/active_record/serialization.rb +6 -1
  191. data/lib/active_record/signed_id.rb +3 -3
  192. data/lib/active_record/store.rb +7 -2
  193. data/lib/active_record/suppressor.rb +11 -15
  194. data/lib/active_record/tasks/database_tasks.rb +127 -60
  195. data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
  196. data/lib/active_record/tasks/postgresql_database_tasks.rb +19 -13
  197. data/lib/active_record/test_databases.rb +1 -1
  198. data/lib/active_record/test_fixtures.rb +16 -9
  199. data/lib/active_record/timestamp.rb +3 -4
  200. data/lib/active_record/transactions.rb +9 -14
  201. data/lib/active_record/translation.rb +3 -3
  202. data/lib/active_record/type/adapter_specific_registry.rb +32 -7
  203. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  204. data/lib/active_record/type/internal/timezone.rb +2 -2
  205. data/lib/active_record/type/serialized.rb +1 -1
  206. data/lib/active_record/type/type_map.rb +17 -20
  207. data/lib/active_record/type.rb +1 -2
  208. data/lib/active_record/validations/associated.rb +4 -4
  209. data/lib/active_record/validations/presence.rb +2 -2
  210. data/lib/active_record/validations/uniqueness.rb +4 -4
  211. data/lib/active_record/version.rb +1 -1
  212. data/lib/active_record.rb +217 -27
  213. data/lib/arel/attributes/attribute.rb +0 -8
  214. data/lib/arel/crud.rb +28 -22
  215. data/lib/arel/delete_manager.rb +18 -4
  216. data/lib/arel/filter_predications.rb +9 -0
  217. data/lib/arel/insert_manager.rb +2 -3
  218. data/lib/arel/nodes/casted.rb +1 -1
  219. data/lib/arel/nodes/delete_statement.rb +12 -13
  220. data/lib/arel/nodes/filter.rb +10 -0
  221. data/lib/arel/nodes/function.rb +1 -0
  222. data/lib/arel/nodes/insert_statement.rb +2 -2
  223. data/lib/arel/nodes/select_core.rb +2 -2
  224. data/lib/arel/nodes/select_statement.rb +2 -2
  225. data/lib/arel/nodes/update_statement.rb +8 -3
  226. data/lib/arel/nodes.rb +1 -0
  227. data/lib/arel/predications.rb +11 -3
  228. data/lib/arel/select_manager.rb +10 -4
  229. data/lib/arel/table.rb +0 -1
  230. data/lib/arel/tree_manager.rb +0 -12
  231. data/lib/arel/update_manager.rb +18 -4
  232. data/lib/arel/visitors/dot.rb +80 -90
  233. data/lib/arel/visitors/mysql.rb +8 -2
  234. data/lib/arel/visitors/postgresql.rb +0 -10
  235. data/lib/arel/visitors/to_sql.rb +58 -2
  236. data/lib/arel.rb +2 -1
  237. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  238. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  239. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  240. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  241. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  242. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  243. metadata +55 -11
@@ -20,10 +20,9 @@ module ActiveRecord
20
20
  SQLite3::ExplainPrettyPrinter.new.pp(exec_query(sql, "EXPLAIN", []))
21
21
  end
22
22
 
23
- def execute(sql, name = nil) #:nodoc:
24
- if preventing_writes? && write_query?(sql)
25
- raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
26
- end
23
+ def execute(sql, name = nil) # :nodoc:
24
+ sql = transform_query(sql)
25
+ check_if_write_query(sql)
27
26
 
28
27
  materialize_transactions
29
28
  mark_transaction_written_if_write(sql)
@@ -35,17 +34,16 @@ module ActiveRecord
35
34
  end
36
35
  end
37
36
 
38
- def exec_query(sql, name = nil, binds = [], prepare: false)
39
- if preventing_writes? && write_query?(sql)
40
- raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
41
- end
37
+ def exec_query(sql, name = nil, binds = [], prepare: false, async: false) # :nodoc:
38
+ sql = transform_query(sql)
39
+ check_if_write_query(sql)
42
40
 
43
41
  materialize_transactions
44
42
  mark_transaction_written_if_write(sql)
45
43
 
46
44
  type_casted_binds = type_casted_binds(binds)
47
45
 
48
- log(sql, name, binds, type_casted_binds) do
46
+ log(sql, name, binds, type_casted_binds, async: async) do
49
47
  ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
50
48
  # Don't cache statements if they are not prepared
51
49
  unless prepare
@@ -72,49 +70,57 @@ module ActiveRecord
72
70
  end
73
71
  end
74
72
 
75
- def exec_delete(sql, name = "SQL", binds = [])
73
+ def exec_delete(sql, name = "SQL", binds = []) # :nodoc:
76
74
  exec_query(sql, name, binds)
77
75
  @connection.changes
78
76
  end
79
77
  alias :exec_update :exec_delete
80
78
 
81
- def begin_isolated_db_transaction(isolation) #:nodoc
79
+ def begin_isolated_db_transaction(isolation) # :nodoc:
82
80
  raise TransactionIsolationError, "SQLite3 only supports the `read_uncommitted` transaction isolation level" if isolation != :read_uncommitted
83
81
  raise StandardError, "You need to enable the shared-cache mode in SQLite mode before attempting to change the transaction isolation level" unless shared_cache?
84
82
 
85
- Thread.current.thread_variable_set("read_uncommitted", @connection.get_first_value("PRAGMA read_uncommitted"))
83
+ ActiveSupport::IsolatedExecutionState[:active_record_read_uncommitted] = @connection.get_first_value("PRAGMA read_uncommitted")
86
84
  @connection.read_uncommitted = true
87
85
  begin_db_transaction
88
86
  end
89
87
 
90
- def begin_db_transaction #:nodoc:
88
+ def begin_db_transaction # :nodoc:
91
89
  log("begin transaction", "TRANSACTION") { @connection.transaction }
92
90
  end
93
91
 
94
- def commit_db_transaction #:nodoc:
92
+ def commit_db_transaction # :nodoc:
95
93
  log("commit transaction", "TRANSACTION") { @connection.commit }
96
94
  reset_read_uncommitted
97
95
  end
98
96
 
99
- def exec_rollback_db_transaction #:nodoc:
97
+ def exec_rollback_db_transaction # :nodoc:
100
98
  log("rollback transaction", "TRANSACTION") { @connection.rollback }
101
99
  reset_read_uncommitted
102
100
  end
103
101
 
102
+ # https://stackoverflow.com/questions/17574784
103
+ # https://www.sqlite.org/lang_datefunc.html
104
+ HIGH_PRECISION_CURRENT_TIMESTAMP = Arel.sql("STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')").freeze # :nodoc:
105
+ private_constant :HIGH_PRECISION_CURRENT_TIMESTAMP
106
+
107
+ def high_precision_current_timestamp
108
+ HIGH_PRECISION_CURRENT_TIMESTAMP
109
+ end
110
+
104
111
  private
105
112
  def reset_read_uncommitted
106
- read_uncommitted = Thread.current.thread_variable_get("read_uncommitted")
113
+ read_uncommitted = ActiveSupport::IsolatedExecutionState[:active_record_read_uncommitted]
107
114
  return unless read_uncommitted
108
115
 
109
116
  @connection.read_uncommitted = read_uncommitted
110
117
  end
111
118
 
112
119
  def execute_batch(statements, name = nil)
120
+ statements = statements.map { |sql| transform_query(sql) }
113
121
  sql = combine_multi_statements(statements)
114
122
 
115
- if preventing_writes? && write_query?(sql)
116
- raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
117
- end
123
+ check_if_write_query(sql)
118
124
 
119
125
  materialize_transactions
120
126
  mark_transaction_written_if_write(sql)
@@ -45,6 +45,34 @@ module ActiveRecord
45
45
  0
46
46
  end
47
47
 
48
+ def quote_default_expression(value, column) # :nodoc:
49
+ if value.is_a?(Proc)
50
+ value = value.call
51
+ if value.match?(/\A\w+\(.*\)\z/)
52
+ "(#{value})"
53
+ else
54
+ value
55
+ end
56
+ else
57
+ super
58
+ end
59
+ end
60
+
61
+ def type_cast(value) # :nodoc:
62
+ case value
63
+ when BigDecimal
64
+ value.to_f
65
+ when String
66
+ if value.encoding == Encoding::ASCII_8BIT
67
+ super(value.encode(Encoding::UTF_8))
68
+ else
69
+ super
70
+ end
71
+ else
72
+ super
73
+ end
74
+ end
75
+
48
76
  def column_name_matcher
49
77
  COLUMN_NAME
50
78
  end
@@ -80,22 +108,6 @@ module ActiveRecord
80
108
  /ix
81
109
 
82
110
  private_constant :COLUMN_NAME, :COLUMN_NAME_WITH_ORDER
83
-
84
- private
85
- def _type_cast(value)
86
- case value
87
- when BigDecimal
88
- value.to_f
89
- when String
90
- if value.encoding == Encoding::ASCII_8BIT
91
- super(value.encode(Encoding::UTF_8))
92
- else
93
- super
94
- end
95
- else
96
- super
97
- end
98
- end
99
111
  end
100
112
  end
101
113
  end
@@ -6,7 +6,7 @@ module ActiveRecord
6
6
  module SchemaStatements # :nodoc:
7
7
  # Returns an array of indexes for the given table.
8
8
  def indexes(table_name)
9
- exec_query("PRAGMA index_list(#{quote_table_name(table_name)})", "SCHEMA").map do |row|
9
+ exec_query("PRAGMA index_list(#{quote_table_name(table_name)})", "SCHEMA").filter_map do |row|
10
10
  # Indexes SQLite creates implicitly for internal use start with "sqlite_".
11
11
  # See https://www.sqlite.org/fileformat2.html#intschema
12
12
  next if row["name"].start_with?("sqlite_")
@@ -21,7 +21,7 @@ module ActiveRecord
21
21
  WHERE name = #{quote(row['name'])} AND type = 'index'
22
22
  SQL
23
23
 
24
- /\bON\b\s*"?(\w+?)"?\s*\((?<expressions>.+?)\)(?:\s*WHERE\b\s*(?<where>.+))?\z/i =~ index_sql
24
+ /\bON\b\s*"?(\w+?)"?\s*\((?<expressions>.+?)\)(?:\s*WHERE\b\s*(?<where>.+))?(?:\s*\/\*.*\*\/)?\z/i =~ index_sql
25
25
 
26
26
  columns = exec_query("PRAGMA index_info(#{quote(row['name'])})", "SCHEMA").map do |col|
27
27
  col["name"]
@@ -49,7 +49,7 @@ module ActiveRecord
49
49
  where: where,
50
50
  orders: orders
51
51
  )
52
- end.compact
52
+ end
53
53
  end
54
54
 
55
55
  def add_foreign_key(from_table, to_table, **options)
@@ -60,6 +60,8 @@ module ActiveRecord
60
60
  end
61
61
 
62
62
  def remove_foreign_key(from_table, to_table = nil, **options)
63
+ return if options.delete(:if_exists) == true && !foreign_key_exists?(from_table, to_table)
64
+
63
65
  to_table ||= options[:to_table]
64
66
  options = options.except(:name, :to_table, :validate)
65
67
  foreign_keys = foreign_keys(from_table)
@@ -125,20 +127,20 @@ module ActiveRecord
125
127
  end
126
128
 
127
129
  def new_column_from_field(table_name, field)
128
- default = \
129
- case field["dflt_value"]
130
- when /^null$/i
131
- nil
132
- when /^'(.*)'$/m
133
- $1.gsub("''", "'")
134
- when /^"(.*)"$/m
135
- $1.gsub('""', '"')
136
- else
137
- field["dflt_value"]
138
- end
130
+ default = field["dflt_value"]
139
131
 
140
132
  type_metadata = fetch_type_metadata(field["type"])
141
- Column.new(field["name"], default, type_metadata, field["notnull"].to_i == 0, collation: field["collation"])
133
+ default_value = extract_value_from_default(default)
134
+ default_function = extract_default_function(default_value, default)
135
+
136
+ Column.new(
137
+ field["name"],
138
+ default_value,
139
+ type_metadata,
140
+ field["notnull"].to_i == 0,
141
+ default_function,
142
+ collation: field["collation"]
143
+ )
142
144
  end
143
145
 
144
146
  def data_source_sql(name = nil, type: nil)
@@ -47,7 +47,7 @@ module ActiveRecord
47
47
  end
48
48
  end
49
49
 
50
- module ConnectionAdapters #:nodoc:
50
+ module ConnectionAdapters # :nodoc:
51
51
  # The SQLite3 adapter works with the sqlite3-ruby drivers
52
52
  # (available as gem from https://rubygems.org/gems/sqlite3).
53
53
  #
@@ -84,6 +84,7 @@ module ActiveRecord
84
84
  end
85
85
 
86
86
  def initialize(connection, logger, connection_options, config)
87
+ @memory_database = config[:database] == ":memory:"
87
88
  super(connection, logger, config)
88
89
  configure_connection
89
90
  end
@@ -153,6 +154,10 @@ module ActiveRecord
153
154
  alias supports_insert_on_duplicate_update? supports_insert_on_conflict?
154
155
  alias supports_insert_conflict_target? supports_insert_on_conflict?
155
156
 
157
+ def supports_concurrent_connections?
158
+ !@memory_database
159
+ end
160
+
156
161
  def active?
157
162
  !@connection.closed?
158
163
  end
@@ -173,11 +178,11 @@ module ActiveRecord
173
178
  true
174
179
  end
175
180
 
176
- def native_database_types #:nodoc:
181
+ def native_database_types # :nodoc:
177
182
  NATIVE_DATABASE_TYPES
178
183
  end
179
184
 
180
- # Returns the current database encoding format as a string, eg: 'UTF-8'
185
+ # Returns the current database encoding format as a string, e.g. 'UTF-8'
181
186
  def encoding
182
187
  @connection.encoding.to_s
183
188
  end
@@ -206,6 +211,10 @@ module ActiveRecord
206
211
  end
207
212
  end
208
213
 
214
+ def all_foreign_keys_valid? # :nodoc:
215
+ execute("PRAGMA foreign_key_check").blank?
216
+ end
217
+
209
218
  # SCHEMA STATEMENTS ========================================
210
219
 
211
220
  def primary_keys(table_name) # :nodoc:
@@ -232,7 +241,7 @@ module ActiveRecord
232
241
  rename_table_indexes(table_name, new_name)
233
242
  end
234
243
 
235
- def add_column(table_name, column_name, type, **options) #:nodoc:
244
+ def add_column(table_name, column_name, type, **options) # :nodoc:
236
245
  if invalid_alter_table_type?(type, options)
237
246
  alter_table(table_name) do |definition|
238
247
  definition.column(column_name, type, **options)
@@ -242,16 +251,24 @@ module ActiveRecord
242
251
  end
243
252
  end
244
253
 
245
- def remove_column(table_name, column_name, type = nil, **options) #:nodoc:
254
+ def remove_column(table_name, column_name, type = nil, **options) # :nodoc:
246
255
  alter_table(table_name) do |definition|
247
256
  definition.remove_column column_name
248
- definition.foreign_keys.delete_if do |_, fk_options|
249
- fk_options[:column] == column_name.to_s
257
+ definition.foreign_keys.delete_if { |fk| fk.column == column_name.to_s }
258
+ end
259
+ end
260
+
261
+ def remove_columns(table_name, *column_names, type: nil, **options) # :nodoc:
262
+ alter_table(table_name) do |definition|
263
+ column_names.each do |column_name|
264
+ definition.remove_column column_name
250
265
  end
266
+ column_names = column_names.map(&:to_s)
267
+ definition.foreign_keys.delete_if { |fk| column_names.include?(fk.column) }
251
268
  end
252
269
  end
253
270
 
254
- def change_column_default(table_name, column_name, default_or_changes) #:nodoc:
271
+ def change_column_default(table_name, column_name, default_or_changes) # :nodoc:
255
272
  default = extract_new_default_value(default_or_changes)
256
273
 
257
274
  alter_table(table_name) do |definition|
@@ -259,7 +276,7 @@ module ActiveRecord
259
276
  end
260
277
  end
261
278
 
262
- def change_column_null(table_name, column_name, null, default = nil) #:nodoc:
279
+ def change_column_null(table_name, column_name, null, default = nil) # :nodoc:
263
280
  unless null || default.nil?
264
281
  exec_query("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
265
282
  end
@@ -268,7 +285,7 @@ module ActiveRecord
268
285
  end
269
286
  end
270
287
 
271
- def change_column(table_name, column_name, type, **options) #:nodoc:
288
+ def change_column(table_name, column_name, type, **options) # :nodoc:
272
289
  alter_table(table_name) do |definition|
273
290
  definition[column_name].instance_eval do
274
291
  self.type = aliased_types(type.to_s, type)
@@ -277,7 +294,7 @@ module ActiveRecord
277
294
  end
278
295
  end
279
296
 
280
- def rename_column(table_name, column_name, new_column_name) #:nodoc:
297
+ def rename_column(table_name, column_name, new_column_name) # :nodoc:
281
298
  column = column_for(table_name, column_name)
282
299
  alter_table(table_name, rename: { column.name => new_column_name.to_s })
283
300
  rename_column_indexes(table_name, column.name, new_column_name)
@@ -308,8 +325,12 @@ module ActiveRecord
308
325
  sql << " ON CONFLICT #{insert.conflict_target} DO NOTHING"
309
326
  elsif insert.update_duplicates?
310
327
  sql << " ON CONFLICT #{insert.conflict_target} DO UPDATE SET "
311
- sql << insert.touch_model_timestamps_unless { |column| "#{column} IS excluded.#{column}" }
312
- sql << insert.updatable_columns.map { |column| "#{column}=excluded.#{column}" }.join(",")
328
+ if insert.raw_update_sql?
329
+ sql << insert.raw_update_sql
330
+ else
331
+ sql << insert.touch_model_timestamps_unless { |column| "#{column} IS excluded.#{column}" }
332
+ sql << insert.updatable_columns.map { |column| "#{column}=excluded.#{column}" }.join(",")
333
+ end
313
334
  end
314
335
 
315
336
  sql
@@ -320,7 +341,7 @@ module ActiveRecord
320
341
  end
321
342
 
322
343
  def get_database_version # :nodoc:
323
- SQLite3Adapter::Version.new(query_value("SELECT sqlite_version(*)"))
344
+ SQLite3Adapter::Version.new(query_value("SELECT sqlite_version(*)", "SCHEMA"))
324
345
  end
325
346
 
326
347
  def check_version # :nodoc:
@@ -329,18 +350,38 @@ module ActiveRecord
329
350
  end
330
351
  end
331
352
 
353
+ class SQLite3Integer < Type::Integer # :nodoc:
354
+ private
355
+ def _limit
356
+ # INTEGER storage class can be stored 8 bytes value.
357
+ # See https://www.sqlite.org/datatype3.html#storage_classes_and_datatypes
358
+ limit || 8
359
+ end
360
+ end
361
+
362
+ ActiveRecord::Type.register(:integer, SQLite3Integer, adapter: :sqlite3)
363
+
364
+ class << self
365
+ private
366
+ def initialize_type_map(m)
367
+ super
368
+ register_class_with_limit m, %r(int)i, SQLite3Integer
369
+ end
370
+ end
371
+
372
+ TYPE_MAP = Type::TypeMap.new.tap { |m| initialize_type_map(m) }
373
+
332
374
  private
375
+ def type_map
376
+ TYPE_MAP
377
+ end
378
+
333
379
  # See https://www.sqlite.org/limits.html,
334
380
  # the default value is 999 when not configured.
335
381
  def bind_params_length
336
382
  999
337
383
  end
338
384
 
339
- def initialize_type_map(m = type_map)
340
- super
341
- register_class_with_limit m, %r(int)i, SQLite3Integer
342
- end
343
-
344
385
  def table_structure(table_name)
345
386
  structure = exec_query("PRAGMA table_info(#{quote_table_name(table_name)})", "SCHEMA")
346
387
  raise(ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'") if structure.empty?
@@ -348,6 +389,34 @@ module ActiveRecord
348
389
  end
349
390
  alias column_definitions table_structure
350
391
 
392
+ def extract_value_from_default(default)
393
+ case default
394
+ when /^null$/i
395
+ nil
396
+ # Quoted types
397
+ when /^'(.*)'$/m
398
+ $1.gsub("''", "'")
399
+ # Quoted types
400
+ when /^"(.*)"$/m
401
+ $1.gsub('""', '"')
402
+ # Numeric types
403
+ when /\A-?\d+(\.\d*)?\z/
404
+ $&
405
+ else
406
+ # Anything else is blank or some function
407
+ # and we can't know the value of that, so return nil.
408
+ nil
409
+ end
410
+ end
411
+
412
+ def extract_default_function(default_value, default)
413
+ default if has_default_function?(default_value, default)
414
+ end
415
+
416
+ def has_default_function?(default_value, default)
417
+ !default_value && %r{\w+\(.*\)|CURRENT_TIME|CURRENT_DATE|CURRENT_TIMESTAMP}.match?(default)
418
+ end
419
+
351
420
  # See: https://www.sqlite.org/lang_altertable.html
352
421
  # SQLite has an additional restriction on the ALTER TABLE statement
353
422
  def invalid_alter_table_type?(type, options)
@@ -408,8 +477,13 @@ module ActiveRecord
408
477
  options[:rename][column.name.to_sym] ||
409
478
  column.name) : column.name
410
479
 
480
+ if column.has_default?
481
+ type = lookup_cast_type_from_column(column)
482
+ default = type.deserialize(column.default)
483
+ end
484
+
411
485
  @definition.column(column_name, column.type,
412
- limit: column.limit, default: column.default,
486
+ limit: column.limit, default: default,
413
487
  precision: column.precision, scale: column.scale,
414
488
  null: column.null, collation: column.collation,
415
489
  primary_key: column_name == from_primary_key
@@ -446,6 +520,7 @@ module ActiveRecord
446
520
  options = { name: name.gsub(/(^|_)(#{from})_/, "\\1#{to}_"), internal: true }
447
521
  options[:unique] = true if index.unique
448
522
  options[:where] = index.where if index.where
523
+ options[:order] = index.orders if index.orders
449
524
  add_index(to, columns, **options)
450
525
  end
451
526
  end
@@ -482,7 +557,7 @@ module ActiveRecord
482
557
  end
483
558
  end
484
559
 
485
- COLLATE_REGEX = /.*\"(\w+)\".*collate\s+\"(\w+)\".*/i.freeze
560
+ COLLATE_REGEX = /.*"(\w+)".*collate\s+"(\w+)".*/i.freeze
486
561
 
487
562
  def table_structure_with_collation(table_name, basic_structure)
488
563
  collation_hash = {}
@@ -544,17 +619,6 @@ module ActiveRecord
544
619
 
545
620
  execute("PRAGMA foreign_keys = ON", "SCHEMA")
546
621
  end
547
-
548
- class SQLite3Integer < Type::Integer # :nodoc:
549
- private
550
- def _limit
551
- # INTEGER storage class can be stored 8 bytes value.
552
- # See https://www.sqlite.org/datatype3.html#storage_classes_and_datatypes
553
- limit || 8
554
- end
555
- end
556
-
557
- ActiveRecord::Type.register(:integer, SQLite3Integer, adapter: :sqlite3)
558
622
  end
559
623
  ActiveSupport.run_load_hooks(:active_record_sqlite3adapter, SQLite3Adapter)
560
624
  end
@@ -27,20 +27,21 @@ module ActiveRecord
27
27
  autoload :ReferenceDefinition
28
28
  end
29
29
 
30
- autoload_at "active_record/connection_adapters/abstract/connection_pool" do
31
- autoload :ConnectionHandler
32
- end
33
-
34
30
  autoload_under "abstract" do
35
31
  autoload :SchemaStatements
36
32
  autoload :DatabaseStatements
37
33
  autoload :DatabaseLimits
38
34
  autoload :Quoting
39
- autoload :ConnectionPool
35
+ autoload :ConnectionHandler
40
36
  autoload :QueryCache
41
37
  autoload :Savepoints
42
38
  end
43
39
 
40
+ autoload_at "active_record/connection_adapters/abstract/connection_pool" do
41
+ autoload :ConnectionPool
42
+ autoload :NullPool
43
+ end
44
+
44
45
  autoload_at "active_record/connection_adapters/abstract/transaction" do
45
46
  autoload :TransactionManager
46
47
  autoload :NullTransaction