activerecord 7.0.8.7 → 7.1.5.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 +1795 -1424
- data/MIT-LICENSE +1 -1
- data/README.rdoc +16 -16
- data/lib/active_record/aggregations.rb +16 -13
- data/lib/active_record/association_relation.rb +1 -1
- data/lib/active_record/associations/association.rb +20 -4
- data/lib/active_record/associations/association_scope.rb +16 -9
- data/lib/active_record/associations/belongs_to_association.rb +14 -6
- data/lib/active_record/associations/builder/association.rb +3 -3
- data/lib/active_record/associations/builder/belongs_to.rb +21 -8
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
- data/lib/active_record/associations/builder/singular_association.rb +4 -0
- data/lib/active_record/associations/collection_association.rb +19 -13
- data/lib/active_record/associations/collection_proxy.rb +15 -10
- data/lib/active_record/associations/foreign_association.rb +10 -3
- data/lib/active_record/associations/has_many_association.rb +20 -13
- data/lib/active_record/associations/has_many_through_association.rb +10 -6
- data/lib/active_record/associations/has_one_association.rb +10 -3
- data/lib/active_record/associations/join_dependency/join_association.rb +3 -2
- data/lib/active_record/associations/join_dependency.rb +10 -10
- data/lib/active_record/associations/preloader/association.rb +31 -7
- data/lib/active_record/associations/preloader.rb +13 -10
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations/through_association.rb +22 -11
- data/lib/active_record/associations.rb +319 -217
- data/lib/active_record/attribute_assignment.rb +0 -2
- data/lib/active_record/attribute_methods/before_type_cast.rb +17 -0
- data/lib/active_record/attribute_methods/dirty.rb +53 -35
- data/lib/active_record/attribute_methods/primary_key.rb +76 -24
- data/lib/active_record/attribute_methods/query.rb +28 -16
- data/lib/active_record/attribute_methods/read.rb +21 -8
- data/lib/active_record/attribute_methods/serialization.rb +150 -31
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -0
- data/lib/active_record/attribute_methods/write.rb +6 -6
- data/lib/active_record/attribute_methods.rb +145 -21
- data/lib/active_record/attributes.rb +3 -3
- data/lib/active_record/autosave_association.rb +59 -10
- data/lib/active_record/base.rb +7 -2
- data/lib/active_record/callbacks.rb +10 -24
- 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 +163 -88
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +3 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +80 -50
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +129 -31
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +62 -23
- data/lib/active_record/connection_adapters/abstract/quoting.rb +41 -6
- 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 +296 -127
- data/lib/active_record/connection_adapters/abstract/transaction.rb +287 -58
- data/lib/active_record/connection_adapters/abstract_adapter.rb +511 -92
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +244 -121
- 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 +22 -143
- data/lib/active_record/connection_adapters/mysql/quoting.rb +16 -12
- 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 +19 -13
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +151 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +106 -55
- data/lib/active_record/connection_adapters/pool_config.rb +14 -5
- 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 +74 -40
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
- 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/quoting.rb +10 -6
- 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 +131 -2
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +53 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +364 -61
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +353 -192
- data/lib/active_record/connection_adapters/schema_cache.rb +287 -59
- data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +52 -39
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +4 -3
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +1 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +26 -7
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +211 -81
- 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 +258 -0
- data/lib/active_record/connection_adapters.rb +3 -1
- data/lib/active_record/connection_handling.rb +72 -95
- data/lib/active_record/core.rb +181 -154
- data/lib/active_record/counter_cache.rb +52 -27
- data/lib/active_record/database_configurations/connection_url_resolver.rb +1 -1
- data/lib/active_record/database_configurations/database_config.rb +9 -3
- data/lib/active_record/database_configurations/hash_config.rb +28 -14
- data/lib/active_record/database_configurations/url_config.rb +17 -11
- data/lib/active_record/database_configurations.rb +86 -33
- data/lib/active_record/delegated_type.rb +15 -10
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +3 -1
- 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 +42 -18
- data/lib/active_record/encryption/encrypted_attribute_type.rb +23 -8
- 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/message_serializer.rb +2 -0
- data/lib/active_record/encryption/properties.rb +3 -3
- data/lib/active_record/encryption/scheme.rb +22 -21
- data/lib/active_record/encryption.rb +3 -0
- data/lib/active_record/enum.rb +112 -28
- data/lib/active_record/errors.rb +112 -18
- data/lib/active_record/explain.rb +23 -3
- 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 +135 -71
- data/lib/active_record/future_result.rb +40 -5
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +30 -16
- data/lib/active_record/insert_all.rb +57 -10
- data/lib/active_record/integration.rb +8 -8
- data/lib/active_record/internal_metadata.rb +120 -30
- data/lib/active_record/locking/optimistic.rb +1 -1
- data/lib/active_record/locking/pessimistic.rb +5 -2
- data/lib/active_record/log_subscriber.rb +29 -12
- 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 +104 -5
- data/lib/active_record/migration/compatibility.rb +145 -5
- data/lib/active_record/migration/default_strategy.rb +23 -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 +219 -111
- data/lib/active_record/model_schema.rb +69 -44
- data/lib/active_record/nested_attributes.rb +37 -8
- data/lib/active_record/normalization.rb +167 -0
- data/lib/active_record/persistence.rb +188 -37
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +4 -22
- data/lib/active_record/query_logs.rb +77 -52
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +15 -2
- data/lib/active_record/railtie.rb +107 -45
- data/lib/active_record/railties/controller_runtime.rb +12 -6
- data/lib/active_record/railties/databases.rake +144 -150
- 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 +181 -45
- data/lib/active_record/relation/batches/batch_enumerator.rb +5 -3
- data/lib/active_record/relation/batches.rb +190 -61
- data/lib/active_record/relation/calculations.rb +187 -63
- data/lib/active_record/relation/delegation.rb +23 -9
- data/lib/active_record/relation/finder_methods.rb +77 -16
- data/lib/active_record/relation/merger.rb +2 -0
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +11 -2
- 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 +26 -14
- data/lib/active_record/relation/query_attribute.rb +2 -1
- data/lib/active_record/relation/query_methods.rb +371 -68
- data/lib/active_record/relation/spawn_methods.rb +18 -1
- data/lib/active_record/relation.rb +103 -37
- data/lib/active_record/result.rb +19 -5
- data/lib/active_record/runtime_registry.rb +24 -1
- data/lib/active_record/sanitization.rb +51 -11
- data/lib/active_record/schema.rb +2 -3
- data/lib/active_record/schema_dumper.rb +46 -7
- data/lib/active_record/schema_migration.rb +68 -33
- data/lib/active_record/scoping/default.rb +15 -5
- data/lib/active_record/scoping/named.rb +2 -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 +7 -5
- data/lib/active_record/store.rb +8 -8
- data/lib/active_record/suppressor.rb +3 -1
- data/lib/active_record/table_metadata.rb +10 -1
- data/lib/active_record/tasks/database_tasks.rb +152 -108
- 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 +15 -7
- data/lib/active_record/test_fixtures.rb +114 -96
- data/lib/active_record/timestamp.rb +30 -16
- data/lib/active_record/token_for.rb +113 -0
- data/lib/active_record/touch_later.rb +11 -6
- data/lib/active_record/transactions.rb +36 -10
- 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/time.rb +4 -0
- data/lib/active_record/validations/absence.rb +1 -1
- 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 +47 -2
- data/lib/active_record/validations.rb +8 -4
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +122 -17
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/nodes/binary.rb +6 -1
- data/lib/arel/nodes/bound_sql_literal.rb +61 -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/node.rb +111 -2
- data/lib/arel/nodes/sql_literal.rb +6 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes.rb +4 -0
- data/lib/arel/predications.rb +2 -0
- data/lib/arel/table.rb +9 -5
- data/lib/arel/tree_manager.rb +5 -1
- data/lib/arel/visitors/mysql.rb +8 -1
- data/lib/arel/visitors/to_sql.rb +83 -18
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +16 -2
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- 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 +46 -10
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -63
@@ -4,6 +4,7 @@ require "set"
|
|
4
4
|
require "active_record/connection_adapters/sql_type_metadata"
|
5
5
|
require "active_record/connection_adapters/abstract/schema_dumper"
|
6
6
|
require "active_record/connection_adapters/abstract/schema_creation"
|
7
|
+
require "active_support/concurrency/null_lock"
|
7
8
|
require "active_support/concurrency/load_interlock_aware_monitor"
|
8
9
|
require "arel/collectors/bind"
|
9
10
|
require "arel/collectors/composite"
|
@@ -12,6 +13,8 @@ require "arel/collectors/substitute_binds"
|
|
12
13
|
|
13
14
|
module ActiveRecord
|
14
15
|
module ConnectionAdapters # :nodoc:
|
16
|
+
# = Active Record Abstract Adapter
|
17
|
+
#
|
15
18
|
# Active Record supports multiple database systems. AbstractAdapter and
|
16
19
|
# related classes form the abstraction layer which makes this possible.
|
17
20
|
# An AbstractAdapter represents a connection to a database, and provides an
|
@@ -36,12 +39,20 @@ module ActiveRecord
|
|
36
39
|
include Savepoints
|
37
40
|
|
38
41
|
SIMPLE_INT = /\A\d+\z/
|
39
|
-
COMMENT_REGEX = %r{(?:--.*\n)|/\*(?:[^*]|\*[^/])*\*/}
|
42
|
+
COMMENT_REGEX = %r{(?:--.*\n)|/\*(?:[^*]|\*[^/])*\*/}
|
40
43
|
|
41
|
-
|
44
|
+
attr_reader :pool
|
42
45
|
attr_reader :visitor, :owner, :logger, :lock
|
43
46
|
alias :in_use? :owner
|
44
47
|
|
48
|
+
def pool=(value)
|
49
|
+
return if value.eql?(@pool)
|
50
|
+
@schema_cache = nil
|
51
|
+
@pool = value
|
52
|
+
|
53
|
+
@pool.schema_reflection.load!(self) if ActiveRecord.lazily_load_schema_cache
|
54
|
+
end
|
55
|
+
|
45
56
|
set_callback :checkin, :after, :enable_lazy_transactions!
|
46
57
|
|
47
58
|
def self.type_cast_config_to_integer(config)
|
@@ -62,6 +73,16 @@ module ActiveRecord
|
|
62
73
|
end
|
63
74
|
end
|
64
75
|
|
76
|
+
def self.validate_default_timezone(config)
|
77
|
+
case config
|
78
|
+
when nil
|
79
|
+
when "utc", "local"
|
80
|
+
config.to_sym
|
81
|
+
else
|
82
|
+
raise ArgumentError, "default_timezone must be either 'utc' or 'local'"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
65
86
|
DEFAULT_READ_QUERY = [:begin, :commit, :explain, :release, :rollback, :savepoint, :select, :with] # :nodoc:
|
66
87
|
private_constant :DEFAULT_READ_QUERY
|
67
88
|
|
@@ -71,27 +92,104 @@ module ActiveRecord
|
|
71
92
|
/\A(?:[(\s]|#{COMMENT_REGEX})*#{Regexp.union(*parts)}/
|
72
93
|
end
|
73
94
|
|
74
|
-
def
|
95
|
+
def self.find_cmd_and_exec(commands, *args) # :doc:
|
96
|
+
commands = Array(commands)
|
97
|
+
|
98
|
+
dirs_on_path = ENV["PATH"].to_s.split(File::PATH_SEPARATOR)
|
99
|
+
unless (ext = RbConfig::CONFIG["EXEEXT"]).empty?
|
100
|
+
commands = commands.map { |cmd| "#{cmd}#{ext}" }
|
101
|
+
end
|
102
|
+
|
103
|
+
full_path_command = nil
|
104
|
+
found = commands.detect do |cmd|
|
105
|
+
dirs_on_path.detect do |path|
|
106
|
+
full_path_command = File.join(path, cmd)
|
107
|
+
begin
|
108
|
+
stat = File.stat(full_path_command)
|
109
|
+
rescue SystemCallError
|
110
|
+
else
|
111
|
+
stat.file? && stat.executable?
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
if found
|
117
|
+
exec full_path_command, *args
|
118
|
+
else
|
119
|
+
abort("Couldn't find database client: #{commands.join(', ')}. Check your $PATH and try again.")
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Opens a database console session.
|
124
|
+
def self.dbconsole(config, options = {})
|
125
|
+
raise NotImplementedError
|
126
|
+
end
|
127
|
+
|
128
|
+
def initialize(config_or_deprecated_connection, deprecated_logger = nil, deprecated_connection_options = nil, deprecated_config = nil) # :nodoc:
|
75
129
|
super()
|
76
130
|
|
77
|
-
@
|
78
|
-
@
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
131
|
+
@raw_connection = nil
|
132
|
+
@unconfigured_connection = nil
|
133
|
+
|
134
|
+
if config_or_deprecated_connection.is_a?(Hash)
|
135
|
+
@config = config_or_deprecated_connection.symbolize_keys
|
136
|
+
@logger = ActiveRecord::Base.logger
|
137
|
+
|
138
|
+
if deprecated_logger || deprecated_connection_options || deprecated_config
|
139
|
+
raise ArgumentError, "when initializing an ActiveRecord adapter with a config hash, that should be the only argument"
|
140
|
+
end
|
141
|
+
else
|
142
|
+
# Soft-deprecated for now; we'll probably warn in future.
|
143
|
+
|
144
|
+
@unconfigured_connection = config_or_deprecated_connection
|
145
|
+
@logger = deprecated_logger || ActiveRecord::Base.logger
|
146
|
+
if deprecated_config
|
147
|
+
@config = (deprecated_config || {}).symbolize_keys
|
148
|
+
@connection_parameters = deprecated_connection_options
|
149
|
+
else
|
150
|
+
@config = (deprecated_connection_options || {}).symbolize_keys
|
151
|
+
@connection_parameters = nil
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
@owner = nil
|
156
|
+
@instrumenter = ActiveSupport::Notifications.instrumenter
|
157
|
+
@pool = ActiveRecord::ConnectionAdapters::NullPool.new
|
158
|
+
@idle_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
84
159
|
@visitor = arel_visitor
|
85
160
|
@statements = build_statement_pool
|
86
|
-
|
161
|
+
self.lock_thread = nil
|
87
162
|
|
88
|
-
@prepared_statements = self.class.type_cast_config_to_boolean(
|
89
|
-
config.fetch(:prepared_statements
|
163
|
+
@prepared_statements = !ActiveRecord.disable_prepared_statements && self.class.type_cast_config_to_boolean(
|
164
|
+
@config.fetch(:prepared_statements) { default_prepared_statements }
|
90
165
|
)
|
91
166
|
|
92
167
|
@advisory_locks_enabled = self.class.type_cast_config_to_boolean(
|
93
|
-
config.fetch(:advisory_locks, true)
|
168
|
+
@config.fetch(:advisory_locks, true)
|
94
169
|
)
|
170
|
+
|
171
|
+
@default_timezone = self.class.validate_default_timezone(@config[:default_timezone])
|
172
|
+
|
173
|
+
@raw_connection_dirty = false
|
174
|
+
@verified = false
|
175
|
+
end
|
176
|
+
|
177
|
+
THREAD_LOCK = ActiveSupport::Concurrency::ThreadLoadInterlockAwareMonitor.new
|
178
|
+
private_constant :THREAD_LOCK
|
179
|
+
|
180
|
+
FIBER_LOCK = ActiveSupport::Concurrency::LoadInterlockAwareMonitor.new
|
181
|
+
private_constant :FIBER_LOCK
|
182
|
+
|
183
|
+
def lock_thread=(lock_thread) # :nodoc:
|
184
|
+
@lock =
|
185
|
+
case lock_thread
|
186
|
+
when Thread
|
187
|
+
THREAD_LOCK
|
188
|
+
when Fiber
|
189
|
+
FIBER_LOCK
|
190
|
+
else
|
191
|
+
ActiveSupport::Concurrency::NullLock
|
192
|
+
end
|
95
193
|
end
|
96
194
|
|
97
195
|
EXCEPTION_NEVER = { Exception => :never }.freeze # :nodoc:
|
@@ -121,18 +219,28 @@ module ActiveRecord
|
|
121
219
|
@config.fetch(:use_metadata_table, true)
|
122
220
|
end
|
123
221
|
|
222
|
+
def connection_retries
|
223
|
+
(@config[:connection_retries] || 1).to_i
|
224
|
+
end
|
225
|
+
|
226
|
+
def retry_deadline
|
227
|
+
if @config[:retry_deadline]
|
228
|
+
@config[:retry_deadline].to_f
|
229
|
+
else
|
230
|
+
nil
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
def default_timezone
|
235
|
+
@default_timezone || ActiveRecord.default_timezone
|
236
|
+
end
|
237
|
+
|
124
238
|
# Determines whether writes are currently being prevented.
|
125
239
|
#
|
126
|
-
# Returns true if the connection is a replica
|
127
|
-
#
|
128
|
-
# If the application is using legacy handling, returns
|
129
|
-
# true if +connection_handler.prevent_writes+ is set.
|
130
|
-
#
|
131
|
-
# If the application is using the new connection handling
|
132
|
-
# will return true based on +current_preventing_writes+.
|
240
|
+
# Returns true if the connection is a replica or returns
|
241
|
+
# the value of +current_preventing_writes+.
|
133
242
|
def preventing_writes?
|
134
243
|
return true if replica?
|
135
|
-
return ActiveRecord::Base.connection_handler.prevent_writes if ActiveRecord.legacy_connection_handling
|
136
244
|
return false if connection_class.nil?
|
137
245
|
|
138
246
|
connection_class.current_preventing_writes
|
@@ -143,25 +251,15 @@ module ActiveRecord
|
|
143
251
|
end
|
144
252
|
|
145
253
|
def migration_context # :nodoc:
|
146
|
-
MigrationContext.new(migrations_paths, schema_migration)
|
254
|
+
MigrationContext.new(migrations_paths, schema_migration, internal_metadata)
|
147
255
|
end
|
148
256
|
|
149
257
|
def schema_migration # :nodoc:
|
150
|
-
|
151
|
-
|
152
|
-
spec_name = conn.pool.pool_config.connection_specification_name
|
153
|
-
|
154
|
-
return ActiveRecord::SchemaMigration if spec_name == "ActiveRecord::Base"
|
155
|
-
|
156
|
-
schema_migration_name = "#{spec_name}::SchemaMigration"
|
157
|
-
|
158
|
-
Class.new(ActiveRecord::SchemaMigration) do
|
159
|
-
define_singleton_method(:name) { schema_migration_name }
|
160
|
-
define_singleton_method(:to_s) { schema_migration_name }
|
258
|
+
SchemaMigration.new(self)
|
259
|
+
end
|
161
260
|
|
162
|
-
|
163
|
-
|
164
|
-
end
|
261
|
+
def internal_metadata # :nodoc:
|
262
|
+
InternalMetadata.new(self)
|
165
263
|
end
|
166
264
|
|
167
265
|
def prepared_statements?
|
@@ -200,16 +298,16 @@ module ActiveRecord
|
|
200
298
|
def lease
|
201
299
|
if in_use?
|
202
300
|
msg = +"Cannot lease connection, "
|
203
|
-
if @owner ==
|
301
|
+
if @owner == ActiveSupport::IsolatedExecutionState.context
|
204
302
|
msg << "it is already leased by the current thread."
|
205
303
|
else
|
206
304
|
msg << "it is already in use by a different thread: #{@owner}. " \
|
207
|
-
"Current thread: #{
|
305
|
+
"Current thread: #{ActiveSupport::IsolatedExecutionState.context}."
|
208
306
|
end
|
209
307
|
raise ActiveRecordError, msg
|
210
308
|
end
|
211
309
|
|
212
|
-
@owner =
|
310
|
+
@owner = ActiveSupport::IsolatedExecutionState.context
|
213
311
|
end
|
214
312
|
|
215
313
|
def connection_class # :nodoc:
|
@@ -229,21 +327,16 @@ module ActiveRecord
|
|
229
327
|
end
|
230
328
|
|
231
329
|
def schema_cache
|
232
|
-
@pool.
|
233
|
-
end
|
234
|
-
|
235
|
-
def schema_cache=(cache)
|
236
|
-
cache.connection = self
|
237
|
-
@pool.set_schema_cache(cache)
|
330
|
+
@schema_cache ||= BoundSchemaReflection.new(@pool.schema_reflection, self)
|
238
331
|
end
|
239
332
|
|
240
333
|
# this method must only be called while holding connection pool's mutex
|
241
334
|
def expire
|
242
335
|
if in_use?
|
243
|
-
if @owner !=
|
336
|
+
if @owner != ActiveSupport::IsolatedExecutionState.context
|
244
337
|
raise ActiveRecordError, "Cannot expire connection, " \
|
245
338
|
"it is owned by a different thread: #{@owner}. " \
|
246
|
-
"Current thread: #{
|
339
|
+
"Current thread: #{ActiveSupport::IsolatedExecutionState.context}."
|
247
340
|
end
|
248
341
|
|
249
342
|
@idle_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
@@ -256,10 +349,10 @@ module ActiveRecord
|
|
256
349
|
# this method must only be called while holding connection pool's mutex (and a desire for segfaults)
|
257
350
|
def steal! # :nodoc:
|
258
351
|
if in_use?
|
259
|
-
if @owner !=
|
352
|
+
if @owner != ActiveSupport::IsolatedExecutionState.context
|
260
353
|
pool.send :remove_connection_from_thread_cache, self, @owner
|
261
354
|
|
262
|
-
@owner =
|
355
|
+
@owner = ActiveSupport::IsolatedExecutionState.context
|
263
356
|
end
|
264
357
|
else
|
265
358
|
raise ActiveRecordError, "Cannot steal connection, it is not currently leased."
|
@@ -287,7 +380,14 @@ module ActiveRecord
|
|
287
380
|
|
288
381
|
# Does the database for this adapter exist?
|
289
382
|
def self.database_exists?(config)
|
290
|
-
|
383
|
+
new(config).database_exists?
|
384
|
+
end
|
385
|
+
|
386
|
+
def database_exists?
|
387
|
+
connect!
|
388
|
+
true
|
389
|
+
rescue ActiveRecord::NoDatabaseError
|
390
|
+
false
|
291
391
|
end
|
292
392
|
|
293
393
|
# Does this adapter support DDL rollbacks in transactions? That is, would
|
@@ -305,6 +405,16 @@ module ActiveRecord
|
|
305
405
|
false
|
306
406
|
end
|
307
407
|
|
408
|
+
# Do TransactionRollbackErrors on savepoints affect the parent
|
409
|
+
# transaction?
|
410
|
+
def savepoint_errors_invalidate_transactions?
|
411
|
+
false
|
412
|
+
end
|
413
|
+
|
414
|
+
def supports_restart_db_transaction?
|
415
|
+
false
|
416
|
+
end
|
417
|
+
|
308
418
|
# Does this adapter support application-enforced advisory locking?
|
309
419
|
def supports_advisory_locks?
|
310
420
|
false
|
@@ -331,6 +441,11 @@ module ActiveRecord
|
|
331
441
|
false
|
332
442
|
end
|
333
443
|
|
444
|
+
# Does this adapter support including non-key columns?
|
445
|
+
def supports_index_include?
|
446
|
+
false
|
447
|
+
end
|
448
|
+
|
334
449
|
# Does this adapter support expression indices?
|
335
450
|
def supports_expression_index?
|
336
451
|
false
|
@@ -377,6 +492,16 @@ module ActiveRecord
|
|
377
492
|
false
|
378
493
|
end
|
379
494
|
|
495
|
+
# Does this adapter support creating exclusion constraints?
|
496
|
+
def supports_exclusion_constraints?
|
497
|
+
false
|
498
|
+
end
|
499
|
+
|
500
|
+
# Does this adapter support creating unique constraints?
|
501
|
+
def supports_unique_constraints?
|
502
|
+
false
|
503
|
+
end
|
504
|
+
|
380
505
|
# Does this adapter support views?
|
381
506
|
def supports_views?
|
382
507
|
false
|
@@ -392,7 +517,7 @@ module ActiveRecord
|
|
392
517
|
false
|
393
518
|
end
|
394
519
|
|
395
|
-
# Does this adapter support
|
520
|
+
# Does this adapter support JSON data type?
|
396
521
|
def supports_json?
|
397
522
|
false
|
398
523
|
end
|
@@ -450,23 +575,47 @@ module ActiveRecord
|
|
450
575
|
true
|
451
576
|
end
|
452
577
|
|
578
|
+
def supports_nulls_not_distinct?
|
579
|
+
false
|
580
|
+
end
|
581
|
+
|
582
|
+
def return_value_after_insert?(column) # :nodoc:
|
583
|
+
column.auto_incremented_by_db?
|
584
|
+
end
|
585
|
+
|
453
586
|
def async_enabled? # :nodoc:
|
454
587
|
supports_concurrent_connections? &&
|
455
588
|
!ActiveRecord.async_query_executor.nil? && !pool.async_executor.nil?
|
456
589
|
end
|
457
590
|
|
458
591
|
# This is meant to be implemented by the adapters that support extensions
|
459
|
-
def disable_extension(name)
|
592
|
+
def disable_extension(name, **)
|
460
593
|
end
|
461
594
|
|
462
595
|
# This is meant to be implemented by the adapters that support extensions
|
463
|
-
def enable_extension(name)
|
596
|
+
def enable_extension(name, **)
|
464
597
|
end
|
465
598
|
|
466
599
|
# This is meant to be implemented by the adapters that support custom enum types
|
467
600
|
def create_enum(*) # :nodoc:
|
468
601
|
end
|
469
602
|
|
603
|
+
# This is meant to be implemented by the adapters that support custom enum types
|
604
|
+
def drop_enum(*) # :nodoc:
|
605
|
+
end
|
606
|
+
|
607
|
+
# This is meant to be implemented by the adapters that support custom enum types
|
608
|
+
def rename_enum(*) # :nodoc:
|
609
|
+
end
|
610
|
+
|
611
|
+
# This is meant to be implemented by the adapters that support custom enum types
|
612
|
+
def add_enum_value(*) # :nodoc:
|
613
|
+
end
|
614
|
+
|
615
|
+
# This is meant to be implemented by the adapters that support custom enum types
|
616
|
+
def rename_enum_value(*) # :nodoc:
|
617
|
+
end
|
618
|
+
|
470
619
|
def advisory_locks_enabled? # :nodoc:
|
471
620
|
supports_advisory_locks? && @advisory_locks_enabled
|
472
621
|
end
|
@@ -504,7 +653,17 @@ module ActiveRecord
|
|
504
653
|
|
505
654
|
# Override to check all foreign key constraints in a database.
|
506
655
|
def all_foreign_keys_valid?
|
656
|
+
check_all_foreign_keys_valid!
|
507
657
|
true
|
658
|
+
rescue ActiveRecord::StatementInvalid
|
659
|
+
false
|
660
|
+
end
|
661
|
+
deprecate :all_foreign_keys_valid?, deprecator: ActiveRecord.deprecator
|
662
|
+
|
663
|
+
# Override to check all foreign key constraints in a database.
|
664
|
+
# The adapter should raise a +ActiveRecord::StatementInvalid+ if foreign key
|
665
|
+
# constraints are not met.
|
666
|
+
def check_all_foreign_keys_valid!
|
508
667
|
end
|
509
668
|
|
510
669
|
# CONNECTION MANAGEMENT ====================================
|
@@ -515,19 +674,51 @@ module ActiveRecord
|
|
515
674
|
def active?
|
516
675
|
end
|
517
676
|
|
518
|
-
# Disconnects from the database if already connected, and establishes a
|
519
|
-
#
|
520
|
-
#
|
521
|
-
def reconnect!
|
522
|
-
|
523
|
-
|
677
|
+
# Disconnects from the database if already connected, and establishes a new
|
678
|
+
# connection with the database. Implementors should define private #reconnect
|
679
|
+
# instead.
|
680
|
+
def reconnect!(restore_transactions: false)
|
681
|
+
retries_available = connection_retries
|
682
|
+
deadline = retry_deadline && Process.clock_gettime(Process::CLOCK_MONOTONIC) + retry_deadline
|
683
|
+
|
684
|
+
@lock.synchronize do
|
685
|
+
reconnect
|
686
|
+
|
687
|
+
enable_lazy_transactions!
|
688
|
+
@raw_connection_dirty = false
|
689
|
+
@verified = true
|
690
|
+
|
691
|
+
reset_transaction(restore: restore_transactions) do
|
692
|
+
clear_cache!(new_connection: true)
|
693
|
+
configure_connection
|
694
|
+
end
|
695
|
+
rescue => original_exception
|
696
|
+
translated_exception = translate_exception_class(original_exception, nil, nil)
|
697
|
+
retry_deadline_exceeded = deadline && deadline < Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
698
|
+
|
699
|
+
if !retry_deadline_exceeded && retries_available > 0
|
700
|
+
retries_available -= 1
|
701
|
+
|
702
|
+
if retryable_connection_error?(translated_exception)
|
703
|
+
backoff(connection_retries - retries_available)
|
704
|
+
retry
|
705
|
+
end
|
706
|
+
end
|
707
|
+
|
708
|
+
@verified = false
|
709
|
+
|
710
|
+
raise translated_exception
|
711
|
+
end
|
524
712
|
end
|
525
713
|
|
526
714
|
# Disconnects from the database if already connected. Otherwise, this
|
527
715
|
# method does nothing.
|
528
716
|
def disconnect!
|
529
|
-
|
530
|
-
|
717
|
+
@lock.synchronize do
|
718
|
+
clear_cache!(new_connection: true)
|
719
|
+
reset_transaction
|
720
|
+
@raw_connection_dirty = false
|
721
|
+
end
|
531
722
|
end
|
532
723
|
|
533
724
|
# Immediately forget this connection ever existed. Unlike disconnect!,
|
@@ -538,22 +729,20 @@ module ActiveRecord
|
|
538
729
|
# rid of a connection that belonged to its parent.
|
539
730
|
def discard!
|
540
731
|
# This should be overridden by concrete adapters.
|
541
|
-
#
|
542
|
-
# Prevent @connection's finalizer from touching the socket, or
|
543
|
-
# otherwise communicating with its server, when it is collected.
|
544
|
-
if schema_cache.connection == self
|
545
|
-
schema_cache.connection = nil
|
546
|
-
end
|
547
732
|
end
|
548
733
|
|
549
734
|
# Reset the state of this connection, directing the DBMS to clear
|
550
735
|
# transactions and other connection-related server-side state. Usually a
|
551
736
|
# database-dependent operation.
|
552
737
|
#
|
553
|
-
#
|
554
|
-
#
|
738
|
+
# If a database driver or protocol does not support such a feature,
|
739
|
+
# implementors may alias this to #reconnect!. Otherwise, implementors
|
740
|
+
# should call super immediately after resetting the connection (and while
|
741
|
+
# still holding @lock).
|
555
742
|
def reset!
|
556
|
-
|
743
|
+
clear_cache!(new_connection: true)
|
744
|
+
reset_transaction
|
745
|
+
configure_connection
|
557
746
|
end
|
558
747
|
|
559
748
|
# Removes the connection from the pool and disconnect it.
|
@@ -563,8 +752,16 @@ module ActiveRecord
|
|
563
752
|
end
|
564
753
|
|
565
754
|
# Clear any caching the database adapter may be doing.
|
566
|
-
def clear_cache!
|
567
|
-
|
755
|
+
def clear_cache!(new_connection: false)
|
756
|
+
if @statements
|
757
|
+
@lock.synchronize do
|
758
|
+
if new_connection
|
759
|
+
@statements.reset
|
760
|
+
else
|
761
|
+
@statements.clear
|
762
|
+
end
|
763
|
+
end
|
764
|
+
end
|
568
765
|
end
|
569
766
|
|
570
767
|
# Returns true if its required to reload the connection between requests for development mode.
|
@@ -576,7 +773,31 @@ module ActiveRecord
|
|
576
773
|
# This is done under the hood by calling #active?. If the connection
|
577
774
|
# is no longer active, then this method will reconnect to the database.
|
578
775
|
def verify!
|
579
|
-
|
776
|
+
unless active?
|
777
|
+
@lock.synchronize do
|
778
|
+
if @unconfigured_connection
|
779
|
+
@raw_connection = @unconfigured_connection
|
780
|
+
@unconfigured_connection = nil
|
781
|
+
configure_connection
|
782
|
+
@verified = true
|
783
|
+
return
|
784
|
+
end
|
785
|
+
|
786
|
+
reconnect!(restore_transactions: true)
|
787
|
+
end
|
788
|
+
end
|
789
|
+
|
790
|
+
@verified = true
|
791
|
+
end
|
792
|
+
|
793
|
+
def connect!
|
794
|
+
verify!
|
795
|
+
self
|
796
|
+
end
|
797
|
+
|
798
|
+
def clean! # :nodoc:
|
799
|
+
@raw_connection_dirty = false
|
800
|
+
@verified = nil
|
580
801
|
end
|
581
802
|
|
582
803
|
# Provides access to the underlying database driver for this adapter. For
|
@@ -590,8 +811,11 @@ module ActiveRecord
|
|
590
811
|
# this client. If that is the case, generally you'll want to invalidate
|
591
812
|
# the query cache using +ActiveRecord::Base.clear_query_cache+.
|
592
813
|
def raw_connection
|
593
|
-
|
594
|
-
|
814
|
+
with_raw_connection do |conn|
|
815
|
+
disable_lazy_transactions!
|
816
|
+
@raw_connection_dirty = true
|
817
|
+
conn
|
818
|
+
end
|
595
819
|
end
|
596
820
|
|
597
821
|
def default_uniqueness_comparison(attribute, value) # :nodoc:
|
@@ -658,6 +882,21 @@ module ActiveRecord
|
|
658
882
|
end
|
659
883
|
|
660
884
|
class << self
|
885
|
+
def register_class_with_precision(mapping, key, klass, **kwargs) # :nodoc:
|
886
|
+
mapping.register_type(key) do |*args|
|
887
|
+
precision = extract_precision(args.last)
|
888
|
+
klass.new(precision: precision, **kwargs)
|
889
|
+
end
|
890
|
+
end
|
891
|
+
|
892
|
+
def extended_type_map(default_timezone:) # :nodoc:
|
893
|
+
Type::TypeMap.new(self::TYPE_MAP).tap do |m|
|
894
|
+
register_class_with_precision m, %r(\A[^\(]*time)i, Type::Time, timezone: default_timezone
|
895
|
+
register_class_with_precision m, %r(\A[^\(]*datetime)i, Type::DateTime, timezone: default_timezone
|
896
|
+
m.alias_type %r(\A[^\(]*timestamp)i, "datetime"
|
897
|
+
end
|
898
|
+
end
|
899
|
+
|
661
900
|
private
|
662
901
|
def initialize_type_map(m)
|
663
902
|
register_class_with_limit m, %r(boolean)i, Type::Boolean
|
@@ -699,13 +938,6 @@ module ActiveRecord
|
|
699
938
|
end
|
700
939
|
end
|
701
940
|
|
702
|
-
def register_class_with_precision(mapping, key, klass)
|
703
|
-
mapping.register_type(key) do |*args|
|
704
|
-
precision = extract_precision(args.last)
|
705
|
-
klass.new(precision: precision)
|
706
|
-
end
|
707
|
-
end
|
708
|
-
|
709
941
|
def extract_scale(sql_type)
|
710
942
|
case sql_type
|
711
943
|
when /\((\d+)\)/ then 0
|
@@ -723,10 +955,177 @@ module ActiveRecord
|
|
723
955
|
end
|
724
956
|
|
725
957
|
TYPE_MAP = Type::TypeMap.new.tap { |m| initialize_type_map(m) }
|
958
|
+
EXTENDED_TYPE_MAPS = Concurrent::Map.new
|
726
959
|
|
727
960
|
private
|
961
|
+
def reconnect_can_restore_state?
|
962
|
+
transaction_manager.restorable? && !@raw_connection_dirty
|
963
|
+
end
|
964
|
+
|
965
|
+
# Lock the monitor, ensure we're properly connected and
|
966
|
+
# transactions are materialized, and then yield the underlying
|
967
|
+
# raw connection object.
|
968
|
+
#
|
969
|
+
# If +allow_retry+ is true, a connection-related exception will
|
970
|
+
# cause an automatic reconnect and re-run of the block, up to
|
971
|
+
# the connection's configured +connection_retries+ setting
|
972
|
+
# and the configured +retry_deadline+ limit. (Note that when
|
973
|
+
# +allow_retry+ is true, it's possible to return without having marked
|
974
|
+
# the connection as verified. If the block is guaranteed to exercise the
|
975
|
+
# connection, consider calling `verified!` to avoid needless
|
976
|
+
# verification queries in subsequent calls.)
|
977
|
+
#
|
978
|
+
# If +materialize_transactions+ is false, the block will be run without
|
979
|
+
# ensuring virtual transactions have been materialized in the DB
|
980
|
+
# server's state. The active transaction will also remain clean
|
981
|
+
# (if it is not already dirty), meaning it's able to be restored
|
982
|
+
# by reconnecting and opening an equivalent-depth set of new
|
983
|
+
# transactions. This should only be used by transaction control
|
984
|
+
# methods, and internal transaction-agnostic queries.
|
985
|
+
#
|
986
|
+
###
|
987
|
+
#
|
988
|
+
# It's not the primary use case, so not something to optimize
|
989
|
+
# for, but note that this method does need to be re-entrant:
|
990
|
+
# +materialize_transactions+ will re-enter if it has work to do,
|
991
|
+
# and the yield block can also do so under some circumstances.
|
992
|
+
#
|
993
|
+
# In the latter case, we really ought to guarantee the inner
|
994
|
+
# call will not reconnect (which would interfere with the
|
995
|
+
# still-yielded connection in the outer block), but we currently
|
996
|
+
# provide no special enforcement there.
|
997
|
+
#
|
998
|
+
def with_raw_connection(allow_retry: false, materialize_transactions: true)
|
999
|
+
@lock.synchronize do
|
1000
|
+
connect! if @raw_connection.nil? && reconnect_can_restore_state?
|
1001
|
+
|
1002
|
+
self.materialize_transactions if materialize_transactions
|
1003
|
+
|
1004
|
+
retries_available = allow_retry ? connection_retries : 0
|
1005
|
+
deadline = retry_deadline && Process.clock_gettime(Process::CLOCK_MONOTONIC) + retry_deadline
|
1006
|
+
reconnectable = reconnect_can_restore_state?
|
1007
|
+
|
1008
|
+
if @verified
|
1009
|
+
# Cool, we're confident the connection's ready to use. (Note this might have
|
1010
|
+
# become true during the above #materialize_transactions.)
|
1011
|
+
elsif reconnectable
|
1012
|
+
if allow_retry
|
1013
|
+
# Not sure about the connection yet, but if anything goes wrong we can
|
1014
|
+
# just reconnect and re-run our query
|
1015
|
+
else
|
1016
|
+
# We can reconnect if needed, but we don't trust the upcoming query to be
|
1017
|
+
# safely re-runnable: let's verify the connection to be sure
|
1018
|
+
verify!
|
1019
|
+
end
|
1020
|
+
else
|
1021
|
+
# We don't know whether the connection is okay, but it also doesn't matter:
|
1022
|
+
# we wouldn't be able to reconnect anyway. We're just going to run our query
|
1023
|
+
# and hope for the best.
|
1024
|
+
end
|
1025
|
+
|
1026
|
+
begin
|
1027
|
+
yield @raw_connection
|
1028
|
+
rescue => original_exception
|
1029
|
+
translated_exception = translate_exception_class(original_exception, nil, nil)
|
1030
|
+
invalidate_transaction(translated_exception)
|
1031
|
+
retry_deadline_exceeded = deadline && deadline < Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
1032
|
+
|
1033
|
+
if !retry_deadline_exceeded && retries_available > 0
|
1034
|
+
retries_available -= 1
|
1035
|
+
|
1036
|
+
if retryable_query_error?(translated_exception)
|
1037
|
+
backoff(connection_retries - retries_available)
|
1038
|
+
retry
|
1039
|
+
elsif reconnectable && retryable_connection_error?(translated_exception)
|
1040
|
+
reconnect!(restore_transactions: true)
|
1041
|
+
# Only allowed to reconnect once, because reconnect! has its own retry
|
1042
|
+
# loop
|
1043
|
+
reconnectable = false
|
1044
|
+
retry
|
1045
|
+
end
|
1046
|
+
end
|
1047
|
+
|
1048
|
+
unless retryable_query_error?(translated_exception)
|
1049
|
+
# Barring a known-retryable error inside the query (regardless of
|
1050
|
+
# whether we were in a _position_ to retry it), we should infer that
|
1051
|
+
# there's likely a real problem with the connection.
|
1052
|
+
@verified = false
|
1053
|
+
end
|
1054
|
+
|
1055
|
+
raise translated_exception
|
1056
|
+
ensure
|
1057
|
+
dirty_current_transaction if materialize_transactions
|
1058
|
+
end
|
1059
|
+
end
|
1060
|
+
end
|
1061
|
+
|
1062
|
+
# Mark the connection as verified. Call this inside a
|
1063
|
+
# `with_raw_connection` block only when the block is guaranteed to
|
1064
|
+
# exercise the raw connection.
|
1065
|
+
def verified!
|
1066
|
+
@verified = true
|
1067
|
+
end
|
1068
|
+
|
1069
|
+
def retryable_connection_error?(exception)
|
1070
|
+
exception.is_a?(ConnectionNotEstablished) || exception.is_a?(ConnectionFailed)
|
1071
|
+
end
|
1072
|
+
|
1073
|
+
def invalidate_transaction(exception)
|
1074
|
+
return unless exception.is_a?(TransactionRollbackError)
|
1075
|
+
return unless savepoint_errors_invalidate_transactions?
|
1076
|
+
|
1077
|
+
current_transaction.invalidate!
|
1078
|
+
end
|
1079
|
+
|
1080
|
+
def retryable_query_error?(exception)
|
1081
|
+
# We definitely can't retry if we were inside an invalidated transaction.
|
1082
|
+
return false if current_transaction.invalidated?
|
1083
|
+
|
1084
|
+
exception.is_a?(Deadlocked) || exception.is_a?(LockWaitTimeout)
|
1085
|
+
end
|
1086
|
+
|
1087
|
+
def backoff(counter)
|
1088
|
+
sleep 0.1 * counter
|
1089
|
+
end
|
1090
|
+
|
1091
|
+
def reconnect
|
1092
|
+
raise NotImplementedError
|
1093
|
+
end
|
1094
|
+
|
1095
|
+
# Returns a raw connection for internal use with methods that are known
|
1096
|
+
# to both be thread-safe and not rely upon actual server communication.
|
1097
|
+
# This is useful for e.g. string escaping methods.
|
1098
|
+
def any_raw_connection
|
1099
|
+
@raw_connection || valid_raw_connection
|
1100
|
+
end
|
1101
|
+
|
1102
|
+
# Similar to any_raw_connection, but ensures it is validated and
|
1103
|
+
# connected. Any method called on this result still needs to be
|
1104
|
+
# independently thread-safe, so it probably shouldn't talk to the
|
1105
|
+
# server... but some drivers fail if they know the connection has gone
|
1106
|
+
# away.
|
1107
|
+
def valid_raw_connection
|
1108
|
+
(@verified && @raw_connection) ||
|
1109
|
+
# `allow_retry: false`, to force verification: the block won't
|
1110
|
+
# raise, so a retry wouldn't help us get the valid connection we
|
1111
|
+
# need.
|
1112
|
+
with_raw_connection(allow_retry: false, materialize_transactions: false) { |conn| conn }
|
1113
|
+
end
|
1114
|
+
|
1115
|
+
def extended_type_map_key
|
1116
|
+
if @default_timezone
|
1117
|
+
{ default_timezone: @default_timezone }
|
1118
|
+
end
|
1119
|
+
end
|
1120
|
+
|
728
1121
|
def type_map
|
729
|
-
|
1122
|
+
if key = extended_type_map_key
|
1123
|
+
self.class::EXTENDED_TYPE_MAPS.compute_if_absent(key) do
|
1124
|
+
self.class.extended_type_map(**key)
|
1125
|
+
end
|
1126
|
+
else
|
1127
|
+
self.class::TYPE_MAP
|
1128
|
+
end
|
730
1129
|
end
|
731
1130
|
|
732
1131
|
def translate_exception_class(e, sql, binds)
|
@@ -748,16 +1147,16 @@ module ActiveRecord
|
|
748
1147
|
type_casted_binds: type_casted_binds,
|
749
1148
|
statement_name: statement_name,
|
750
1149
|
async: async,
|
751
|
-
connection: self
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
1150
|
+
connection: self,
|
1151
|
+
&block
|
1152
|
+
)
|
1153
|
+
rescue ActiveRecord::StatementInvalid => ex
|
1154
|
+
raise ex.set_query(sql, binds)
|
756
1155
|
end
|
757
1156
|
|
758
1157
|
def transform_query(sql)
|
759
1158
|
ActiveRecord.query_transformers.each do |transformer|
|
760
|
-
sql = transformer.call(sql)
|
1159
|
+
sql = transformer.call(sql, self)
|
761
1160
|
end
|
762
1161
|
sql
|
763
1162
|
end
|
@@ -765,10 +1164,10 @@ module ActiveRecord
|
|
765
1164
|
def translate_exception(exception, message:, sql:, binds:)
|
766
1165
|
# override in derived class
|
767
1166
|
case exception
|
768
|
-
when RuntimeError
|
1167
|
+
when RuntimeError, ActiveRecord::ActiveRecordError
|
769
1168
|
exception
|
770
1169
|
else
|
771
|
-
ActiveRecord::StatementInvalid.new(message, sql: sql, binds: binds)
|
1170
|
+
ActiveRecord::StatementInvalid.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
772
1171
|
end
|
773
1172
|
end
|
774
1173
|
|
@@ -815,6 +1214,26 @@ module ActiveRecord
|
|
815
1214
|
def build_result(columns:, rows:, column_types: {})
|
816
1215
|
ActiveRecord::Result.new(columns, rows, column_types)
|
817
1216
|
end
|
1217
|
+
|
1218
|
+
# Perform any necessary initialization upon the newly-established
|
1219
|
+
# @raw_connection -- this is the place to modify the adapter's
|
1220
|
+
# connection settings, run queries to configure any application-global
|
1221
|
+
# "session" variables, etc.
|
1222
|
+
#
|
1223
|
+
# Implementations may assume this method will only be called while
|
1224
|
+
# holding @lock (or from #initialize).
|
1225
|
+
def configure_connection
|
1226
|
+
end
|
1227
|
+
|
1228
|
+
def default_prepared_statements
|
1229
|
+
true
|
1230
|
+
end
|
1231
|
+
|
1232
|
+
def warning_ignored?(warning)
|
1233
|
+
ActiveRecord.db_warnings_ignore.any? do |warning_matcher|
|
1234
|
+
warning.message.match?(warning_matcher) || warning.code.to_s.match?(warning_matcher)
|
1235
|
+
end
|
1236
|
+
end
|
818
1237
|
end
|
819
1238
|
end
|
820
1239
|
end
|