activerecord 6.0.4.8 → 6.1.0.rc1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +764 -883
- data/MIT-LICENSE +1 -1
- data/README.rdoc +3 -3
- data/lib/active_record/aggregations.rb +1 -1
- data/lib/active_record/association_relation.rb +22 -14
- data/lib/active_record/associations/alias_tracker.rb +19 -15
- data/lib/active_record/associations/association.rb +39 -27
- data/lib/active_record/associations/association_scope.rb +11 -15
- data/lib/active_record/associations/belongs_to_association.rb +15 -5
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
- data/lib/active_record/associations/builder/association.rb +9 -3
- data/lib/active_record/associations/builder/belongs_to.rb +10 -7
- data/lib/active_record/associations/builder/collection_association.rb +5 -4
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -1
- data/lib/active_record/associations/builder/has_many.rb +6 -2
- data/lib/active_record/associations/builder/has_one.rb +11 -14
- data/lib/active_record/associations/builder/singular_association.rb +1 -1
- data/lib/active_record/associations/collection_association.rb +19 -13
- data/lib/active_record/associations/collection_proxy.rb +12 -5
- data/lib/active_record/associations/foreign_association.rb +13 -0
- data/lib/active_record/associations/has_many_association.rb +24 -2
- data/lib/active_record/associations/has_many_through_association.rb +10 -4
- data/lib/active_record/associations/has_one_association.rb +15 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +29 -14
- data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +63 -49
- data/lib/active_record/associations/preloader/association.rb +13 -5
- data/lib/active_record/associations/preloader/through_association.rb +1 -1
- data/lib/active_record/associations/preloader.rb +5 -3
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations.rb +114 -11
- data/lib/active_record/attribute_assignment.rb +10 -8
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -9
- data/lib/active_record/attribute_methods/dirty.rb +1 -11
- data/lib/active_record/attribute_methods/primary_key.rb +6 -2
- data/lib/active_record/attribute_methods/query.rb +3 -6
- data/lib/active_record/attribute_methods/read.rb +8 -11
- data/lib/active_record/attribute_methods/serialization.rb +4 -4
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -13
- data/lib/active_record/attribute_methods/write.rb +12 -20
- data/lib/active_record/attribute_methods.rb +52 -48
- data/lib/active_record/attributes.rb +27 -7
- data/lib/active_record/autosave_association.rb +47 -30
- data/lib/active_record/base.rb +2 -14
- data/lib/active_record/callbacks.rb +32 -22
- data/lib/active_record/coders/yaml_column.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +180 -134
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +65 -22
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -7
- data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -116
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +110 -30
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +224 -85
- data/lib/active_record/connection_adapters/abstract/transaction.rb +66 -24
- data/lib/active_record/connection_adapters/abstract_adapter.rb +31 -70
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +123 -87
- data/lib/active_record/connection_adapters/column.rb +15 -1
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +22 -24
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +33 -6
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +3 -3
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -12
- data/lib/active_record/connection_adapters/pool_config.rb +63 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +12 -53
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -10
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -1
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +61 -29
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +72 -55
- data/lib/active_record/connection_adapters/schema_cache.rb +98 -15
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +10 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +30 -5
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +36 -3
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +48 -50
- data/lib/active_record/connection_adapters.rb +50 -0
- data/lib/active_record/connection_handling.rb +210 -71
- data/lib/active_record/core.rb +215 -49
- data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
- data/lib/active_record/database_configurations/database_config.rb +52 -9
- data/lib/active_record/database_configurations/hash_config.rb +54 -8
- data/lib/active_record/database_configurations/url_config.rb +15 -40
- data/lib/active_record/database_configurations.rb +124 -85
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/enum.rb +33 -23
- data/lib/active_record/errors.rb +47 -12
- data/lib/active_record/explain.rb +9 -4
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +10 -17
- data/lib/active_record/fixture_set/model_metadata.rb +1 -2
- data/lib/active_record/fixture_set/render_context.rb +1 -1
- data/lib/active_record/fixture_set/table_row.rb +2 -2
- data/lib/active_record/fixtures.rb +54 -8
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +40 -18
- data/lib/active_record/insert_all.rb +32 -5
- data/lib/active_record/integration.rb +3 -5
- data/lib/active_record/internal_metadata.rb +15 -4
- data/lib/active_record/legacy_yaml_adapter.rb +7 -3
- data/lib/active_record/locking/optimistic.rb +13 -16
- data/lib/active_record/locking/pessimistic.rb +6 -2
- data/lib/active_record/log_subscriber.rb +26 -8
- data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +5 -0
- data/lib/active_record/middleware/database_selector.rb +4 -1
- data/lib/active_record/migration/command_recorder.rb +47 -27
- data/lib/active_record/migration/compatibility.rb +67 -17
- data/lib/active_record/migration.rb +113 -83
- data/lib/active_record/model_schema.rb +88 -42
- data/lib/active_record/nested_attributes.rb +2 -3
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/persistence.rb +50 -45
- data/lib/active_record/query_cache.rb +15 -5
- data/lib/active_record/querying.rb +11 -6
- data/lib/active_record/railtie.rb +64 -44
- data/lib/active_record/railties/databases.rake +253 -98
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +59 -44
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/batches.rb +38 -31
- data/lib/active_record/relation/calculations.rb +100 -43
- data/lib/active_record/relation/finder_methods.rb +44 -14
- data/lib/active_record/relation/from_clause.rb +1 -1
- data/lib/active_record/relation/merger.rb +20 -23
- data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +2 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +3 -3
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +57 -33
- data/lib/active_record/relation/query_methods.rb +319 -196
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +6 -5
- data/lib/active_record/relation/where_clause.rb +104 -57
- data/lib/active_record/relation.rb +90 -64
- data/lib/active_record/result.rb +41 -33
- data/lib/active_record/runtime_registry.rb +2 -2
- data/lib/active_record/sanitization.rb +6 -17
- data/lib/active_record/schema_dumper.rb +34 -4
- data/lib/active_record/schema_migration.rb +0 -4
- data/lib/active_record/scoping/named.rb +1 -17
- data/lib/active_record/secure_token.rb +16 -8
- data/lib/active_record/serialization.rb +5 -3
- data/lib/active_record/signed_id.rb +116 -0
- data/lib/active_record/statement_cache.rb +20 -4
- data/lib/active_record/store.rb +2 -2
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +36 -52
- data/lib/active_record/tasks/database_tasks.rb +139 -113
- data/lib/active_record/tasks/mysql_database_tasks.rb +34 -35
- data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -26
- data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -9
- data/lib/active_record/test_databases.rb +5 -4
- data/lib/active_record/test_fixtures.rb +36 -33
- data/lib/active_record/timestamp.rb +4 -6
- data/lib/active_record/touch_later.rb +21 -21
- data/lib/active_record/transactions.rb +15 -64
- data/lib/active_record/type/serialized.rb +6 -2
- data/lib/active_record/type.rb +8 -1
- data/lib/active_record/type_caster/connection.rb +0 -1
- data/lib/active_record/type_caster/map.rb +8 -5
- data/lib/active_record/validations/associated.rb +1 -1
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +24 -4
- data/lib/active_record/validations.rb +1 -0
- data/lib/active_record.rb +7 -14
- data/lib/arel/attributes/attribute.rb +4 -0
- data/lib/arel/collectors/bind.rb +5 -0
- data/lib/arel/collectors/composite.rb +8 -0
- data/lib/arel/collectors/sql_string.rb +7 -0
- data/lib/arel/collectors/substitute_binds.rb +7 -0
- data/lib/arel/nodes/binary.rb +82 -8
- data/lib/arel/nodes/bind_param.rb +8 -0
- data/lib/arel/nodes/casted.rb +21 -9
- data/lib/arel/nodes/equality.rb +6 -9
- data/lib/arel/nodes/grouping.rb +3 -0
- data/lib/arel/nodes/homogeneous_in.rb +72 -0
- data/lib/arel/nodes/in.rb +8 -1
- data/lib/arel/nodes/infix_operation.rb +13 -1
- data/lib/arel/nodes/join_source.rb +1 -1
- data/lib/arel/nodes/node.rb +7 -6
- data/lib/arel/nodes/ordering.rb +27 -0
- data/lib/arel/nodes/sql_literal.rb +3 -0
- data/lib/arel/nodes/table_alias.rb +7 -3
- data/lib/arel/nodes/unary.rb +0 -1
- data/lib/arel/nodes.rb +3 -1
- data/lib/arel/predications.rb +12 -18
- data/lib/arel/select_manager.rb +1 -2
- data/lib/arel/table.rb +13 -5
- data/lib/arel/visitors/dot.rb +14 -2
- data/lib/arel/visitors/mysql.rb +11 -1
- data/lib/arel/visitors/postgresql.rb +15 -4
- data/lib/arel/visitors/to_sql.rb +89 -78
- data/lib/arel/visitors.rb +0 -7
- data/lib/arel.rb +5 -13
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +3 -3
- data/lib/rails/generators/active_record/migration.rb +6 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- metadata +30 -31
- data/lib/active_record/advisory_lock_base.rb +0 -18
- data/lib/active_record/attribute_decorators.rb +0 -88
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -296
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
- data/lib/active_record/define_callbacks.rb +0 -22
- data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
- data/lib/active_record/relation/where_clause_factory.rb +0 -33
- data/lib/arel/attributes.rb +0 -22
- data/lib/arel/visitors/depth_first.rb +0 -203
- data/lib/arel/visitors/ibm_db.rb +0 -34
- data/lib/arel/visitors/informix.rb +0 -62
- data/lib/arel/visitors/mssql.rb +0 -156
- data/lib/arel/visitors/oracle.rb +0 -158
- data/lib/arel/visitors/oracle12.rb +0 -65
- data/lib/arel/visitors/where_sql.rb +0 -22
@@ -14,29 +14,32 @@ module ActiveRecord
|
|
14
14
|
sql
|
15
15
|
end
|
16
16
|
|
17
|
-
def to_sql_and_binds(arel_or_sql_string, binds = []) # :nodoc:
|
17
|
+
def to_sql_and_binds(arel_or_sql_string, binds = [], preparable = nil) # :nodoc:
|
18
18
|
if arel_or_sql_string.respond_to?(:ast)
|
19
19
|
unless binds.empty?
|
20
20
|
raise "Passing bind parameters with an arel AST is forbidden. " \
|
21
21
|
"The values must be stored on the AST directly"
|
22
22
|
end
|
23
23
|
|
24
|
+
collector = collector()
|
25
|
+
|
24
26
|
if prepared_statements
|
27
|
+
collector.preparable = true
|
25
28
|
sql, binds = visitor.compile(arel_or_sql_string.ast, collector)
|
26
29
|
|
27
30
|
if binds.length > bind_params_length
|
28
31
|
unprepared_statement do
|
29
|
-
|
30
|
-
visitor.preparable = false
|
32
|
+
return to_sql_and_binds(arel_or_sql_string)
|
31
33
|
end
|
32
34
|
end
|
35
|
+
preparable = collector.preparable
|
33
36
|
else
|
34
37
|
sql = visitor.compile(arel_or_sql_string.ast, collector)
|
35
38
|
end
|
36
|
-
[sql.freeze, binds]
|
39
|
+
[sql.freeze, binds, preparable]
|
37
40
|
else
|
38
|
-
|
39
|
-
[arel_or_sql_string
|
41
|
+
arel_or_sql_string = arel_or_sql_string.dup.freeze unless arel_or_sql_string.frozen?
|
42
|
+
[arel_or_sql_string, binds, preparable]
|
40
43
|
end
|
41
44
|
end
|
42
45
|
private :to_sql_and_binds
|
@@ -58,17 +61,15 @@ module ActiveRecord
|
|
58
61
|
# Returns an ActiveRecord::Result instance.
|
59
62
|
def select_all(arel, name = nil, binds = [], preparable: nil)
|
60
63
|
arel = arel_from_relation(arel)
|
61
|
-
sql, binds = to_sql_and_binds(arel, binds)
|
62
|
-
|
63
|
-
if preparable.nil?
|
64
|
-
preparable = prepared_statements ? visitor.preparable : false
|
65
|
-
end
|
64
|
+
sql, binds, preparable = to_sql_and_binds(arel, binds, preparable)
|
66
65
|
|
67
66
|
if prepared_statements && preparable
|
68
67
|
select_prepared(sql, name, binds)
|
69
68
|
else
|
70
69
|
select(sql, name, binds)
|
71
70
|
end
|
71
|
+
rescue ::RangeError
|
72
|
+
ActiveRecord::Result.new([], [])
|
72
73
|
end
|
73
74
|
|
74
75
|
# Returns a record hash with the column names as keys and column values
|
@@ -153,6 +154,10 @@ module ActiveRecord
|
|
153
154
|
exec_query(sql, name)
|
154
155
|
end
|
155
156
|
|
157
|
+
def explain(arel, binds = []) # :nodoc:
|
158
|
+
raise NotImplementedError
|
159
|
+
end
|
160
|
+
|
156
161
|
# Executes an INSERT query and returns the new record's ID
|
157
162
|
#
|
158
163
|
# +id_value+ will be returned unless the value is +nil+, in
|
@@ -186,6 +191,8 @@ module ActiveRecord
|
|
186
191
|
end
|
187
192
|
|
188
193
|
def truncate_tables(*table_names) # :nodoc:
|
194
|
+
table_names -= [schema_migration.table_name, InternalMetadata.table_name]
|
195
|
+
|
189
196
|
return if table_names.empty?
|
190
197
|
|
191
198
|
with_multi_statements do
|
@@ -201,15 +208,30 @@ module ActiveRecord
|
|
201
208
|
#
|
202
209
|
# == Nested transactions support
|
203
210
|
#
|
211
|
+
# #transaction calls can be nested. By default, this makes all database
|
212
|
+
# statements in the nested transaction block become part of the parent
|
213
|
+
# transaction. For example, the following behavior may be surprising:
|
214
|
+
#
|
215
|
+
# ActiveRecord::Base.transaction do
|
216
|
+
# Post.create(title: 'first')
|
217
|
+
# ActiveRecord::Base.transaction do
|
218
|
+
# Post.create(title: 'second')
|
219
|
+
# raise ActiveRecord::Rollback
|
220
|
+
# end
|
221
|
+
# end
|
222
|
+
#
|
223
|
+
# This creates both "first" and "second" posts. Reason is the
|
224
|
+
# ActiveRecord::Rollback exception in the nested block does not issue a
|
225
|
+
# ROLLBACK. Since these exceptions are captured in transaction blocks,
|
226
|
+
# the parent block does not see it and the real transaction is committed.
|
227
|
+
#
|
204
228
|
# Most databases don't support true nested transactions. At the time of
|
205
229
|
# writing, the only database that supports true nested transactions that
|
206
230
|
# we're aware of, is MS-SQL.
|
207
231
|
#
|
208
232
|
# In order to get around this problem, #transaction will emulate the effect
|
209
233
|
# of nested transactions, by using savepoints:
|
210
|
-
# https://dev.mysql.com/doc/refman/
|
211
|
-
# Savepoints are supported by MySQL and PostgreSQL. SQLite3 version >= '3.6.8'
|
212
|
-
# supports savepoints.
|
234
|
+
# https://dev.mysql.com/doc/refman/en/savepoint.html.
|
213
235
|
#
|
214
236
|
# It is safe to call this method if a database transaction is already open,
|
215
237
|
# i.e. if #transaction is called within another #transaction block. In case
|
@@ -221,6 +243,24 @@ module ActiveRecord
|
|
221
243
|
# - However, if +:requires_new+ is set, the block will be wrapped in a
|
222
244
|
# database savepoint acting as a sub-transaction.
|
223
245
|
#
|
246
|
+
# In order to get a ROLLBACK for the nested transaction you may ask for a
|
247
|
+
# real sub-transaction by passing <tt>requires_new: true</tt>.
|
248
|
+
# If anything goes wrong, the database rolls back to the beginning of
|
249
|
+
# the sub-transaction without rolling back the parent transaction.
|
250
|
+
# If we add it to the previous example:
|
251
|
+
#
|
252
|
+
# ActiveRecord::Base.transaction do
|
253
|
+
# Post.create(title: 'first')
|
254
|
+
# ActiveRecord::Base.transaction(requires_new: true) do
|
255
|
+
# Post.create(title: 'second')
|
256
|
+
# raise ActiveRecord::Rollback
|
257
|
+
# end
|
258
|
+
# end
|
259
|
+
#
|
260
|
+
# only post with title "first" is created.
|
261
|
+
#
|
262
|
+
# See ActiveRecord::Transactions to learn more.
|
263
|
+
#
|
224
264
|
# === Caveats
|
225
265
|
#
|
226
266
|
# MySQL doesn't support DDL transactions. If you perform a DDL operation,
|
@@ -260,7 +300,7 @@ module ActiveRecord
|
|
260
300
|
# semantics of these different levels:
|
261
301
|
#
|
262
302
|
# * https://www.postgresql.org/docs/current/static/transaction-iso.html
|
263
|
-
# * https://dev.mysql.com/doc/refman/
|
303
|
+
# * https://dev.mysql.com/doc/refman/en/set-transaction.html
|
264
304
|
#
|
265
305
|
# An ActiveRecord::TransactionIsolationError will be raised if:
|
266
306
|
#
|
@@ -289,6 +329,13 @@ module ActiveRecord
|
|
289
329
|
:commit_transaction, :rollback_transaction, :materialize_transactions,
|
290
330
|
:disable_lazy_transactions!, :enable_lazy_transactions!, to: :transaction_manager
|
291
331
|
|
332
|
+
def mark_transaction_written_if_write(sql) # :nodoc:
|
333
|
+
transaction = current_transaction
|
334
|
+
if transaction.open?
|
335
|
+
transaction.written ||= write_query?(sql)
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
292
339
|
def transaction_open?
|
293
340
|
current_transaction.open?
|
294
341
|
end
|
@@ -299,12 +346,8 @@ module ActiveRecord
|
|
299
346
|
|
300
347
|
# Register a record with the current transaction so that its after_commit and after_rollback callbacks
|
301
348
|
# can be called.
|
302
|
-
def add_transaction_record(record)
|
303
|
-
current_transaction.add_record(record)
|
304
|
-
end
|
305
|
-
|
306
|
-
def transaction_state
|
307
|
-
current_transaction.state
|
349
|
+
def add_transaction_record(record, ensure_finalize = true)
|
350
|
+
current_transaction.add_record(record, ensure_finalize)
|
308
351
|
end
|
309
352
|
|
310
353
|
# Begins the transaction (and turns off auto-committing).
|
@@ -351,7 +394,7 @@ module ActiveRecord
|
|
351
394
|
end
|
352
395
|
|
353
396
|
# Inserts the given fixture into the table. Overridden in adapters that require
|
354
|
-
# something beyond a simple insert (
|
397
|
+
# something beyond a simple insert (e.g. Oracle).
|
355
398
|
# Most of adapters should implement `insert_fixtures_set` that leverages bulk SQL insert.
|
356
399
|
# We keep this method to provide fallback
|
357
400
|
# for databases like sqlite that do not support bulk inserts.
|
@@ -18,7 +18,7 @@ module ActiveRecord
|
|
18
18
|
method_names.each do |method_name|
|
19
19
|
base.class_eval <<-end_code, __FILE__, __LINE__ + 1
|
20
20
|
def #{method_name}(*)
|
21
|
-
ActiveRecord::Base.clear_query_caches_for_current_thread
|
21
|
+
ActiveRecord::Base.clear_query_caches_for_current_thread
|
22
22
|
super
|
23
23
|
end
|
24
24
|
end_code
|
@@ -96,11 +96,7 @@ module ActiveRecord
|
|
96
96
|
def select_all(arel, name = nil, binds = [], preparable: nil)
|
97
97
|
if @query_cache_enabled && !locked?(arel)
|
98
98
|
arel = arel_from_relation(arel)
|
99
|
-
sql, binds = to_sql_and_binds(arel, binds)
|
100
|
-
|
101
|
-
if preparable.nil?
|
102
|
-
preparable = prepared_statements ? visitor.preparable : false
|
103
|
-
end
|
99
|
+
sql, binds, preparable = to_sql_and_binds(arel, binds, preparable)
|
104
100
|
|
105
101
|
cache_sql(sql, name, binds) { super(sql, name, binds, preparable: preparable) }
|
106
102
|
else
|
@@ -133,7 +129,6 @@ module ActiveRecord
|
|
133
129
|
binds: binds,
|
134
130
|
type_casted_binds: -> { type_casted_binds(binds) },
|
135
131
|
name: name,
|
136
|
-
connection_id: object_id,
|
137
132
|
connection: self,
|
138
133
|
cached: true
|
139
134
|
}
|
@@ -9,10 +9,12 @@ module ActiveRecord
|
|
9
9
|
# Quotes the column value to help prevent
|
10
10
|
# {SQL injection attacks}[https://en.wikipedia.org/wiki/SQL_injection].
|
11
11
|
def quote(value)
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
12
|
+
if value.is_a?(Base)
|
13
|
+
ActiveSupport::Deprecation.warn(<<~MSG)
|
14
|
+
Passing an Active Record object to `quote` directly is deprecated
|
15
|
+
and will be no longer quoted as id value in Rails 6.2.
|
16
|
+
MSG
|
17
|
+
value = value.id_for_database
|
16
18
|
end
|
17
19
|
|
18
20
|
_quote(value)
|
@@ -22,16 +24,23 @@ module ActiveRecord
|
|
22
24
|
# SQLite does not understand dates, so this method will convert a Date
|
23
25
|
# to a String.
|
24
26
|
def type_cast(value, column = nil)
|
25
|
-
|
27
|
+
if value.is_a?(Base)
|
28
|
+
ActiveSupport::Deprecation.warn(<<~MSG)
|
29
|
+
Passing an Active Record object to `type_cast` directly is deprecated
|
30
|
+
and will be no longer type casted as id value in Rails 6.2.
|
31
|
+
MSG
|
32
|
+
value = value.id_for_database
|
33
|
+
end
|
26
34
|
|
27
35
|
if column
|
28
|
-
|
36
|
+
ActiveSupport::Deprecation.warn(<<~MSG)
|
37
|
+
Passing a column to `type_cast` is deprecated and will be removed in Rails 6.2.
|
38
|
+
MSG
|
39
|
+
type = lookup_cast_type_from_column(column)
|
40
|
+
value = type.serialize(value)
|
29
41
|
end
|
30
42
|
|
31
43
|
_type_cast(value)
|
32
|
-
rescue TypeError
|
33
|
-
to_type = column ? " to #{column.type}" : ""
|
34
|
-
raise TypeError, "can't cast #{value.class}#{to_type}"
|
35
44
|
end
|
36
45
|
|
37
46
|
# If you are having to call this function, you are likely doing something
|
@@ -43,16 +52,6 @@ module ActiveRecord
|
|
43
52
|
# represent the type doesn't sufficiently reflect the differences
|
44
53
|
# (varchar vs binary) for example. The type used to get this primitive
|
45
54
|
# should have been provided before reaching the connection adapter.
|
46
|
-
def type_cast_from_column(column, value) # :nodoc:
|
47
|
-
if column
|
48
|
-
type = lookup_cast_type_from_column(column)
|
49
|
-
type.serialize(value)
|
50
|
-
else
|
51
|
-
value
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
# See docs for #type_cast_from_column
|
56
55
|
def lookup_cast_type_from_column(column) # :nodoc:
|
57
56
|
lookup_cast_type(column.sql_type)
|
58
57
|
end
|
@@ -114,16 +113,16 @@ module ActiveRecord
|
|
114
113
|
# if the value is a Time responding to usec.
|
115
114
|
def quoted_date(value)
|
116
115
|
if value.acts_like?(:time)
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
value = value.
|
116
|
+
if ActiveRecord::Base.default_timezone == :utc
|
117
|
+
value = value.getutc if value.respond_to?(:getutc) && !value.utc?
|
118
|
+
else
|
119
|
+
value = value.getlocal if value.respond_to?(:getlocal)
|
121
120
|
end
|
122
121
|
end
|
123
122
|
|
124
123
|
result = value.to_s(:db)
|
125
124
|
if value.respond_to?(:usec) && value.usec > 0
|
126
|
-
"
|
125
|
+
result << "." << sprintf("%06d", value.usec)
|
127
126
|
else
|
128
127
|
result
|
129
128
|
end
|
@@ -162,7 +161,7 @@ module ActiveRecord
|
|
162
161
|
# table_name.column_name | function(one or no argument)
|
163
162
|
((?:\w+\.)?\w+) | \w+\((?:|\g<2>)\)
|
164
163
|
)
|
165
|
-
(?:\s+AS
|
164
|
+
(?:(?:\s+AS)?\s+\w+)?
|
166
165
|
)
|
167
166
|
(?:\s*,\s*\g<1>)*
|
168
167
|
\z
|
@@ -197,10 +196,17 @@ module ActiveRecord
|
|
197
196
|
|
198
197
|
private
|
199
198
|
def type_casted_binds(binds)
|
200
|
-
|
199
|
+
case binds.first
|
200
|
+
when Array
|
201
201
|
binds.map { |column, value| type_cast(value, column) }
|
202
202
|
else
|
203
|
-
binds.map
|
203
|
+
binds.map do |value|
|
204
|
+
if ActiveModel::Attribute === value
|
205
|
+
type_cast(value.value_for_database)
|
206
|
+
else
|
207
|
+
type_cast(value)
|
208
|
+
end
|
209
|
+
end
|
204
210
|
end
|
205
211
|
end
|
206
212
|
|
@@ -208,12 +214,6 @@ module ActiveRecord
|
|
208
214
|
type_map.lookup(sql_type)
|
209
215
|
end
|
210
216
|
|
211
|
-
def id_value_for_database(value)
|
212
|
-
if primary_key = value.class.primary_key
|
213
|
-
value.instance_variable_get(:@attributes)[primary_key].value_for_database
|
214
|
-
end
|
215
|
-
end
|
216
|
-
|
217
217
|
def _quote(value)
|
218
218
|
case value
|
219
219
|
when String, Symbol, ActiveSupport::Multibyte::Chars
|
@@ -243,7 +243,7 @@ module ActiveRecord
|
|
243
243
|
when nil, Numeric, String then value
|
244
244
|
when Type::Time::Value then quoted_time(value)
|
245
245
|
when Date, Time then quoted_date(value)
|
246
|
-
else raise TypeError
|
246
|
+
else raise TypeError, "can't cast #{value.class.name}"
|
247
247
|
end
|
248
248
|
end
|
249
249
|
end
|
@@ -8,15 +8,15 @@ module ActiveRecord
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def create_savepoint(name = current_savepoint_name)
|
11
|
-
execute("SAVEPOINT #{name}")
|
11
|
+
execute("SAVEPOINT #{name}", "TRANSACTION")
|
12
12
|
end
|
13
13
|
|
14
14
|
def exec_rollback_to_savepoint(name = current_savepoint_name)
|
15
|
-
execute("ROLLBACK TO SAVEPOINT #{name}")
|
15
|
+
execute("ROLLBACK TO SAVEPOINT #{name}", "TRANSACTION")
|
16
16
|
end
|
17
17
|
|
18
18
|
def release_savepoint(name = current_savepoint_name)
|
19
|
-
execute("RELEASE SAVEPOINT #{name}")
|
19
|
+
execute("RELEASE SAVEPOINT #{name}", "TRANSACTION")
|
20
20
|
end
|
21
21
|
end
|
22
22
|
end
|
@@ -2,151 +2,188 @@
|
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
4
|
module ConnectionAdapters
|
5
|
-
class
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
5
|
+
class SchemaCreation # :nodoc:
|
6
|
+
def initialize(conn)
|
7
|
+
@conn = conn
|
8
|
+
@cache = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def accept(o)
|
12
|
+
m = @cache[o.class] ||= "visit_#{o.class.name.split('::').last}"
|
13
|
+
send m, o
|
14
|
+
end
|
15
|
+
|
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?, :foreign_key_options,
|
18
|
+
:quoted_columns_for_index, :supports_partial_index?, :supports_check_constraints?, :check_constraint_options,
|
19
|
+
to: :@conn, private: true
|
20
|
+
|
21
|
+
private
|
22
|
+
def visit_AlterTable(o)
|
23
|
+
sql = +"ALTER TABLE #{quote_table_name(o.name)} "
|
24
|
+
sql << o.adds.map { |col| accept col }.join(" ")
|
25
|
+
sql << o.foreign_key_adds.map { |fk| visit_AddForeignKey fk }.join(" ")
|
26
|
+
sql << o.foreign_key_drops.map { |fk| visit_DropForeignKey fk }.join(" ")
|
27
|
+
sql << o.check_constraint_adds.map { |con| visit_AddCheckConstraint con }.join(" ")
|
28
|
+
sql << o.check_constraint_drops.map { |con| visit_DropCheckConstraint con }.join(" ")
|
29
|
+
end
|
30
|
+
|
31
|
+
def visit_ColumnDefinition(o)
|
32
|
+
o.sql_type = type_to_sql(o.type, **o.options)
|
33
|
+
column_sql = +"#{quote_column_name(o.name)} #{o.sql_type}"
|
34
|
+
add_column_options!(column_sql, column_options(o)) unless o.type == :primary_key
|
35
|
+
column_sql
|
10
36
|
end
|
11
37
|
|
12
|
-
def
|
13
|
-
|
14
|
-
send m, o
|
38
|
+
def visit_AddColumnDefinition(o)
|
39
|
+
+"ADD #{accept(o.column)}"
|
15
40
|
end
|
16
41
|
|
17
|
-
|
18
|
-
|
19
|
-
|
42
|
+
def visit_TableDefinition(o)
|
43
|
+
create_sql = +"CREATE#{table_modifier_in_create(o)} TABLE "
|
44
|
+
create_sql << "IF NOT EXISTS " if o.if_not_exists
|
45
|
+
create_sql << "#{quote_table_name(o.name)} "
|
20
46
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
sql << o.foreign_key_drops.map { |fk| visit_DropForeignKey fk }.join(" ")
|
47
|
+
statements = o.columns.map { |c| accept c }
|
48
|
+
statements << accept(o.primary_keys) if o.primary_keys
|
49
|
+
|
50
|
+
if supports_indexes_in_create?
|
51
|
+
statements.concat(o.indexes.map { |column_name, options| index_in_create(o.name, column_name, options) })
|
27
52
|
end
|
28
53
|
|
29
|
-
|
30
|
-
o.
|
31
|
-
column_sql = +"#{quote_column_name(o.name)} #{o.sql_type}"
|
32
|
-
add_column_options!(column_sql, column_options(o)) unless o.type == :primary_key
|
33
|
-
column_sql
|
54
|
+
if supports_foreign_keys?
|
55
|
+
statements.concat(o.foreign_keys.map { |to_table, options| foreign_key_in_create(o.name, to_table, options) })
|
34
56
|
end
|
35
57
|
|
36
|
-
|
37
|
-
|
58
|
+
if supports_check_constraints?
|
59
|
+
statements.concat(o.check_constraints.map { |expression, options| check_constraint_in_create(o.name, expression, options) })
|
38
60
|
end
|
39
61
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
62
|
+
create_sql << "(#{statements.join(', ')})" if statements.present?
|
63
|
+
add_table_options!(create_sql, o)
|
64
|
+
create_sql << " AS #{to_sql(o.as)}" if o.as
|
65
|
+
create_sql
|
66
|
+
end
|
44
67
|
|
45
|
-
|
46
|
-
|
68
|
+
def visit_PrimaryKeyDefinition(o)
|
69
|
+
"PRIMARY KEY (#{o.name.map { |name| quote_column_name(name) }.join(', ')})"
|
70
|
+
end
|
47
71
|
|
48
|
-
|
49
|
-
|
50
|
-
|
72
|
+
def visit_ForeignKeyDefinition(o)
|
73
|
+
sql = +<<~SQL
|
74
|
+
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)})
|
77
|
+
SQL
|
78
|
+
sql << " #{action_sql('DELETE', o.on_delete)}" if o.on_delete
|
79
|
+
sql << " #{action_sql('UPDATE', o.on_update)}" if o.on_update
|
80
|
+
sql
|
81
|
+
end
|
51
82
|
|
52
|
-
|
53
|
-
|
54
|
-
|
83
|
+
def visit_AddForeignKey(o)
|
84
|
+
"ADD #{accept(o)}"
|
85
|
+
end
|
55
86
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
create_sql
|
60
|
-
end
|
87
|
+
def visit_DropForeignKey(name)
|
88
|
+
"DROP CONSTRAINT #{quote_column_name(name)}"
|
89
|
+
end
|
61
90
|
|
62
|
-
|
63
|
-
|
64
|
-
|
91
|
+
def visit_CreateIndexDefinition(o)
|
92
|
+
index = o.index
|
93
|
+
|
94
|
+
sql = ["CREATE"]
|
95
|
+
sql << "UNIQUE" if index.unique
|
96
|
+
sql << "INDEX"
|
97
|
+
sql << "IF NOT EXISTS" if o.if_not_exists
|
98
|
+
sql << o.algorithm if o.algorithm
|
99
|
+
sql << index.type if index.type
|
100
|
+
sql << "#{quote_column_name(index.name)} ON #{quote_table_name(index.table)}"
|
101
|
+
sql << "USING #{index.using}" if supports_index_using? && index.using
|
102
|
+
sql << "(#{quoted_columns(index)})"
|
103
|
+
sql << "WHERE #{index.where}" if supports_partial_index? && index.where
|
104
|
+
|
105
|
+
sql.join(" ")
|
106
|
+
end
|
65
107
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
FOREIGN KEY (#{quote_column_name(o.column)})
|
70
|
-
REFERENCES #{quote_table_name(o.to_table)} (#{quote_column_name(o.primary_key)})
|
71
|
-
SQL
|
72
|
-
sql << " #{action_sql('DELETE', o.on_delete)}" if o.on_delete
|
73
|
-
sql << " #{action_sql('UPDATE', o.on_update)}" if o.on_update
|
74
|
-
sql
|
75
|
-
end
|
108
|
+
def visit_CheckConstraintDefinition(o)
|
109
|
+
"CONSTRAINT #{o.name} CHECK (#{o.expression})"
|
110
|
+
end
|
76
111
|
|
77
|
-
|
78
|
-
|
79
|
-
|
112
|
+
def visit_AddCheckConstraint(o)
|
113
|
+
"ADD #{accept(o)}"
|
114
|
+
end
|
80
115
|
|
81
|
-
|
82
|
-
|
83
|
-
|
116
|
+
def visit_DropCheckConstraint(name)
|
117
|
+
"DROP CONSTRAINT #{quote_column_name(name)}"
|
118
|
+
end
|
84
119
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
table_options[:options] = o.options
|
89
|
-
table_options
|
90
|
-
end
|
120
|
+
def quoted_columns(o)
|
121
|
+
String === o.columns ? o.columns : quoted_columns_for_index(o.columns, o.column_options)
|
122
|
+
end
|
91
123
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
end
|
96
|
-
create_sql
|
97
|
-
end
|
124
|
+
def supports_index_using?
|
125
|
+
true
|
126
|
+
end
|
98
127
|
|
99
|
-
|
100
|
-
|
101
|
-
|
128
|
+
def add_table_options!(create_sql, o)
|
129
|
+
create_sql << " #{o.options}" if o.options
|
130
|
+
create_sql
|
131
|
+
end
|
102
132
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
if options[:null] == false
|
107
|
-
sql << " NOT NULL"
|
108
|
-
end
|
109
|
-
if options[:auto_increment] == true
|
110
|
-
sql << " AUTO_INCREMENT"
|
111
|
-
end
|
112
|
-
if options[:primary_key] == true
|
113
|
-
sql << " PRIMARY KEY"
|
114
|
-
end
|
115
|
-
sql
|
116
|
-
end
|
133
|
+
def column_options(o)
|
134
|
+
o.options.merge(column: o)
|
135
|
+
end
|
117
136
|
|
118
|
-
|
119
|
-
|
120
|
-
|
137
|
+
def add_column_options!(sql, options)
|
138
|
+
sql << " DEFAULT #{quote_default_expression(options[:default], options[:column])}" if options_include_default?(options)
|
139
|
+
# must explicitly check for :null to allow change_column to work on migrations
|
140
|
+
if options[:null] == false
|
141
|
+
sql << " NOT NULL"
|
121
142
|
end
|
122
|
-
|
123
|
-
|
124
|
-
def table_modifier_in_create(o)
|
125
|
-
" TEMPORARY" if o.temporary
|
143
|
+
if options[:auto_increment] == true
|
144
|
+
sql << " AUTO_INCREMENT"
|
126
145
|
end
|
127
|
-
|
128
|
-
|
129
|
-
prefix = ActiveRecord::Base.table_name_prefix
|
130
|
-
suffix = ActiveRecord::Base.table_name_suffix
|
131
|
-
to_table = "#{prefix}#{to_table}#{suffix}"
|
132
|
-
options = foreign_key_options(from_table, to_table, options)
|
133
|
-
accept ForeignKeyDefinition.new(from_table, to_table, options)
|
146
|
+
if options[:primary_key] == true
|
147
|
+
sql << " PRIMARY KEY"
|
134
148
|
end
|
149
|
+
sql
|
150
|
+
end
|
135
151
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
152
|
+
def to_sql(sql)
|
153
|
+
sql = sql.to_sql if sql.respond_to?(:to_sql)
|
154
|
+
sql
|
155
|
+
end
|
156
|
+
|
157
|
+
# Returns any SQL string to go between CREATE and TABLE. May be nil.
|
158
|
+
def table_modifier_in_create(o)
|
159
|
+
" TEMPORARY" if o.temporary
|
160
|
+
end
|
161
|
+
|
162
|
+
def foreign_key_in_create(from_table, to_table, options)
|
163
|
+
prefix = ActiveRecord::Base.table_name_prefix
|
164
|
+
suffix = ActiveRecord::Base.table_name_suffix
|
165
|
+
to_table = "#{prefix}#{to_table}#{suffix}"
|
166
|
+
options = foreign_key_options(from_table, to_table, options)
|
167
|
+
accept ForeignKeyDefinition.new(from_table, to_table, options)
|
168
|
+
end
|
169
|
+
|
170
|
+
def check_constraint_in_create(table_name, expression, options)
|
171
|
+
options = check_constraint_options(table_name, expression, options)
|
172
|
+
accept CheckConstraintDefinition.new(table_name, expression, options)
|
173
|
+
end
|
174
|
+
|
175
|
+
def action_sql(action, dependency)
|
176
|
+
case dependency
|
177
|
+
when :nullify then "ON #{action} SET NULL"
|
178
|
+
when :cascade then "ON #{action} CASCADE"
|
179
|
+
when :restrict then "ON #{action} RESTRICT"
|
180
|
+
else
|
181
|
+
raise ArgumentError, <<~MSG
|
182
|
+
'#{dependency}' is not supported for :on_update or :on_delete.
|
183
|
+
Supported values are: :nullify, :cascade, :restrict
|
184
|
+
MSG
|
147
185
|
end
|
148
|
-
|
186
|
+
end
|
149
187
|
end
|
150
|
-
SchemaCreation = AbstractAdapter::SchemaCreation # :nodoc:
|
151
188
|
end
|
152
189
|
end
|