activerecord 6.0.1 → 6.1.0
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 +843 -626
- data/MIT-LICENSE +1 -1
- data/README.rdoc +3 -3
- data/lib/active_record/aggregations.rb +1 -2
- data/lib/active_record/association_relation.rb +18 -17
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +49 -37
- data/lib/active_record/associations/association_scope.rb +17 -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 -3
- 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 +25 -8
- data/lib/active_record/associations/collection_proxy.rb +14 -7
- data/lib/active_record/associations/foreign_association.rb +13 -0
- data/lib/active_record/associations/has_many_association.rb +24 -3
- 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 +36 -14
- data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
- data/lib/active_record/associations/join_dependency.rb +73 -42
- data/lib/active_record/associations/preloader/association.rb +51 -25
- data/lib/active_record/associations/preloader/through_association.rb +2 -2
- data/lib/active_record/associations/preloader.rb +12 -7
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +115 -12
- data/lib/active_record/attribute_assignment.rb +10 -9
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -10
- data/lib/active_record/attribute_methods/dirty.rb +3 -13
- data/lib/active_record/attribute_methods/primary_key.rb +6 -4
- data/lib/active_record/attribute_methods/query.rb +3 -6
- data/lib/active_record/attribute_methods/read.rb +8 -12
- data/lib/active_record/attribute_methods/serialization.rb +11 -6
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
- data/lib/active_record/attribute_methods/write.rb +12 -21
- data/lib/active_record/attribute_methods.rb +64 -54
- data/lib/active_record/attributes.rb +32 -8
- data/lib/active_record/autosave_association.rb +56 -41
- data/lib/active_record/base.rb +2 -14
- data/lib/active_record/callbacks.rb +153 -24
- data/lib/active_record/coders/yaml_column.rb +1 -2
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +190 -136
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +82 -37
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -8
- 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 +152 -116
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +137 -52
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +263 -107
- data/lib/active_record/connection_adapters/abstract/transaction.rb +82 -35
- data/lib/active_record/connection_adapters/abstract_adapter.rb +60 -73
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +136 -111
- 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/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +28 -36
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
- data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -7
- 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 +17 -13
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -13
- 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 +19 -56
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +0 -1
- 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 +10 -2
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -3
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -3
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +24 -6
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -2
- 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 +2 -2
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +7 -3
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +72 -54
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +77 -57
- 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 +36 -12
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +38 -5
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +57 -57
- data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
- data/lib/active_record/connection_adapters.rb +50 -0
- data/lib/active_record/connection_handling.rb +210 -87
- data/lib/active_record/core.rb +229 -65
- data/lib/active_record/counter_cache.rb +4 -1
- 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 -41
- 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/dynamic_matchers.rb +2 -3
- data/lib/active_record/enum.rb +40 -16
- data/lib/active_record/errors.rb +47 -12
- data/lib/active_record/explain.rb +9 -5
- 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 -3
- data/lib/active_record/fixture_set/table_rows.rb +0 -1
- data/lib/active_record/fixtures.rb +54 -11
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +40 -21
- data/lib/active_record/insert_all.rb +38 -9
- data/lib/active_record/integration.rb +3 -5
- data/lib/active_record/internal_metadata.rb +16 -7
- data/lib/active_record/legacy_yaml_adapter.rb +7 -3
- data/lib/active_record/locking/optimistic.rb +22 -17
- data/lib/active_record/locking/pessimistic.rb +6 -2
- data/lib/active_record/log_subscriber.rb +27 -9
- data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +6 -2
- data/lib/active_record/middleware/database_selector.rb +4 -2
- data/lib/active_record/migration/command_recorder.rb +53 -45
- data/lib/active_record/migration/compatibility.rb +70 -20
- data/lib/active_record/migration/join_table.rb +0 -1
- data/lib/active_record/migration.rb +114 -84
- data/lib/active_record/model_schema.rb +117 -15
- data/lib/active_record/nested_attributes.rb +2 -5
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/null_relation.rb +0 -1
- data/lib/active_record/persistence.rb +50 -46
- data/lib/active_record/query_cache.rb +15 -5
- data/lib/active_record/querying.rb +12 -7
- data/lib/active_record/railtie.rb +65 -45
- data/lib/active_record/railties/databases.rake +267 -93
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +77 -63
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/batches.rb +38 -32
- data/lib/active_record/relation/calculations.rb +102 -45
- data/lib/active_record/relation/delegation.rb +9 -7
- data/lib/active_record/relation/finder_methods.rb +45 -16
- data/lib/active_record/relation/from_clause.rb +5 -1
- data/lib/active_record/relation/merger.rb +27 -26
- data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +4 -5
- 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 +55 -35
- data/lib/active_record/relation/query_methods.rb +335 -187
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +8 -8
- data/lib/active_record/relation/where_clause.rb +104 -58
- data/lib/active_record/relation.rb +108 -68
- data/lib/active_record/result.rb +41 -34
- 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 +2 -8
- data/lib/active_record/scoping/default.rb +0 -1
- data/lib/active_record/scoping/named.rb +7 -18
- data/lib/active_record/scoping.rb +0 -1
- 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 +3 -3
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +39 -36
- data/lib/active_record/tasks/database_tasks.rb +139 -113
- data/lib/active_record/tasks/mysql_database_tasks.rb +34 -36
- data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -27
- data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -10
- data/lib/active_record/test_databases.rb +5 -4
- data/lib/active_record/test_fixtures.rb +38 -16
- data/lib/active_record/timestamp.rb +4 -7
- data/lib/active_record/touch_later.rb +20 -21
- data/lib/active_record/transactions.rb +21 -70
- data/lib/active_record/type/adapter_specific_registry.rb +2 -5
- data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
- data/lib/active_record/type/serialized.rb +6 -3
- data/lib/active_record/type/time.rb +10 -0
- data/lib/active_record/type/type_map.rb +0 -1
- data/lib/active_record/type/unsigned_integer.rb +0 -1
- data/lib/active_record/type.rb +8 -2
- 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 -2
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +24 -4
- data/lib/active_record/validations.rb +3 -3
- data/lib/active_record.rb +7 -13
- 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 +17 -24
- data/lib/arel/select_manager.rb +1 -2
- data/lib/arel/table.rb +13 -5
- data/lib/arel/visitors/dot.rb +14 -3
- data/lib/arel/visitors/mysql.rb +11 -1
- data/lib/arel/visitors/postgresql.rb +15 -5
- data/lib/arel/visitors/sqlite.rb +0 -1
- data/lib/arel/visitors/to_sql.rb +89 -79
- data/lib/arel/visitors/visitor.rb +0 -1
- data/lib/arel/visitors.rb +0 -7
- data/lib/arel.rb +5 -9
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
- 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 +4 -4
- data/lib/rails/generators/active_record/migration.rb +6 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +38 -2
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- metadata +26 -26
- data/lib/active_record/attribute_decorators.rb +0 -90
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -297
- 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 -204
- data/lib/arel/visitors/ibm_db.rb +0 -34
- data/lib/arel/visitors/informix.rb +0 -62
- data/lib/arel/visitors/mssql.rb +0 -157
- data/lib/arel/visitors/oracle.rb +0 -159
- data/lib/arel/visitors/oracle12.rb +0 -66
- data/lib/arel/visitors/where_sql.rb +0 -23
@@ -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
|
@@ -182,17 +187,18 @@ module ActiveRecord
|
|
182
187
|
|
183
188
|
# Executes the truncate statement.
|
184
189
|
def truncate(table_name, name = nil)
|
185
|
-
execute(
|
190
|
+
execute(build_truncate_statement(table_name), name)
|
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
|
192
199
|
disable_referential_integrity do
|
193
|
-
|
194
|
-
|
195
|
-
end
|
200
|
+
statements = build_truncate_statements(table_names)
|
201
|
+
execute_batch(statements, "Truncate Tables")
|
196
202
|
end
|
197
203
|
end
|
198
204
|
end
|
@@ -202,15 +208,30 @@ module ActiveRecord
|
|
202
208
|
#
|
203
209
|
# == Nested transactions support
|
204
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
|
+
#
|
205
228
|
# Most databases don't support true nested transactions. At the time of
|
206
229
|
# writing, the only database that supports true nested transactions that
|
207
230
|
# we're aware of, is MS-SQL.
|
208
231
|
#
|
209
232
|
# In order to get around this problem, #transaction will emulate the effect
|
210
233
|
# of nested transactions, by using savepoints:
|
211
|
-
# https://dev.mysql.com/doc/refman/
|
212
|
-
# Savepoints are supported by MySQL and PostgreSQL. SQLite3 version >= '3.6.8'
|
213
|
-
# supports savepoints.
|
234
|
+
# https://dev.mysql.com/doc/refman/en/savepoint.html.
|
214
235
|
#
|
215
236
|
# It is safe to call this method if a database transaction is already open,
|
216
237
|
# i.e. if #transaction is called within another #transaction block. In case
|
@@ -222,6 +243,24 @@ module ActiveRecord
|
|
222
243
|
# - However, if +:requires_new+ is set, the block will be wrapped in a
|
223
244
|
# database savepoint acting as a sub-transaction.
|
224
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
|
+
#
|
225
264
|
# === Caveats
|
226
265
|
#
|
227
266
|
# MySQL doesn't support DDL transactions. If you perform a DDL operation,
|
@@ -261,7 +300,7 @@ module ActiveRecord
|
|
261
300
|
# semantics of these different levels:
|
262
301
|
#
|
263
302
|
# * https://www.postgresql.org/docs/current/static/transaction-iso.html
|
264
|
-
# * https://dev.mysql.com/doc/refman/
|
303
|
+
# * https://dev.mysql.com/doc/refman/en/set-transaction.html
|
265
304
|
#
|
266
305
|
# An ActiveRecord::TransactionIsolationError will be raised if:
|
267
306
|
#
|
@@ -290,6 +329,13 @@ module ActiveRecord
|
|
290
329
|
:commit_transaction, :rollback_transaction, :materialize_transactions,
|
291
330
|
:disable_lazy_transactions!, :enable_lazy_transactions!, to: :transaction_manager
|
292
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
|
+
|
293
339
|
def transaction_open?
|
294
340
|
current_transaction.open?
|
295
341
|
end
|
@@ -300,12 +346,8 @@ module ActiveRecord
|
|
300
346
|
|
301
347
|
# Register a record with the current transaction so that its after_commit and after_rollback callbacks
|
302
348
|
# can be called.
|
303
|
-
def add_transaction_record(record)
|
304
|
-
current_transaction.add_record(record)
|
305
|
-
end
|
306
|
-
|
307
|
-
def transaction_state
|
308
|
-
current_transaction.state
|
349
|
+
def add_transaction_record(record, ensure_finalize = true)
|
350
|
+
current_transaction.add_record(record, ensure_finalize)
|
309
351
|
end
|
310
352
|
|
311
353
|
# Begins the transaction (and turns off auto-committing).
|
@@ -352,7 +394,7 @@ module ActiveRecord
|
|
352
394
|
end
|
353
395
|
|
354
396
|
# Inserts the given fixture into the table. Overridden in adapters that require
|
355
|
-
# something beyond a simple insert (
|
397
|
+
# something beyond a simple insert (e.g. Oracle).
|
356
398
|
# Most of adapters should implement `insert_fixtures_set` that leverages bulk SQL insert.
|
357
399
|
# We keep this method to provide fallback
|
358
400
|
# for databases like sqlite that do not support bulk inserts.
|
@@ -363,14 +405,12 @@ module ActiveRecord
|
|
363
405
|
def insert_fixtures_set(fixture_set, tables_to_delete = [])
|
364
406
|
fixture_inserts = build_fixture_statements(fixture_set)
|
365
407
|
table_deletes = tables_to_delete.map { |table| "DELETE FROM #{quote_table_name(table)}" }
|
366
|
-
|
408
|
+
statements = table_deletes + fixture_inserts
|
367
409
|
|
368
410
|
with_multi_statements do
|
369
411
|
disable_referential_integrity do
|
370
412
|
transaction(requires_new: true) do
|
371
|
-
|
372
|
-
execute_batch(sql, "Fixtures Load")
|
373
|
-
end
|
413
|
+
execute_batch(statements, "Fixtures Load")
|
374
414
|
end
|
375
415
|
end
|
376
416
|
end
|
@@ -406,8 +446,10 @@ module ActiveRecord
|
|
406
446
|
end
|
407
447
|
|
408
448
|
private
|
409
|
-
def execute_batch(
|
410
|
-
|
449
|
+
def execute_batch(statements, name = nil)
|
450
|
+
statements.each do |statement|
|
451
|
+
execute(statement, name)
|
452
|
+
end
|
411
453
|
end
|
412
454
|
|
413
455
|
DEFAULT_INSERT_VALUE = Arel.sql("DEFAULT").freeze
|
@@ -457,7 +499,7 @@ module ActiveRecord
|
|
457
499
|
end
|
458
500
|
|
459
501
|
manager.values = manager.create_values_list(values_list)
|
460
|
-
manager.
|
502
|
+
visitor.compile(manager.ast)
|
461
503
|
end
|
462
504
|
|
463
505
|
def build_fixture_statements(fixture_set)
|
@@ -467,11 +509,14 @@ module ActiveRecord
|
|
467
509
|
end.compact
|
468
510
|
end
|
469
511
|
|
470
|
-
def
|
471
|
-
|
472
|
-
|
512
|
+
def build_truncate_statement(table_name)
|
513
|
+
"TRUNCATE TABLE #{quote_table_name(table_name)}"
|
514
|
+
end
|
515
|
+
|
516
|
+
def build_truncate_statements(table_names)
|
517
|
+
table_names.map do |table_name|
|
518
|
+
build_truncate_statement(table_name)
|
473
519
|
end
|
474
|
-
combine_multi_statements(truncate_tables)
|
475
520
|
end
|
476
521
|
|
477
522
|
def with_multi_statements
|
@@ -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
|
@@ -109,7 +105,6 @@ module ActiveRecord
|
|
109
105
|
end
|
110
106
|
|
111
107
|
private
|
112
|
-
|
113
108
|
def cache_sql(sql, name, binds)
|
114
109
|
@lock.synchronize do
|
115
110
|
result =
|
@@ -134,7 +129,6 @@ module ActiveRecord
|
|
134
129
|
binds: binds,
|
135
130
|
type_casted_binds: -> { type_casted_binds(binds) },
|
136
131
|
name: name,
|
137
|
-
connection_id: object_id,
|
138
132
|
connection: self,
|
139
133
|
cached: true
|
140
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
|