activerecord 7.0.4.3 → 7.1.3.4

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 (242) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1657 -1274
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +18 -18
  5. data/lib/active_record/aggregations.rb +16 -13
  6. data/lib/active_record/association_relation.rb +1 -1
  7. data/lib/active_record/associations/association.rb +20 -4
  8. data/lib/active_record/associations/association_scope.rb +16 -9
  9. data/lib/active_record/associations/belongs_to_association.rb +14 -6
  10. data/lib/active_record/associations/builder/association.rb +3 -3
  11. data/lib/active_record/associations/builder/belongs_to.rb +21 -8
  12. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
  13. data/lib/active_record/associations/builder/singular_association.rb +4 -0
  14. data/lib/active_record/associations/collection_association.rb +16 -10
  15. data/lib/active_record/associations/collection_proxy.rb +20 -10
  16. data/lib/active_record/associations/foreign_association.rb +10 -3
  17. data/lib/active_record/associations/has_many_association.rb +20 -13
  18. data/lib/active_record/associations/has_many_through_association.rb +10 -6
  19. data/lib/active_record/associations/has_one_association.rb +10 -3
  20. data/lib/active_record/associations/join_dependency.rb +10 -8
  21. data/lib/active_record/associations/preloader/association.rb +31 -7
  22. data/lib/active_record/associations/preloader/through_association.rb +1 -1
  23. data/lib/active_record/associations/preloader.rb +13 -10
  24. data/lib/active_record/associations/singular_association.rb +1 -1
  25. data/lib/active_record/associations/through_association.rb +22 -11
  26. data/lib/active_record/associations.rb +327 -222
  27. data/lib/active_record/attribute_assignment.rb +0 -2
  28. data/lib/active_record/attribute_methods/before_type_cast.rb +17 -0
  29. data/lib/active_record/attribute_methods/dirty.rb +52 -34
  30. data/lib/active_record/attribute_methods/primary_key.rb +76 -24
  31. data/lib/active_record/attribute_methods/query.rb +28 -16
  32. data/lib/active_record/attribute_methods/read.rb +18 -5
  33. data/lib/active_record/attribute_methods/serialization.rb +150 -31
  34. data/lib/active_record/attribute_methods/time_zone_conversion.rb +0 -4
  35. data/lib/active_record/attribute_methods/write.rb +3 -3
  36. data/lib/active_record/attribute_methods.rb +108 -26
  37. data/lib/active_record/attributes.rb +3 -3
  38. data/lib/active_record/autosave_association.rb +55 -9
  39. data/lib/active_record/base.rb +7 -2
  40. data/lib/active_record/callbacks.rb +16 -32
  41. data/lib/active_record/coders/column_serializer.rb +61 -0
  42. data/lib/active_record/coders/json.rb +1 -1
  43. data/lib/active_record/coders/yaml_column.rb +70 -42
  44. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +163 -88
  45. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +2 -0
  46. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +3 -1
  47. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +74 -51
  48. data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
  49. data/lib/active_record/connection_adapters/abstract/database_statements.rb +129 -31
  50. data/lib/active_record/connection_adapters/abstract/query_cache.rb +62 -23
  51. data/lib/active_record/connection_adapters/abstract/quoting.rb +41 -6
  52. data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
  53. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +18 -4
  54. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +155 -25
  55. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +290 -124
  56. data/lib/active_record/connection_adapters/abstract/transaction.rb +287 -58
  57. data/lib/active_record/connection_adapters/abstract_adapter.rb +509 -102
  58. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +217 -112
  59. data/lib/active_record/connection_adapters/column.rb +9 -0
  60. data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
  61. data/lib/active_record/connection_adapters/mysql/database_statements.rb +23 -144
  62. data/lib/active_record/connection_adapters/mysql/quoting.rb +29 -14
  63. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
  64. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
  65. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
  66. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +18 -13
  67. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +151 -0
  68. data/lib/active_record/connection_adapters/mysql2_adapter.rb +98 -53
  69. data/lib/active_record/connection_adapters/pool_config.rb +14 -5
  70. data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
  71. data/lib/active_record/connection_adapters/postgresql/column.rb +16 -3
  72. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +75 -45
  73. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  74. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
  75. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +11 -2
  76. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +2 -2
  77. data/lib/active_record/connection_adapters/postgresql/quoting.rb +15 -8
  78. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +3 -9
  79. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -6
  80. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +131 -2
  81. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +53 -0
  82. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +362 -60
  83. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
  84. data/lib/active_record/connection_adapters/postgresql_adapter.rb +354 -193
  85. data/lib/active_record/connection_adapters/schema_cache.rb +287 -59
  86. data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
  87. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +52 -39
  88. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +9 -5
  89. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +7 -0
  90. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +28 -9
  91. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +211 -83
  92. data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
  93. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
  94. data/lib/active_record/connection_adapters/trilogy_adapter.rb +262 -0
  95. data/lib/active_record/connection_adapters.rb +3 -1
  96. data/lib/active_record/connection_handling.rb +72 -95
  97. data/lib/active_record/core.rb +175 -153
  98. data/lib/active_record/counter_cache.rb +46 -25
  99. data/lib/active_record/database_configurations/database_config.rb +9 -3
  100. data/lib/active_record/database_configurations/hash_config.rb +22 -12
  101. data/lib/active_record/database_configurations/url_config.rb +17 -11
  102. data/lib/active_record/database_configurations.rb +86 -33
  103. data/lib/active_record/delegated_type.rb +9 -4
  104. data/lib/active_record/deprecator.rb +7 -0
  105. data/lib/active_record/destroy_association_async_job.rb +2 -0
  106. data/lib/active_record/disable_joins_association_relation.rb +1 -1
  107. data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
  108. data/lib/active_record/encryption/cipher/aes256_gcm.rb +4 -1
  109. data/lib/active_record/encryption/config.rb +25 -1
  110. data/lib/active_record/encryption/configurable.rb +12 -19
  111. data/lib/active_record/encryption/context.rb +10 -3
  112. data/lib/active_record/encryption/contexts.rb +5 -1
  113. data/lib/active_record/encryption/derived_secret_key_provider.rb +8 -2
  114. data/lib/active_record/encryption/encryptable_record.rb +42 -18
  115. data/lib/active_record/encryption/encrypted_attribute_type.rb +21 -6
  116. data/lib/active_record/encryption/extended_deterministic_queries.rb +66 -69
  117. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +3 -3
  118. data/lib/active_record/encryption/key_generator.rb +12 -1
  119. data/lib/active_record/encryption/message_serializer.rb +2 -0
  120. data/lib/active_record/encryption/properties.rb +3 -3
  121. data/lib/active_record/encryption/scheme.rb +19 -22
  122. data/lib/active_record/encryption.rb +1 -0
  123. data/lib/active_record/enum.rb +112 -28
  124. data/lib/active_record/errors.rb +112 -18
  125. data/lib/active_record/explain.rb +23 -3
  126. data/lib/active_record/explain_subscriber.rb +1 -1
  127. data/lib/active_record/fixture_set/model_metadata.rb +14 -4
  128. data/lib/active_record/fixture_set/render_context.rb +2 -0
  129. data/lib/active_record/fixture_set/table_row.rb +29 -8
  130. data/lib/active_record/fixtures.rb +135 -71
  131. data/lib/active_record/future_result.rb +31 -5
  132. data/lib/active_record/gem_version.rb +4 -4
  133. data/lib/active_record/inheritance.rb +30 -16
  134. data/lib/active_record/insert_all.rb +57 -10
  135. data/lib/active_record/integration.rb +8 -8
  136. data/lib/active_record/internal_metadata.rb +120 -30
  137. data/lib/active_record/locking/optimistic.rb +32 -18
  138. data/lib/active_record/locking/pessimistic.rb +5 -2
  139. data/lib/active_record/log_subscriber.rb +29 -12
  140. data/lib/active_record/marshalling.rb +56 -0
  141. data/lib/active_record/message_pack.rb +124 -0
  142. data/lib/active_record/middleware/database_selector/resolver.rb +4 -0
  143. data/lib/active_record/middleware/database_selector.rb +9 -11
  144. data/lib/active_record/middleware/shard_selector.rb +3 -1
  145. data/lib/active_record/migration/command_recorder.rb +105 -7
  146. data/lib/active_record/migration/compatibility.rb +157 -58
  147. data/lib/active_record/migration/default_strategy.rb +23 -0
  148. data/lib/active_record/migration/execution_strategy.rb +19 -0
  149. data/lib/active_record/migration/pending_migration_connection.rb +21 -0
  150. data/lib/active_record/migration.rb +271 -114
  151. data/lib/active_record/model_schema.rb +64 -44
  152. data/lib/active_record/nested_attributes.rb +24 -6
  153. data/lib/active_record/normalization.rb +167 -0
  154. data/lib/active_record/persistence.rb +195 -42
  155. data/lib/active_record/promise.rb +84 -0
  156. data/lib/active_record/query_cache.rb +3 -21
  157. data/lib/active_record/query_logs.rb +77 -52
  158. data/lib/active_record/query_logs_formatter.rb +41 -0
  159. data/lib/active_record/querying.rb +15 -2
  160. data/lib/active_record/railtie.rb +109 -47
  161. data/lib/active_record/railties/controller_runtime.rb +14 -9
  162. data/lib/active_record/railties/databases.rake +142 -148
  163. data/lib/active_record/railties/job_runtime.rb +23 -0
  164. data/lib/active_record/readonly_attributes.rb +32 -5
  165. data/lib/active_record/reflection.rb +182 -44
  166. data/lib/active_record/relation/batches/batch_enumerator.rb +5 -3
  167. data/lib/active_record/relation/batches.rb +190 -61
  168. data/lib/active_record/relation/calculations.rb +232 -81
  169. data/lib/active_record/relation/delegation.rb +23 -9
  170. data/lib/active_record/relation/finder_methods.rb +77 -16
  171. data/lib/active_record/relation/merger.rb +2 -0
  172. data/lib/active_record/relation/predicate_builder/association_query_value.rb +31 -3
  173. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +4 -6
  174. data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
  175. data/lib/active_record/relation/predicate_builder.rb +26 -14
  176. data/lib/active_record/relation/query_attribute.rb +25 -1
  177. data/lib/active_record/relation/query_methods.rb +387 -71
  178. data/lib/active_record/relation/spawn_methods.rb +18 -1
  179. data/lib/active_record/relation.rb +91 -35
  180. data/lib/active_record/result.rb +25 -9
  181. data/lib/active_record/runtime_registry.rb +24 -1
  182. data/lib/active_record/sanitization.rb +51 -11
  183. data/lib/active_record/schema.rb +2 -3
  184. data/lib/active_record/schema_dumper.rb +50 -7
  185. data/lib/active_record/schema_migration.rb +68 -33
  186. data/lib/active_record/scoping/default.rb +15 -5
  187. data/lib/active_record/scoping/named.rb +2 -2
  188. data/lib/active_record/scoping.rb +2 -1
  189. data/lib/active_record/secure_password.rb +60 -0
  190. data/lib/active_record/secure_token.rb +21 -3
  191. data/lib/active_record/signed_id.rb +7 -5
  192. data/lib/active_record/store.rb +9 -9
  193. data/lib/active_record/suppressor.rb +3 -1
  194. data/lib/active_record/table_metadata.rb +16 -3
  195. data/lib/active_record/tasks/database_tasks.rb +127 -105
  196. data/lib/active_record/tasks/mysql_database_tasks.rb +15 -6
  197. data/lib/active_record/tasks/postgresql_database_tasks.rb +16 -13
  198. data/lib/active_record/tasks/sqlite_database_tasks.rb +15 -7
  199. data/lib/active_record/test_fixtures.rb +113 -96
  200. data/lib/active_record/timestamp.rb +27 -15
  201. data/lib/active_record/token_for.rb +113 -0
  202. data/lib/active_record/touch_later.rb +11 -6
  203. data/lib/active_record/transactions.rb +39 -13
  204. data/lib/active_record/type/adapter_specific_registry.rb +1 -8
  205. data/lib/active_record/type/internal/timezone.rb +7 -2
  206. data/lib/active_record/type/serialized.rb +8 -4
  207. data/lib/active_record/type/time.rb +4 -0
  208. data/lib/active_record/validations/absence.rb +1 -1
  209. data/lib/active_record/validations/numericality.rb +5 -4
  210. data/lib/active_record/validations/presence.rb +5 -28
  211. data/lib/active_record/validations/uniqueness.rb +47 -2
  212. data/lib/active_record/validations.rb +8 -4
  213. data/lib/active_record/version.rb +1 -1
  214. data/lib/active_record.rb +121 -16
  215. data/lib/arel/errors.rb +10 -0
  216. data/lib/arel/factory_methods.rb +4 -0
  217. data/lib/arel/filter_predications.rb +1 -1
  218. data/lib/arel/nodes/and.rb +4 -0
  219. data/lib/arel/nodes/binary.rb +6 -1
  220. data/lib/arel/nodes/bound_sql_literal.rb +61 -0
  221. data/lib/arel/nodes/cte.rb +36 -0
  222. data/lib/arel/nodes/filter.rb +1 -1
  223. data/lib/arel/nodes/fragments.rb +35 -0
  224. data/lib/arel/nodes/homogeneous_in.rb +1 -9
  225. data/lib/arel/nodes/leading_join.rb +8 -0
  226. data/lib/arel/nodes/node.rb +111 -2
  227. data/lib/arel/nodes/sql_literal.rb +6 -0
  228. data/lib/arel/nodes/table_alias.rb +4 -0
  229. data/lib/arel/nodes.rb +4 -0
  230. data/lib/arel/predications.rb +2 -0
  231. data/lib/arel/table.rb +9 -5
  232. data/lib/arel/visitors/mysql.rb +8 -1
  233. data/lib/arel/visitors/to_sql.rb +81 -17
  234. data/lib/arel/visitors/visitor.rb +2 -2
  235. data/lib/arel.rb +16 -2
  236. data/lib/rails/generators/active_record/application_record/USAGE +8 -0
  237. data/lib/rails/generators/active_record/migration.rb +3 -1
  238. data/lib/rails/generators/active_record/model/USAGE +113 -0
  239. data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
  240. metadata +48 -12
  241. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
  242. data/lib/active_record/null_relation.rb +0 -63
