Skip to content

Commit d6e6686

Browse files
authored
Merge pull request rails#44570 from matthewd/configure-connection
Define AbstractAdapter#configure_connection
2 parents 4975e0b + dc4420c commit d6e6686

File tree

4 files changed

+79
-50
lines changed

4 files changed

+79
-50
lines changed

activerecord/lib/active_record/connection_adapters/abstract_adapter.rb

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ def initialize(connection, logger = nil, config = {}) # :nodoc:
112112
)
113113

114114
@default_timezone = self.class.validate_default_timezone(config[:default_timezone])
115+
116+
configure_connection
115117
end
116118

117119
EXCEPTION_NEVER = { Exception => :never }.freeze # :nodoc:
@@ -550,11 +552,13 @@ def active?
550552
end
551553

552554
# Disconnects from the database if already connected, and establishes a
553-
# new connection with the database. Implementors should call super if they
554-
# override the default implementation.
555+
# new connection with the database. Implementors should call super
556+
# immediately after establishing the new connection (and while still
557+
# holding @lock).
555558
def reconnect!
556559
clear_cache!(new_connection: true)
557560
reset_transaction
561+
configure_connection
558562
end
559563

560564
# Disconnects from the database if already connected. Otherwise, this
@@ -584,10 +588,14 @@ def discard!
584588
# transactions and other connection-related server-side state. Usually a
585589
# database-dependent operation.
586590
#
587-
# The default implementation does nothing; the implementation should be
588-
# overridden by concrete adapters.
591+
# If a database driver or protocol does not support such a feature,
592+
# implementors may alias this to #reconnect!. Otherwise, implementors
593+
# should call super immediately after resetting the connection (and while
594+
# still holding @lock).
589595
def reset!
590-
# this should be overridden by concrete adapters
596+
clear_cache!(new_connection: true)
597+
reset_transaction
598+
configure_connection
591599
end
592600

593601
# Removes the connection from the pool and disconnect it.
@@ -883,6 +891,16 @@ def build_statement_pool
883891
def build_result(columns:, rows:, column_types: {})
884892
ActiveRecord::Result.new(columns, rows, column_types)
885893
end
894+
895+
# Perform any necessary initialization upon the newly-established
896+
# @raw_connection -- this is the place to modify the adapter's
897+
# connection settings, run queries to configure any application-global
898+
# "session" variables, etc.
899+
#
900+
# Implementations may assume this method will only be called while
901+
# holding @lock (or from #initialize).
902+
def configure_connection
903+
end
886904
end
887905
end
888906
end

activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ def initialize(connection, logger, connection_options, config)
5959
check_prepared_statements_deprecation(config)
6060
superclass_config = config.reverse_merge(prepared_statements: false)
6161
super(connection, logger, connection_options, superclass_config)
62-
configure_connection
6362
end
6463

6564
def self.database_exists?(config)
@@ -125,9 +124,11 @@ def active?
125124
end
126125

127126
def reconnect!
128-
super
129-
disconnect!
130-
connect
127+
@lock.synchronize do
128+
disconnect!
129+
connect
130+
super
131+
end
131132
end
132133
alias :reset! :reconnect!
133134

@@ -155,7 +156,6 @@ def check_prepared_statements_deprecation(config)
155156

156157
def connect
157158
@raw_connection = self.class.new_client(@config)
158-
configure_connection
159159
end
160160

161161
def configure_connection

activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb

Lines changed: 42 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -283,21 +283,13 @@ def connection_active?
283283

284284
# Initializes and connects a PostgreSQL adapter.
285285
def initialize(connection, logger, connection_parameters, config)
286-
super(connection, logger, config)
287-
288286
@connection_parameters = connection_parameters || {}
289287

290-
# @local_tz is initialized as nil to avoid warnings when connect tries to use it
291-
@local_tz = nil
292288
@max_identifier_length = nil
289+
@type_map = nil
293290

294-
configure_connection
295-
add_pg_encoders
296-
add_pg_decoders
291+
super(connection, logger, config)
297292

298-
@type_map = Type::HashLookupTypeMap.new
299-
initialize_type_map
300-
@local_tz = execute("SHOW TIME ZONE", "SCHEMA").first["TimeZone"]
301293
@use_insert_returning = @config.key?(:insert_returning) ? self.class.type_cast_config_to_boolean(@config[:insert_returning]) : true
302294
end
303295

@@ -318,31 +310,38 @@ def active?
318310
end
319311

