activerecord 7.0.8.1 → 7.2.2.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +642 -1925
- data/MIT-LICENSE +1 -1
- data/README.rdoc +29 -29
- data/examples/performance.rb +2 -2
- data/lib/active_record/aggregations.rb +16 -13
- data/lib/active_record/association_relation.rb +2 -2
- data/lib/active_record/associations/alias_tracker.rb +25 -19
- data/lib/active_record/associations/association.rb +35 -12
- data/lib/active_record/associations/association_scope.rb +16 -9
- data/lib/active_record/associations/belongs_to_association.rb +23 -8
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
- data/lib/active_record/associations/builder/association.rb +3 -3
- data/lib/active_record/associations/builder/belongs_to.rb +22 -8
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -7
- data/lib/active_record/associations/builder/has_many.rb +3 -4
- data/lib/active_record/associations/builder/has_one.rb +3 -4
- data/lib/active_record/associations/builder/singular_association.rb +4 -0
- data/lib/active_record/associations/collection_association.rb +26 -14
- data/lib/active_record/associations/collection_proxy.rb +29 -11
- data/lib/active_record/associations/errors.rb +265 -0
- data/lib/active_record/associations/foreign_association.rb +10 -3
- data/lib/active_record/associations/has_many_association.rb +21 -14
- data/lib/active_record/associations/has_many_through_association.rb +17 -7
- data/lib/active_record/associations/has_one_association.rb +10 -3
- data/lib/active_record/associations/join_dependency/join_association.rb +30 -27
- data/lib/active_record/associations/join_dependency.rb +10 -10
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +33 -8
- data/lib/active_record/associations/preloader/branch.rb +7 -1
- data/lib/active_record/associations/preloader/through_association.rb +1 -3
- data/lib/active_record/associations/preloader.rb +13 -10
- data/lib/active_record/associations/singular_association.rb +7 -1
- data/lib/active_record/associations/through_association.rb +22 -11
- data/lib/active_record/associations.rb +354 -485
- data/lib/active_record/attribute_assignment.rb +0 -4
- data/lib/active_record/attribute_methods/before_type_cast.rb +17 -0
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/dirty.rb +53 -35
- data/lib/active_record/attribute_methods/primary_key.rb +45 -25
- data/lib/active_record/attribute_methods/query.rb +28 -16
- data/lib/active_record/attribute_methods/read.rb +8 -7
- data/lib/active_record/attribute_methods/serialization.rb +131 -32
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +11 -6
- data/lib/active_record/attribute_methods/write.rb +6 -6
- data/lib/active_record/attribute_methods.rb +148 -33
- data/lib/active_record/attributes.rb +64 -50
- data/lib/active_record/autosave_association.rb +69 -37
- data/lib/active_record/base.rb +9 -5
- data/lib/active_record/callbacks.rb +11 -25
- data/lib/active_record/coders/column_serializer.rb +61 -0
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +70 -42
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +123 -131
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +4 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +323 -88
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +160 -45
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +217 -63
- data/lib/active_record/connection_adapters/abstract/quoting.rb +72 -63
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +18 -4
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +137 -11
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +307 -129
- data/lib/active_record/connection_adapters/abstract/transaction.rb +367 -75
- data/lib/active_record/connection_adapters/abstract_adapter.rb +510 -111
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +278 -125
- data/lib/active_record/connection_adapters/column.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +26 -139
- data/lib/active_record/connection_adapters/mysql/quoting.rb +53 -54
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +6 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +25 -13
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +101 -68
- data/lib/active_record/connection_adapters/pool_config.rb +20 -10
- data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +14 -3
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +100 -43
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +11 -2
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +65 -61
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +3 -9
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -6
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +151 -2
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +53 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +370 -63
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +367 -201
- data/lib/active_record/connection_adapters/schema_cache.rb +302 -79
- data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +60 -43
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +45 -46
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +14 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +50 -8
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +290 -110
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +229 -0
- data/lib/active_record/connection_adapters.rb +124 -1
- data/lib/active_record/connection_handling.rb +96 -104
- data/lib/active_record/core.rb +251 -176
- data/lib/active_record/counter_cache.rb +68 -34
- data/lib/active_record/database_configurations/connection_url_resolver.rb +8 -3
- data/lib/active_record/database_configurations/database_config.rb +26 -5
- data/lib/active_record/database_configurations/hash_config.rb +52 -34
- data/lib/active_record/database_configurations/url_config.rb +37 -12
- data/lib/active_record/database_configurations.rb +87 -34
- data/lib/active_record/delegated_type.rb +39 -10
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +3 -1
- data/lib/active_record/dynamic_matchers.rb +2 -2
- data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +4 -1
- data/lib/active_record/encryption/config.rb +25 -1
- data/lib/active_record/encryption/configurable.rb +12 -19
- data/lib/active_record/encryption/context.rb +10 -3
- data/lib/active_record/encryption/contexts.rb +5 -1
- data/lib/active_record/encryption/derived_secret_key_provider.rb +8 -2
- data/lib/active_record/encryption/encryptable_record.rb +45 -21
- data/lib/active_record/encryption/encrypted_attribute_type.rb +47 -12
- data/lib/active_record/encryption/encryptor.rb +18 -3
- data/lib/active_record/encryption/extended_deterministic_queries.rb +66 -69
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +3 -3
- data/lib/active_record/encryption/key_generator.rb +12 -1
- data/lib/active_record/encryption/key_provider.rb +1 -1
- data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
- data/lib/active_record/encryption/message_serializer.rb +6 -0
- data/lib/active_record/encryption/null_encryptor.rb +4 -0
- data/lib/active_record/encryption/properties.rb +3 -3
- data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
- data/lib/active_record/encryption/scheme.rb +22 -21
- data/lib/active_record/encryption.rb +3 -0
- data/lib/active_record/enum.rb +129 -28
- data/lib/active_record/errors.rb +151 -31
- data/lib/active_record/explain.rb +21 -12
- data/lib/active_record/fixture_set/model_metadata.rb +14 -4
- data/lib/active_record/fixture_set/render_context.rb +2 -0
- data/lib/active_record/fixture_set/table_row.rb +29 -8
- data/lib/active_record/fixtures.rb +167 -97
- data/lib/active_record/future_result.rb +47 -8
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +34 -18
- data/lib/active_record/insert_all.rb +72 -22
- data/lib/active_record/integration.rb +11 -8
- data/lib/active_record/internal_metadata.rb +124 -20
- data/lib/active_record/locking/optimistic.rb +8 -7
- data/lib/active_record/locking/pessimistic.rb +5 -2
- data/lib/active_record/log_subscriber.rb +18 -22
- data/lib/active_record/marshalling.rb +59 -0
- data/lib/active_record/message_pack.rb +124 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +4 -0
- data/lib/active_record/middleware/database_selector.rb +6 -8
- data/lib/active_record/middleware/shard_selector.rb +3 -1
- data/lib/active_record/migration/command_recorder.rb +106 -8
- data/lib/active_record/migration/compatibility.rb +147 -5
- data/lib/active_record/migration/default_strategy.rb +22 -0
- data/lib/active_record/migration/execution_strategy.rb +19 -0
- data/lib/active_record/migration/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +234 -117
- data/lib/active_record/model_schema.rb +90 -102
- data/lib/active_record/nested_attributes.rb +48 -11
- data/lib/active_record/normalization.rb +163 -0
- data/lib/active_record/persistence.rb +168 -339
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +18 -25
- data/lib/active_record/query_logs.rb +92 -52
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +33 -8
- data/lib/active_record/railtie.rb +129 -85
- data/lib/active_record/railties/controller_runtime.rb +22 -7
- data/lib/active_record/railties/databases.rake +145 -154
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +32 -5
- data/lib/active_record/reflection.rb +267 -69
- data/lib/active_record/relation/batches/batch_enumerator.rb +20 -5
- data/lib/active_record/relation/batches.rb +198 -63
- data/lib/active_record/relation/calculations.rb +250 -93
- data/lib/active_record/relation/delegation.rb +30 -19
- data/lib/active_record/relation/finder_methods.rb +93 -18
- data/lib/active_record/relation/merger.rb +6 -6
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +18 -3
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -7
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
- data/lib/active_record/relation/predicate_builder.rb +28 -16
- data/lib/active_record/relation/query_attribute.rb +2 -1
- data/lib/active_record/relation/query_methods.rb +576 -107
- data/lib/active_record/relation/record_fetch_warning.rb +3 -0
- data/lib/active_record/relation/spawn_methods.rb +5 -4
- data/lib/active_record/relation/where_clause.rb +7 -19
- data/lib/active_record/relation.rb +580 -90
- data/lib/active_record/result.rb +49 -48
- data/lib/active_record/runtime_registry.rb +63 -1
- data/lib/active_record/sanitization.rb +70 -25
- data/lib/active_record/schema.rb +8 -7
- data/lib/active_record/schema_dumper.rb +63 -14
- data/lib/active_record/schema_migration.rb +75 -24
- data/lib/active_record/scoping/default.rb +15 -5
- data/lib/active_record/scoping/named.rb +3 -2
- data/lib/active_record/scoping.rb +2 -1
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +21 -3
- data/lib/active_record/signed_id.rb +27 -6
- data/lib/active_record/statement_cache.rb +7 -7
- data/lib/active_record/store.rb +8 -8
- data/lib/active_record/suppressor.rb +3 -1
- data/lib/active_record/table_metadata.rb +1 -1
- data/lib/active_record/tasks/database_tasks.rb +190 -118
- data/lib/active_record/tasks/mysql_database_tasks.rb +15 -6
- data/lib/active_record/tasks/postgresql_database_tasks.rb +16 -13
- data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -7
- data/lib/active_record/test_fixtures.rb +170 -155
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +31 -17
- data/lib/active_record/token_for.rb +123 -0
- data/lib/active_record/touch_later.rb +12 -7
- data/lib/active_record/transaction.rb +132 -0
- data/lib/active_record/transactions.rb +106 -24
- data/lib/active_record/translation.rb +0 -2
- data/lib/active_record/type/adapter_specific_registry.rb +1 -8
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/serialized.rb +1 -3
- data/lib/active_record/type/time.rb +4 -0
- data/lib/active_record/type_caster/connection.rb +4 -4
- data/lib/active_record/validations/absence.rb +1 -1
- data/lib/active_record/validations/associated.rb +9 -3
- data/lib/active_record/validations/numericality.rb +5 -4
- data/lib/active_record/validations/presence.rb +5 -28
- data/lib/active_record/validations/uniqueness.rb +61 -11
- data/lib/active_record/validations.rb +12 -5
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +247 -33
- data/lib/arel/alias_predication.rb +1 -1
- data/lib/arel/collectors/bind.rb +2 -0
- data/lib/arel/collectors/composite.rb +7 -0
- data/lib/arel/collectors/sql_string.rb +1 -1
- data/lib/arel/collectors/substitute_binds.rb +1 -1
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/nodes/binary.rb +6 -7
- data/lib/arel/nodes/bound_sql_literal.rb +65 -0
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/homogeneous_in.rb +1 -9
- data/lib/arel/nodes/leading_join.rb +8 -0
- data/lib/arel/nodes/{and.rb → nary.rb} +5 -2
- data/lib/arel/nodes/node.rb +115 -5
- data/lib/arel/nodes/sql_literal.rb +13 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes.rb +6 -2
- data/lib/arel/predications.rb +3 -1
- data/lib/arel/select_manager.rb +1 -1
- data/lib/arel/table.rb +9 -5
- data/lib/arel/tree_manager.rb +8 -3
- data/lib/arel/update_manager.rb +2 -1
- data/lib/arel/visitors/dot.rb +1 -0
- data/lib/arel/visitors/mysql.rb +17 -5
- data/lib/arel/visitors/postgresql.rb +1 -12
- data/lib/arel/visitors/sqlite.rb +25 -0
- data/lib/arel/visitors/to_sql.rb +112 -34
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +21 -3
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
- data/lib/rails/generators/active_record/migration.rb +3 -1
- data/lib/rails/generators/active_record/model/USAGE +113 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
- metadata +59 -17
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -63
@@ -14,18 +14,24 @@ module ActiveRecord
|
|
14
14
|
sql
|
15
15
|
end
|
16
16
|
|
17
|
-
def to_sql_and_binds(arel_or_sql_string, binds = [], preparable = nil) # :nodoc:
|
17
|
+
def to_sql_and_binds(arel_or_sql_string, binds = [], preparable = nil, allow_retry = false) # :nodoc:
|
18
|
+
# Arel::TreeManager -> Arel::Node
|
18
19
|
if arel_or_sql_string.respond_to?(:ast)
|
20
|
+
arel_or_sql_string = arel_or_sql_string.ast
|
21
|
+
end
|
22
|
+
|
23
|
+
if Arel.arel_node?(arel_or_sql_string) && !(String === arel_or_sql_string)
|
19
24
|
unless binds.empty?
|
20
25
|
raise "Passing bind parameters with an arel AST is forbidden. " \
|
21
26
|
"The values must be stored on the AST directly"
|
22
27
|
end
|
23
28
|
|
24
29
|
collector = collector()
|
30
|
+
collector.retryable = true
|
25
31
|
|
26
32
|
if prepared_statements
|
27
33
|
collector.preparable = true
|
28
|
-
sql, binds = visitor.compile(arel_or_sql_string
|
34
|
+
sql, binds = visitor.compile(arel_or_sql_string, collector)
|
29
35
|
|
30
36
|
if binds.length > bind_params_length
|
31
37
|
unprepared_statement do
|
@@ -34,12 +40,13 @@ module ActiveRecord
|
|
34
40
|
end
|
35
41
|
preparable = collector.preparable
|
36
42
|
else
|
37
|
-
sql = visitor.compile(arel_or_sql_string
|
43
|
+
sql = visitor.compile(arel_or_sql_string, collector)
|
38
44
|
end
|
39
|
-
|
45
|
+
allow_retry = collector.retryable
|
46
|
+
[sql.freeze, binds, preparable, allow_retry]
|
40
47
|
else
|
41
48
|
arel_or_sql_string = arel_or_sql_string.dup.freeze unless arel_or_sql_string.frozen?
|
42
|
-
[arel_or_sql_string, binds, preparable]
|
49
|
+
[arel_or_sql_string, binds, preparable, allow_retry]
|
43
50
|
end
|
44
51
|
end
|
45
52
|
private :to_sql_and_binds
|
@@ -59,24 +66,28 @@ module ActiveRecord
|
|
59
66
|
end
|
60
67
|
|
61
68
|
# Returns an ActiveRecord::Result instance.
|
62
|
-
def select_all(arel, name = nil, binds = [], preparable: nil, async: false)
|
69
|
+
def select_all(arel, name = nil, binds = [], preparable: nil, async: false, allow_retry: false)
|
63
70
|
arel = arel_from_relation(arel)
|
64
|
-
sql, binds, preparable = to_sql_and_binds(arel, binds, preparable)
|
71
|
+
sql, binds, preparable, allow_retry = to_sql_and_binds(arel, binds, preparable, allow_retry)
|
65
72
|
|
66
|
-
select(sql, name, binds,
|
73
|
+
select(sql, name, binds,
|
74
|
+
prepare: prepared_statements && preparable,
|
75
|
+
async: async && FutureResult::SelectAll,
|
76
|
+
allow_retry: allow_retry
|
77
|
+
)
|
67
78
|
rescue ::RangeError
|
68
|
-
ActiveRecord::Result.empty
|
79
|
+
ActiveRecord::Result.empty(async: async)
|
69
80
|
end
|
70
81
|
|
71
82
|
# Returns a record hash with the column names as keys and column values
|
72
83
|
# as values.
|
73
|
-
def select_one(arel, name = nil, binds = [])
|
74
|
-
select_all(arel, name, binds).first
|
84
|
+
def select_one(arel, name = nil, binds = [], async: false)
|
85
|
+
select_all(arel, name, binds, async: async).then(&:first)
|
75
86
|
end
|
76
87
|
|
77
88
|
# Returns a single value from a record
|
78
|
-
def select_value(arel, name = nil, binds = [])
|
79
|
-
|
89
|
+
def select_value(arel, name = nil, binds = [], async: false)
|
90
|
+
select_rows(arel, name, binds, async: async).then { |rows| single_value_from_rows(rows) }
|
80
91
|
end
|
81
92
|
|
82
93
|
# Returns an array of the values of the first column in a select:
|
@@ -87,8 +98,8 @@ module ActiveRecord
|
|
87
98
|
|
88
99
|
# Returns an array of arrays containing the field values.
|
89
100
|
# Order is the same as that returned by +columns+.
|
90
|
-
def select_rows(arel, name = nil, binds = [])
|
91
|
-
select_all(arel, name, binds).rows
|
101
|
+
def select_rows(arel, name = nil, binds = [], async: false)
|
102
|
+
select_all(arel, name, binds, async: async).then(&:rows)
|
92
103
|
end
|
93
104
|
|
94
105
|
def query_value(sql, name = nil) # :nodoc:
|
@@ -100,7 +111,7 @@ module ActiveRecord
|
|
100
111
|
end
|
101
112
|
|
102
113
|
def query(sql, name = nil) # :nodoc:
|
103
|
-
|
114
|
+
internal_exec_query(sql, name).rows
|
104
115
|
end
|
105
116
|
|
106
117
|
# Determines whether the SQL statement is a write query.
|
@@ -110,47 +121,63 @@ module ActiveRecord
|
|
110
121
|
|
111
122
|
# Executes the SQL statement in the context of this connection and returns
|
112
123
|
# the raw result from the connection adapter.
|
124
|
+
#
|
125
|
+
# Setting +allow_retry+ to true causes the db to reconnect and retry
|
126
|
+
# executing the SQL statement in case of a connection-related exception.
|
127
|
+
# This option should only be enabled for known idempotent queries.
|
128
|
+
#
|
129
|
+
# Note: the query is assumed to have side effects and the query cache
|
130
|
+
# will be cleared. If the query is read-only, consider using #select_all
|
131
|
+
# instead.
|
132
|
+
#
|
113
133
|
# Note: depending on your database connector, the result returned by this
|
114
|
-
# method may be manually memory managed. Consider using
|
134
|
+
# method may be manually memory managed. Consider using #exec_query
|
115
135
|
# wrapper instead.
|
116
|
-
def execute(sql, name = nil)
|
117
|
-
|
136
|
+
def execute(sql, name = nil, allow_retry: false)
|
137
|
+
internal_execute(sql, name, allow_retry: allow_retry)
|
118
138
|
end
|
119
139
|
|
120
140
|
# Executes +sql+ statement in the context of this connection using
|
121
141
|
# +binds+ as the bind substitutes. +name+ is logged along with
|
122
142
|
# the executed +sql+ statement.
|
143
|
+
#
|
144
|
+
# Note: the query is assumed to have side effects and the query cache
|
145
|
+
# will be cleared. If the query is read-only, consider using #select_all
|
146
|
+
# instead.
|
123
147
|
def exec_query(sql, name = "SQL", binds = [], prepare: false)
|
124
|
-
|
148
|
+
internal_exec_query(sql, name, binds, prepare: prepare)
|
125
149
|
end
|
126
150
|
|
127
151
|
# Executes insert +sql+ statement in the context of this connection using
|
128
152
|
# +binds+ as the bind substitutes. +name+ is logged along with
|
129
153
|
# the executed +sql+ statement.
|
130
|
-
|
131
|
-
|
132
|
-
|
154
|
+
# Some adapters support the `returning` keyword argument which allows to control the result of the query:
|
155
|
+
# `nil` is the default value and maintains default behavior. If an array of column names is passed -
|
156
|
+
# the result will contain values of the specified columns from the inserted row.
|
157
|
+
def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil, returning: nil)
|
158
|
+
sql, binds = sql_for_insert(sql, pk, binds, returning)
|
159
|
+
internal_exec_query(sql, name, binds)
|
133
160
|
end
|
134
161
|
|
135
162
|
# Executes delete +sql+ statement in the context of this connection using
|
136
163
|
# +binds+ as the bind substitutes. +name+ is logged along with
|
137
164
|
# the executed +sql+ statement.
|
138
165
|
def exec_delete(sql, name = nil, binds = [])
|
139
|
-
|
166
|
+
internal_exec_query(sql, name, binds)
|
140
167
|
end
|
141
168
|
|
142
169
|
# Executes update +sql+ statement in the context of this connection using
|
143
170
|
# +binds+ as the bind substitutes. +name+ is logged along with
|
144
171
|
# the executed +sql+ statement.
|
145
172
|
def exec_update(sql, name = nil, binds = [])
|
146
|
-
|
173
|
+
internal_exec_query(sql, name, binds)
|
147
174
|
end
|
148
175
|
|
149
176
|
def exec_insert_all(sql, name) # :nodoc:
|
150
|
-
|
177
|
+
internal_exec_query(sql, name)
|
151
178
|
end
|
152
179
|
|
153
|
-
def explain(arel, binds = []) # :nodoc:
|
180
|
+
def explain(arel, binds = [], options = []) # :nodoc:
|
154
181
|
raise NotImplementedError
|
155
182
|
end
|
156
183
|
|
@@ -162,9 +189,15 @@ module ActiveRecord
|
|
162
189
|
#
|
163
190
|
# If the next id was calculated in advance (as in Oracle), it should be
|
164
191
|
# passed in as +id_value+.
|
165
|
-
|
192
|
+
# Some adapters support the `returning` keyword argument which allows defining the return value of the method:
|
193
|
+
# `nil` is the default value and maintains default behavior. If an array of column names is passed -
|
194
|
+
# an array of is returned from the method representing values of the specified columns from the inserted row.
|
195
|
+
def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [], returning: nil)
|
166
196
|
sql, binds = to_sql_and_binds(arel, binds)
|
167
|
-
value = exec_insert(sql, name, binds, pk, sequence_name)
|
197
|
+
value = exec_insert(sql, name, binds, pk, sequence_name, returning: returning)
|
198
|
+
|
199
|
+
return returning_column_values(value) unless returning.nil?
|
200
|
+
|
168
201
|
id_value || last_inserted_id(value)
|
169
202
|
end
|
170
203
|
alias create insert
|
@@ -187,7 +220,7 @@ module ActiveRecord
|
|
187
220
|
end
|
188
221
|
|
189
222
|
def truncate_tables(*table_names) # :nodoc:
|
190
|
-
table_names -= [schema_migration.table_name,
|
223
|
+
table_names -= [pool.schema_migration.table_name, pool.internal_metadata.table_name]
|
191
224
|
|
192
225
|
return if table_names.empty?
|
193
226
|
|
@@ -202,6 +235,17 @@ module ActiveRecord
|
|
202
235
|
# Runs the given block in a database transaction, and returns the result
|
203
236
|
# of the block.
|
204
237
|
#
|
238
|
+
# == Transaction callbacks
|
239
|
+
#
|
240
|
+
# #transaction yields an ActiveRecord::Transaction object on which it is
|
241
|
+
# possible to register callback:
|
242
|
+
#
|
243
|
+
# ActiveRecord::Base.transaction do |transaction|
|
244
|
+
# transaction.before_commit { puts "before commit!" }
|
245
|
+
# transaction.after_commit { puts "after commit!" }
|
246
|
+
# transaction.after_rollback { puts "after rollback!" }
|
247
|
+
# end
|
248
|
+
#
|
205
249
|
# == Nested transactions support
|
206
250
|
#
|
207
251
|
# #transaction calls can be nested. By default, this makes all database
|
@@ -269,9 +313,9 @@ module ActiveRecord
|
|
269
313
|
# #transaction will raise exceptions when it tries to release the
|
270
314
|
# already-automatically-released savepoints:
|
271
315
|
#
|
272
|
-
# Model.
|
273
|
-
# Model.
|
274
|
-
# Model.
|
316
|
+
# Model.lease_connection.transaction do # BEGIN
|
317
|
+
# Model.lease_connection.transaction(requires_new: true) do # CREATE SAVEPOINT active_record_1
|
318
|
+
# Model.lease_connection.create_table(...)
|
275
319
|
# # active_record_1 now automatically released
|
276
320
|
# end # RELEASE SAVEPOINT active_record_1 <--- BOOM! database error!
|
277
321
|
# end
|
@@ -304,14 +348,15 @@ module ActiveRecord
|
|
304
348
|
# * You are joining an existing open transaction
|
305
349
|
# * You are creating a nested (savepoint) transaction
|
306
350
|
#
|
307
|
-
# The mysql2 and postgresql adapters support setting the transaction
|
351
|
+
# The mysql2, trilogy, and postgresql adapters support setting the transaction
|
308
352
|
# isolation level.
|
353
|
+
# :args: (requires_new: nil, isolation: nil, &block)
|
309
354
|
def transaction(requires_new: nil, isolation: nil, joinable: true, &block)
|
310
355
|
if !requires_new && current_transaction.joinable?
|
311
356
|
if isolation
|
312
357
|
raise ActiveRecord::TransactionIsolationError, "cannot set isolation when joining a transaction"
|
313
358
|
end
|
314
|
-
yield
|
359
|
+
yield current_transaction.user_transaction
|
315
360
|
else
|
316
361
|
transaction_manager.within_new_transaction(isolation: isolation, joinable: joinable, &block)
|
317
362
|
end
|
@@ -323,7 +368,8 @@ module ActiveRecord
|
|
323
368
|
|
324
369
|
delegate :within_new_transaction, :open_transactions, :current_transaction, :begin_transaction,
|
325
370
|
:commit_transaction, :rollback_transaction, :materialize_transactions,
|
326
|
-
:disable_lazy_transactions!, :enable_lazy_transactions!,
|
371
|
+
:disable_lazy_transactions!, :enable_lazy_transactions!, :dirty_current_transaction,
|
372
|
+
to: :transaction_manager
|
327
373
|
|
328
374
|
def mark_transaction_written_if_write(sql) # :nodoc:
|
329
375
|
transaction = current_transaction
|
@@ -336,8 +382,24 @@ module ActiveRecord
|
|
336
382
|
current_transaction.open?
|
337
383
|
end
|
338
384
|
|
339
|
-
def reset_transaction # :nodoc:
|
385
|
+
def reset_transaction(restore: false) # :nodoc:
|
386
|
+
# Store the existing transaction state to the side
|
387
|
+
old_state = @transaction_manager if restore && @transaction_manager&.restorable?
|
388
|
+
|
340
389
|
@transaction_manager = ConnectionAdapters::TransactionManager.new(self)
|
390
|
+
|
391
|
+
if block_given?
|
392
|
+
# Reconfigure the connection without any transaction state in the way
|
393
|
+
result = yield
|
394
|
+
|
395
|
+
# Now the connection's fully established, we can swap back
|
396
|
+
if old_state
|
397
|
+
@transaction_manager = old_state
|
398
|
+
@transaction_manager.restore_transactions
|
399
|
+
end
|
400
|
+
|
401
|
+
result
|
402
|
+
end
|
341
403
|
end
|
342
404
|
|
343
405
|
# Register a record with the current transaction so that its after_commit and after_rollback callbacks
|
@@ -372,10 +434,18 @@ module ActiveRecord
|
|
372
434
|
# done if the transaction block raises an exception or returns false.
|
373
435
|
def rollback_db_transaction
|
374
436
|
exec_rollback_db_transaction
|
437
|
+
rescue ActiveRecord::ConnectionNotEstablished, ActiveRecord::ConnectionFailed
|
438
|
+
# Connection's gone; that counts as a rollback
|
375
439
|
end
|
376
440
|
|
377
441
|
def exec_rollback_db_transaction() end # :nodoc:
|
378
442
|
|
443
|
+
def restart_db_transaction
|
444
|
+
exec_restart_db_transaction
|
445
|
+
end
|
446
|
+
|
447
|
+
def exec_restart_db_transaction() end # :nodoc:
|
448
|
+
|
379
449
|
def rollback_to_savepoint(name = nil)
|
380
450
|
exec_rollback_to_savepoint(name)
|
381
451
|
end
|
@@ -393,7 +463,7 @@ module ActiveRecord
|
|
393
463
|
# something beyond a simple insert (e.g. Oracle).
|
394
464
|
# Most of adapters should implement +insert_fixtures_set+ that leverages bulk SQL insert.
|
395
465
|
# We keep this method to provide fallback
|
396
|
-
# for databases like
|
466
|
+
# for databases like SQLite that do not support bulk inserts.
|
397
467
|
def insert_fixture(fixture, table_name)
|
398
468
|
execute(build_fixture_sql(Array.wrap(fixture), table_name), "Fixture Insert")
|
399
469
|
end
|
@@ -404,8 +474,8 @@ module ActiveRecord
|
|
404
474
|
statements = table_deletes + fixture_inserts
|
405
475
|
|
406
476
|
with_multi_statements do
|
407
|
-
|
408
|
-
|
477
|
+
transaction(requires_new: true) do
|
478
|
+
disable_referential_integrity do
|
409
479
|
execute_batch(statements, "Fixtures Load")
|
410
480
|
end
|
411
481
|
end
|
@@ -442,7 +512,7 @@ module ActiveRecord
|
|
442
512
|
end
|
443
513
|
|
444
514
|
# This is a safe default, even if not high precision on all databases
|
445
|
-
HIGH_PRECISION_CURRENT_TIMESTAMP = Arel.sql("CURRENT_TIMESTAMP").freeze # :nodoc:
|
515
|
+
HIGH_PRECISION_CURRENT_TIMESTAMP = Arel.sql("CURRENT_TIMESTAMP", retryable: true).freeze # :nodoc:
|
446
516
|
private_constant :HIGH_PRECISION_CURRENT_TIMESTAMP
|
447
517
|
|
448
518
|
# Returns an Arel SQL literal for the CURRENT_TIMESTAMP for usage with
|
@@ -454,13 +524,30 @@ module ActiveRecord
|
|
454
524
|
HIGH_PRECISION_CURRENT_TIMESTAMP
|
455
525
|
end
|
456
526
|
|
527
|
+
def internal_exec_query(sql, name = "SQL", binds = [], prepare: false, async: false, allow_retry: false) # :nodoc:
|
528
|
+
raise NotImplementedError
|
529
|
+
end
|
530
|
+
|
457
531
|
private
|
532
|
+
def internal_execute(sql, name = "SCHEMA", allow_retry: false, materialize_transactions: true)
|
533
|
+
sql = transform_query(sql)
|
534
|
+
check_if_write_query(sql)
|
535
|
+
|
536
|
+
mark_transaction_written_if_write(sql)
|
537
|
+
|
538
|
+
raw_execute(sql, name, allow_retry: allow_retry, materialize_transactions: materialize_transactions)
|
539
|
+
end
|
540
|
+
|
458
541
|
def execute_batch(statements, name = nil)
|
459
542
|
statements.each do |statement|
|
460
|
-
|
543
|
+
internal_execute(statement, name)
|
461
544
|
end
|
462
545
|
end
|
463
546
|
|
547
|
+
def raw_execute(sql, name, async: false, allow_retry: false, materialize_transactions: true)
|
548
|
+
raise NotImplementedError
|
549
|
+
end
|
550
|
+
|
464
551
|
DEFAULT_INSERT_VALUE = Arel.sql("DEFAULT").freeze
|
465
552
|
private_constant :DEFAULT_INSERT_VALUE
|
466
553
|
|
@@ -536,7 +623,7 @@ module ActiveRecord
|
|
536
623
|
end
|
537
624
|
|
538
625
|
# Returns an ActiveRecord::Result instance.
|
539
|
-
def select(sql, name = nil, binds = [], prepare: false, async: false)
|
626
|
+
def select(sql, name = nil, binds = [], prepare: false, async: false, allow_retry: false)
|
540
627
|
if async && async_enabled?
|
541
628
|
if current_transaction.joinable?
|
542
629
|
raise AsynchronousQueryInsideTransactionError, "Asynchronous queries are not allowed inside transactions"
|
@@ -557,10 +644,28 @@ module ActiveRecord
|
|
557
644
|
return future_result
|
558
645
|
end
|
559
646
|
|
560
|
-
|
647
|
+
result = internal_exec_query(sql, name, binds, prepare: prepare, allow_retry: allow_retry)
|
648
|
+
if async
|
649
|
+
FutureResult.wrap(result)
|
650
|
+
else
|
651
|
+
result
|
652
|
+
end
|
561
653
|
end
|
562
654
|
|
563
|
-
def sql_for_insert(sql, pk, binds)
|
655
|
+
def sql_for_insert(sql, pk, binds, returning) # :nodoc:
|
656
|
+
if supports_insert_returning?
|
657
|
+
if pk.nil?
|
658
|
+
# Extract the table from the insert sql. Yuck.
|
659
|
+
table_ref = extract_table_ref_from_insert_sql(sql)
|
660
|
+
pk = primary_key(table_ref) if table_ref
|
661
|
+
end
|
662
|
+
|
663
|
+
returning_columns = returning || Array(pk)
|
664
|
+
|
665
|
+
returning_columns_statement = returning_columns.map { |c| quote_column_name(c) }.join(", ")
|
666
|
+
sql = "#{sql} RETURNING #{returning_columns_statement}" if returning_columns.any?
|
667
|
+
end
|
668
|
+
|
564
669
|
[sql, binds]
|
565
670
|
end
|
566
671
|
|
@@ -568,6 +673,10 @@ module ActiveRecord
|
|
568
673
|
single_value_from_rows(result.rows)
|
569
674
|
end
|
570
675
|
|
676
|
+
def returning_column_values(result)
|
677
|
+
[last_inserted_id(result)]
|
678
|
+
end
|
679
|
+
|
571
680
|
def single_value_from_rows(rows)
|
572
681
|
row = rows.first
|
573
682
|
row && row.first
|
@@ -580,6 +689,12 @@ module ActiveRecord
|
|
580
689
|
relation
|
581
690
|
end
|
582
691
|
end
|
692
|
+
|
693
|
+
def extract_table_ref_from_insert_sql(sql)
|
694
|
+
if sql =~ /into\s("[A-Za-z0-9_."\[\]\s]+"|[A-Za-z0-9_."\[\]]+)\s*/im
|
695
|
+
$1.delete('"').strip
|
696
|
+
end
|
697
|
+
end
|
583
698
|
end
|
584
699
|
end
|
585
700
|
end
|