@@ -5,10 +5,13 @@ require "concurrent/map"
5
5
  module ActiveRecord
6
6
  module ConnectionAdapters # :nodoc:
7
7
  module QueryCache
8
+ DEFAULT_SIZE = 100 # :nodoc:
9
+
8
10
  class << self
9
11
  def included(base) # :nodoc:
10
- dirties_query_cache base, :create, :insert, :update, :delete, :truncate, :truncate_tables,
11
- :rollback_to_savepoint, :rollback_db_transaction, :exec_insert_all
12
+ dirties_query_cache base, :exec_query, :execute, :create, :insert, :update, :delete, :truncate,
13
+ :truncate_tables, :rollback_to_savepoint, :rollback_db_transaction, :restart_db_transaction,
14
+ :exec_insert_all
12
15
 
13
16
  base.set_callback :checkout, :after, :configure_query_cache!
14
17
  base.set_callback :checkin, :after, :disable_query_cache!
@@ -17,7 +20,7 @@ module ActiveRecord
17
20
  def dirties_query_cache(base, *method_names)
18
21
  method_names.each do |method_name|
19
22
  base.class_eval <<-end_code, __FILE__, __LINE__ + 1
20
- def #{method_name}(*)
23
+ def #{method_name}(...)
21
24
  ActiveRecord::Base.clear_query_caches_for_current_thread