320312
def reload_type_map # :nodoc:
321-
type_map.clear
322-
initialize_type_map
313+
@lock.synchronize do
314+
if @type_map
315+
type_map.clear
316+
else
317+
@type_map = Type::HashLookupTypeMap.new
318+
end
319+
320+
initialize_type_map
321+
end
323322
end
324323

325324
# Close then reopen the connection.
326325
def reconnect!
327326
@lock.synchronize do
328-
@raw_connection.reset
327+
begin
328+
@raw_connection.reset
329+
rescue PG::ConnectionBad
330+
connect
331+
end
332+
329333
super
330-
configure_connection
331-
reload_type_map
332-
rescue PG::ConnectionBad
333-
connect
334334
end
335335
end
336336

337337
def reset!
338338
@lock.synchronize do
339-
reset_transaction
340339
unless @raw_connection.transaction_status == ::PG::PQTRANS_IDLE
341340
@raw_connection.query "ROLLBACK"
342341
end
343342
@raw_connection.query "DISCARD ALL"
344-
clear_cache!(new_connection: true)
345-
configure_connection
343+
344+
super
346345
end
347346
end
348347

@@ -853,9 +852,6 @@ def prepare_statement(sql, binds)
853852
# connected server's characteristics.
854853
def connect
855854
@raw_connection = self.class.new_client(@connection_parameters)
856-
configure_connection
857-
add_pg_encoders
858-
add_pg_decoders
859855
end
860856

861857
# Configures the encoding, verbosity, schema search path, and time zone of the connection.
@@ -872,16 +868,6 @@ def configure_connection
872868

873869
variables = @config.fetch(:variables, {}).stringify_keys
874870

875-
# If using Active Record's time zone support configure the connection to return
876-
# TIMESTAMP WITH ZONE types in UTC.
877-
unless variables["timezone"]
878-
if default_timezone == :utc
879-
variables["timezone"] = "UTC"
880-
elsif @local_tz
881-
variables["timezone"] = @local_tz
882-
end
883-
end
884-
885871
# Set interval output format to ISO 8601 for ease of parsing by ActiveSupport::Duration.parse
886872
execute("SET intervalstyle = iso_8601", "SCHEMA")
887873

@@ -895,6 +881,28 @@ def configure_connection
895881
execute("SET SESSION #{k} TO #{quote(v)}", "SCHEMA")
896882
end
897883
end
884+
885+
add_pg_encoders
886+
add_pg_decoders
887+
888+
reload_type_map
889+
end
890+
891+
def reconfigure_connection_timezone
892+
variables = @config.fetch(:variables, {}).stringify_keys
893+
894+
# If it's been directly configured as a connection variable, we don't
895+
# need to do anything here; it will be set up by configure_connection
896+
# and then never changed.
897+
return if variables["timezone"]
898+
899+
# If using Active Record's time zone support configure the connection
900+
# to return TIMESTAMP WITH ZONE types in UTC.
901+
if default_timezone == :utc
902+
execute("SET SESSION timezone TO 'UTC'", "SCHEMA")
903+
else
904+
execute("SET SESSION timezone TO DEFAULT", "SCHEMA")
905+
end
898906
end
899907

900908
# Returns the list of a table's column names, data types, and default values.
@@ -987,7 +995,7 @@ def update_typemap_for_default_timezone
987995

988996
# if default timezone has changed, we need to reconfigure the connection
989997
# (specifically, the session time zone)
990-
configure_connection
998+
reconfigure_connection_timezone
991999
end
9921000
end
9931001

activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,6 @@ def dealloc(stmt)
8888
def initialize(connection, logger, connection_options, config)
8989
@memory_database = config[:database] == ":memory:"
9090
super(connection, logger, config)
91-
configure_connection
9291
end
9392

9493
def self.database_exists?(config)
@@ -165,12 +164,17 @@ def active?
165164
end
166165

167166
def reconnect!
168-
unless @raw_connection.closed?
169-
@raw_connection.rollback rescue nil
167+
@lock.synchronize do
168+
if active?
169+
@raw_connection.rollback rescue nil
170+
else
171+
connect
172+
end
173+
174+
super
170175
end
171-
super
172-
connect if @raw_connection.closed?
173176
end
177+
alias :reset! :reconnect!
174178

175179
# Disconnects from the database if already connected. Otherwise, this
176180
# method does nothing.
@@ -608,7 +612,6 @@ def connect
608612
@config[:database].to_s,
609613
@config.merge(results_as_hash: true)
610614
)
611-
configure_connection
612615
end
613616

614617
def configure_connection

0 commit comments

Comments
 (0)