22
25
  super
23
26
  end
@@ -51,8 +54,9 @@ module ActiveRecord
51
54
 
52
55
  def initialize(*)
53
56
  super
54
- @query_cache = Hash.new { |h, sql| h[sql] = {} }
57
+ @query_cache = {}
55
58
  @query_cache_enabled = false
59
+ @query_cache_max_size = nil
56
60
  end
57
61
 
58
62
  # Enable the query cache within the block.
@@ -93,7 +97,7 @@ module ActiveRecord
93
97
  end
94
98
  end
95
99
 
96
- def select_all(arel, name = nil, binds = [], preparable: nil, async: false)
100
+ def select_all(arel, name = nil, binds = [], preparable: nil, async: false) # :nodoc:
97
101
  arel = arel_from_relation(arel)
98
102
 
99
103
  # If arel is locked this is a SELECT ... FOR UPDATE or somesuch.
@@ -102,7 +106,8 @@ module ActiveRecord
102
106
  sql, binds, preparable = to_sql_and_binds(arel, binds, preparable)
103
107
 
104
108
  if async
105
- lookup_sql_cache(sql, name, binds) || super(sql, name, binds, preparable: preparable, async: async)
109
+ result = lookup_sql_cache(sql, name, binds) || super(sql, name, binds, preparable: preparable, async: async)
110
+ FutureResult::Complete.new(result)
106
111
  else
107
112
  cache_sql(sql, name, binds) { super(sql, name, binds, preparable: preparable, async: async) }
108
113
  end
@@ -113,31 +118,52 @@ module ActiveRecord
113
118
 
114
119
  private
115
120
  def lookup_sql_cache(sql, name, binds)
121
+ key = binds.empty? ? sql : [sql, binds]
122
+ hit = false
123
+ result = nil
124
+
116
125
  @lock.synchronize do
117
- if @query_cache[sql].key?(binds)
118
- ActiveSupport::Notifications.instrument(
119
- "sql.active_record",
120
- cache_notification_info(sql, name, binds)
121
- )
122
- @query_cache[sql][binds]
126
+ if (result = @query_cache.delete(key))
127
+ hit = true
128
+ @query_cache[key] = result
123
129
  end
124
130
  end
131
+
132
+ if hit
133
+ ActiveSupport::Notifications.instrument(
134
+ "sql.active_record",
135
+ cache_notification_info(sql, name, binds)
136
+ )
137
+
138
+ result
139
+ end
125
140
  end
126
141
 
127
142
  def cache_sql(sql, name, binds)
143
+ key = binds.empty? ? sql : [sql, binds]
144
+ result = nil
145
+ hit = false
146
+
128
147
  @lock.synchronize do
129
- result =
130
- if @query_cache[sql].key?(binds)
131
- ActiveSupport::Notifications.instrument(
132
- "sql.active_record",
133
- cache_notification_info(sql, name, binds)
134
- )
135
- @query_cache[sql][binds]
136
- else
137
- @query_cache[sql][binds] = yield
148
+ if (result = @query_cache.delete(key))
149
+ hit = true
150
+ @query_cache[key] = result
151
+ else
152
+ result = @query_cache[key] = yield
153
+ if @query_cache_max_size && @query_cache.size > @query_cache_max_size
154
+ @query_cache.shift
138
155
  end
139
- result.dup
156
+ end
140
157
  end
158
+
159
+ if hit
160
+ ActiveSupport::Notifications.instrument(
161
+ "sql.active_record",
162
+ cache_notification_info(sql, name, binds)
163
+ )
164
+ end
165
+
166
+ result.dup
141
167
  end
142
168
 
143
169
  # Database adapters can override this method to
@@ -154,7 +180,20 @@ module ActiveRecord
154
180
  end
155
181
 
156
182
  def configure_query_cache!
157
- enable_query_cache! if pool.query_cache_enabled
183
+ case query_cache = pool.db_config.query_cache
184
+ when 0, false
185
+ return
186
+ when Integer
187
+ @query_cache_max_size = query_cache
188
+ when nil
189
+ @query_cache_max_size = DEFAULT_SIZE
190
+ else
191
+ @query_cache_max_size = nil # no limit
192
+ end
193
+
194
+ if pool.query_cache_enabled
195
+ enable_query_cache!
196
+ end
158
197
  end
159
198
  end
160
199
  end
@@ -5,6 +5,7 @@ require "active_support/multibyte/chars"
5
5
 
6
6
  module ActiveRecord
7
7
  module ConnectionAdapters # :nodoc:
8
+ # = Active Record Connection Adapters \Quoting
8
9
  module Quoting
9
10
  # Quotes the column value to help prevent
10
11
  # {SQL injection attacks}[https://en.wikipedia.org/wiki/SQL_injection].
@@ -17,11 +18,14 @@ module ActiveRecord
17
18
  when nil then "NULL"
18
19
  # BigDecimals need to be put in a non-normalized form and quoted.
19
20
  when BigDecimal then value.to_s("F")
20
- when Numeric, ActiveSupport::Duration then value.to_s
21
+ when Numeric then value.to_s
21
22
  when Type::Binary::Data then quoted_binary(value)
22
23
  when Type::Time::Value then "'#{quoted_time(value)}'"
23
24
  when Date, Time then "'#{quoted_date(value)}'"
24
25
  when Class then "'#{value}'"
26
+ when ActiveSupport::Duration
27
+ warn_quote_duration_deprecated
28
+ value.to_s
25
29
  else raise TypeError, "can't quote #{value.class.name}"
26
30
  end
27
31
  end
@@ -47,8 +51,23 @@ module ActiveRecord
47
51
  # Quote a value to be used as a bound parameter of unknown type. For example,
48
52
  # MySQL might perform dangerous castings when comparing a string to a number,
49
53
  # so this method will cast numbers to string.
54
+ #
55
+ # Deprecated: Consider `Arel.sql("... ? ...", value)` or
56
+ # +sanitize_sql+ instead.
50
57
  def quote_bound_value(value)
51
- quote(value)
58
+ ActiveRecord.deprecator.warn(<<~MSG.squish)
59
+ #quote_bound_value is deprecated and will be removed in Rails 7.2.
60
+ Consider Arel.sql(".. ? ..", value) or #sanitize_sql instead.
61
+ MSG
62
+
63
+ quote(cast_bound_value(value))
64
+ end
65
+
66
+ # Cast a value to be used as a bound parameter of unknown type. For example,
67
+ # MySQL might perform dangerous castings when comparing a string to a number,
68
+ # so this method will cast numbers to string.
69
+ def cast_bound_value(value) # :nodoc:
70
+ value
52
71
  end
53
72
 
54
73
  # If you are having to call this function, you are likely doing something
@@ -83,7 +102,7 @@ module ActiveRecord
83
102
  # Override to return the quoted table name for assignment. Defaults to
84
103
  # table quoting.
85
104
  #
86
- # This works for mysql2 where table.column can be used to
105
+ # This works for MySQL where table.column can be used to
87
106
  # resolve ambiguity.
88
107
  #
89
108
  # We override this in the sqlite3 and postgresql adapters to use only
@@ -121,7 +140,7 @@ module ActiveRecord
121
140
  # if the value is a Time responding to usec.
122
141
  def quoted_date(value)
123
142
  if value.acts_like?(:time)
124
- if ActiveRecord.default_timezone == :utc
143
+ if default_timezone == :utc
125
144
  value = value.getutc if !value.utc?
126
145
  else
127
146
  value = value.getlocal
@@ -176,7 +195,7 @@ module ActiveRecord
176
195
  (
177
196
  (?:
178
197
  # table_name.column_name | function(one or no argument)
179
- ((?:\w+\.)?\w+) | \w+\((?:|\g<2>)\)
198
+ ((?:\w+\.)?\w+ | \w+\((?:|\g<2>)\))
180
199
  )
181
200
  (?:(?:\s+AS)?\s+\w+)?
182
201
  )
@@ -200,7 +219,7 @@ module ActiveRecord
200
219
  (
201
220
  (?:
202
221
  # table_name.column_name | function(one or no argument)
203
- ((?:\w+\.)?\w+) | \w+\((?:|\g<2>)\)
222
+ ((?:\w+\.)?\w+ | \w+\((?:|\g<2>)\))
204
223
  )
205
224
  (?:\s+ASC|\s+DESC)?
206
225
  (?:\s+NULLS\s+(?:FIRST|LAST))?
@@ -225,6 +244,22 @@ module ActiveRecord
225
244
  def lookup_cast_type(sql_type)
226
245
  type_map.lookup(sql_type)
227
246
  end
247
+
248
+ def warn_quote_duration_deprecated
249
+ ActiveRecord.deprecator.warn(<<~MSG)
250
+ Using ActiveSupport::Duration as an interpolated bind parameter in a SQL
251
+ string template is deprecated. To avoid this warning, you should explicitly
252
+ convert the duration to a more specific database type. For example, if you
253
+ want to use a duration as an integer number of seconds:
254
+ ```
255
+ Record.where("duration = ?", 1.hour.to_i)
256
+ ```
257
+ If you want to use a duration as an ISO 8601 string:
258
+ ```
259
+ Record.where("duration = ?", 1.hour.iso8601)
260
+ ```
261
+ MSG
262
+ end
228
263
  end
229
264
  end
230
265
  end
@@ -2,21 +2,22 @@
2
2
 
3
3
  module ActiveRecord
4
4
  module ConnectionAdapters
5
+ # = Active Record Connection Adapters \Savepoints
5
6
  module Savepoints
6
7
  def current_savepoint_name
7
8
  current_transaction.savepoint_name
8
9
  end
9
10
 
10
11
  def create_savepoint(name = current_savepoint_name)
11
- execute("SAVEPOINT #{name}", "TRANSACTION")
12
+ internal_execute("SAVEPOINT #{name}", "TRANSACTION")
12
13
  end
13
14
 
14
15
  def exec_rollback_to_savepoint(name = current_savepoint_name)
15
- execute("ROLLBACK TO SAVEPOINT #{name}", "TRANSACTION")
16
+ internal_execute("ROLLBACK TO SAVEPOINT #{name}", "TRANSACTION")
16
17
  end
17
18
 
18
19
  def release_savepoint(name = current_savepoint_name)
19
- execute("RELEASE SAVEPOINT #{name}", "TRANSACTION")
20
+ internal_execute("RELEASE SAVEPOINT #{name}", "TRANSACTION")
20
21
  end
21
22
  end
22
23
  end
@@ -14,8 +14,10 @@ module ActiveRecord
14
14
  end
15
15
 
16
16
  delegate :quote_column_name, :quote_table_name, :quote_default_expression, :type_to_sql,
17
- :options_include_default?, :supports_indexes_in_create?, :supports_foreign_keys?,
17
+ :options_include_default?, :supports_indexes_in_create?, :use_foreign_keys?,
18
18
  :quoted_columns_for_index, :supports_partial_index?, :supports_check_constraints?,
19
+ :supports_index_include?, :supports_exclusion_constraints?, :supports_unique_constraints?,
20
+ :supports_nulls_not_distinct?,
19
21
  to: :@conn, private: true
20
22
 
21
23
  private
@@ -51,7 +53,7 @@ module ActiveRecord
51
53
  statements.concat(o.indexes.map { |column_name, options| index_in_create(o.name, column_name, options) })
52
54
  end
53
55
 
54
- if supports_foreign_keys?
56
+ if use_foreign_keys?
55
57
  statements.concat(o.foreign_keys.map { |fk| accept fk })
56
58
  end
57
59
 
@@ -59,6 +61,14 @@ module ActiveRecord
59
61
  statements.concat(o.check_constraints.map { |chk| accept chk })
60
62
  end
61
63
 
64
+ if supports_exclusion_constraints?
65
+ statements.concat(o.exclusion_constraints.map { |exc| accept exc })
66
+ end
67
+
68
+ if supports_unique_constraints?
69
+ statements.concat(o.unique_constraints.map { |exc| accept exc })
70
+ end
71
+
62
72
  create_sql << "(#{statements.join(', ')})" if statements.present?
63
73
  add_table_options!(create_sql, o)
64
74
  create_sql << " AS #{to_sql(o.as)}" if o.as
@@ -70,10 +80,12 @@ module ActiveRecord
70
80
  end
71
81
 
72
82
  def visit_ForeignKeyDefinition(o)
83
+ quoted_columns = Array(o.column).map { |c| quote_column_name(c) }
84
+ quoted_primary_keys = Array(o.primary_key).map { |c| quote_column_name(c) }
73
85
  sql = +<<~SQL
74
86
  CONSTRAINT #{quote_column_name(o.name)}
75
- FOREIGN KEY (#{quote_column_name(o.column)})
76
- REFERENCES #{quote_table_name(o.to_table)} (#{quote_column_name(o.primary_key)})
87
+ FOREIGN KEY (#{quoted_columns.join(", ")})
88
+ REFERENCES #{quote_table_name(o.to_table)} (#{quoted_primary_keys.join(", ")})
77
89
  SQL
78
90
  sql << " #{action_sql('DELETE', o.on_delete)}" if o.on_delete
79
91
  sql << " #{action_sql('UPDATE', o.on_update)}" if o.on_update
@@ -100,6 +112,8 @@ module ActiveRecord
100
112
  sql << "#{quote_column_name(index.name)} ON #{quote_table_name(index.table)}"
101
113
  sql << "USING #{index.using}" if supports_index_using? && index.using
102
114
  sql << "(#{quoted_columns(index)})"
115
+ sql << "INCLUDE (#{quoted_include_columns(index.include)})" if supports_index_include? && index.include
116
+ sql << "NULLS NOT DISTINCT" if supports_nulls_not_distinct? && index.nulls_not_distinct
103
117
  sql << "WHERE #{index.where}" if supports_partial_index? && index.where
104
118
 
105
119
  sql.join(" ")