mirror of https://github.com/rails/rails
Eliminate missed `lease_connection` calls
Followup: https://github.com/rails/rails/pull/51353 Fix: https://github.com/rails/rails/issues/51722 Not too sure what happened, but I somehow missed quite a number of `lease_connection` calls inside Active Record.
This commit is contained in:
parent
793ff00442
commit
fa048105d1
|
@ -6,21 +6,23 @@ module ActiveRecord
|
|||
module Associations
|
||||
# Keeps track of table aliases for ActiveRecord::Associations::JoinDependency
|
||||
class AliasTracker # :nodoc:
|
||||
def self.create(connection, initial_table, joins, aliases = nil)
|
||||
if joins.empty?
|
||||
aliases ||= Hash.new(0)
|
||||
elsif aliases
|
||||
default_proc = aliases.default_proc || proc { 0 }
|
||||
aliases.default_proc = proc { |h, k|
|
||||
h[k] = initial_count_for(connection, k, joins) + default_proc.call(h, k)
|
||||
}
|
||||
else
|
||||
aliases = Hash.new { |h, k|
|
||||
h[k] = initial_count_for(connection, k, joins)
|
||||
}
|
||||
def self.create(pool, initial_table, joins, aliases = nil)
|
||||
pool.with_connection do |connection|
|
||||
if joins.empty?
|
||||
aliases ||= Hash.new(0)
|
||||
elsif aliases
|
||||
default_proc = aliases.default_proc || proc { 0 }
|
||||
aliases.default_proc = proc { |h, k|
|
||||
h[k] = initial_count_for(connection, k, joins) + default_proc.call(h, k)
|
||||
}
|
||||
else
|
||||
aliases = Hash.new { |h, k|
|
||||
h[k] = initial_count_for(connection, k, joins)
|
||||
}
|
||||
end
|
||||
aliases[initial_table] = 1
|
||||
new(connection.table_alias_length, aliases)
|
||||
end
|
||||
aliases[initial_table] = 1
|
||||
new(connection, aliases)
|
||||
end
|
||||
|
||||
def self.initial_count_for(connection, name, table_joins)
|
||||
|
@ -46,9 +48,9 @@ module ActiveRecord
|
|||
end
|
||||
|
||||
# table_joins is an array of arel joins which might conflict with the aliases we assign here
|
||||
def initialize(connection, aliases)
|
||||
@aliases = aliases
|
||||
@connection = connection
|
||||
def initialize(table_alias_length, aliases)
|
||||
@aliases = aliases
|
||||
@table_alias_length = table_alias_length
|
||||
end
|
||||
|
||||
def aliased_table_for(arel_table, table_name = nil)
|
||||
|
@ -60,7 +62,7 @@ module ActiveRecord
|
|||
arel_table = arel_table.alias(table_name) if arel_table.name != table_name
|
||||
else
|
||||
# Otherwise, we need to use an alias
|
||||
aliased_name = @connection.table_alias_for(yield)
|
||||
aliased_name = table_alias_for(yield)
|
||||
|
||||
# Update the count
|
||||
count = aliases[aliased_name] += 1
|
||||
|
@ -76,8 +78,12 @@ module ActiveRecord
|
|||
attr_reader :aliases
|
||||
|
||||
private
|
||||
def table_alias_for(table_name)
|
||||
table_name[0...@table_alias_length].tr(".", "_")
|
||||
end
|
||||
|
||||
def truncate(name)
|
||||
name.slice(0, @connection.table_alias_length - 2)
|
||||
name.slice(0, @table_alias_length - 2)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -239,8 +239,10 @@ module ActiveRecord
|
|||
|
||||
def _default_attributes # :nodoc:
|
||||
@default_attributes ||= begin
|
||||
attributes_hash = columns_hash.transform_values do |column|
|
||||
ActiveModel::Attribute.from_database(column.name, column.default, type_for_column(column))
|
||||
attributes_hash = with_connection do |connection|
|
||||
columns_hash.transform_values do |column|
|
||||
ActiveModel::Attribute.from_database(column.name, column.default, type_for_column(connection, column))
|
||||
end
|
||||
end
|
||||
|
||||
attribute_set = ActiveModel::AttributeSet.new(attributes_hash)
|
||||
|
@ -295,7 +297,7 @@ module ActiveRecord
|
|||
Type.lookup(name, **options, adapter: Type.adapter_name_from(self))
|
||||
end
|
||||
|
||||
def type_for_column(column)
|
||||
def type_for_column(connection, column)
|
||||
hook_attribute_type(column.name, super)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -93,8 +93,8 @@ module ActiveRecord
|
|||
end
|
||||
end
|
||||
|
||||
def lease_connection(**)
|
||||
connection = super
|
||||
def checkout_and_verify(connection)
|
||||
super
|
||||
connection.query_cache ||= query_cache
|
||||
connection
|
||||
end
|
||||
|
@ -147,6 +147,12 @@ module ActiveRecord
|
|||
end
|
||||
end
|
||||
|
||||
def query_cache
|
||||
@thread_query_caches.compute_if_absent(ActiveSupport::IsolatedExecutionState.context) do
|
||||
Store.new(@query_cache_max_size)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def prune_thread_cache
|
||||
dead_threads = @thread_query_caches.keys.reject(&:alive?)
|
||||
|
@ -154,12 +160,6 @@ module ActiveRecord
|
|||
@thread_query_caches.delete(dead_thread)
|
||||
end
|
||||
end
|
||||
|
||||
def query_cache
|
||||
@thread_query_caches.compute_if_absent(ActiveSupport::IsolatedExecutionState.context) do
|
||||
Store.new(@query_cache_max_size)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
attr_accessor :query_cache
|
||||
|
|
|
@ -376,9 +376,9 @@ module ActiveRecord
|
|||
TypeCaster::Map.new(self)
|
||||
end
|
||||
|
||||
def cached_find_by_statement(key, &block) # :nodoc:
|
||||
cache = @find_by_statement_cache[lease_connection.prepared_statements]
|
||||
cache.compute_if_absent(key) { StatementCache.create(lease_connection, &block) }
|
||||
def cached_find_by_statement(connection, key, &block) # :nodoc:
|
||||
cache = @find_by_statement_cache[connection.prepared_statements]
|
||||
cache.compute_if_absent(key) { StatementCache.create(connection, &block) }
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -419,21 +419,23 @@ module ActiveRecord
|
|||
end
|
||||
|
||||
def cached_find_by(keys, values)
|
||||
statement = cached_find_by_statement(keys) { |params|
|
||||
wheres = keys.index_with do |key|
|
||||
if key.is_a?(Array)
|
||||
[key.map { params.bind }]
|
||||
else
|
||||
params.bind
|
||||
with_connection do |connection|
|
||||
statement = cached_find_by_statement(connection, keys) { |params|
|
||||
wheres = keys.index_with do |key|
|
||||
if key.is_a?(Array)
|
||||
[key.map { params.bind }]
|
||||
else
|
||||
params.bind
|
||||
end
|
||||
end
|
||||
end
|
||||
where(wheres).limit(1)
|
||||
}
|
||||
where(wheres).limit(1)
|
||||
}
|
||||
|
||||
begin
|
||||
statement.execute(values.flatten, lease_connection, allow_retry: true).first
|
||||
rescue TypeError
|
||||
raise ActiveRecord::StatementInvalid
|
||||
begin
|
||||
statement.execute(values.flatten, lease_connection, allow_retry: true).first
|
||||
rescue TypeError
|
||||
raise ActiveRecord::StatementInvalid
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -379,7 +379,7 @@ module ActiveRecord
|
|||
|
||||
def reset_sequence_name # :nodoc:
|
||||
@explicit_sequence_name = false
|
||||
@sequence_name = lease_connection.default_sequence_name(table_name, primary_key)
|
||||
@sequence_name = with_connection { |c| c.default_sequence_name(table_name, primary_key) }
|
||||
end
|
||||
|
||||
# Sets the name of the sequence to use when generating ids to the given
|
||||
|
@ -404,13 +404,13 @@ module ActiveRecord
|
|||
# Determines if the primary key values should be selected from their
|
||||
# corresponding sequence before the insert statement.
|
||||
def prefetch_primary_key?
|
||||
lease_connection.prefetch_primary_key?(table_name)
|
||||
with_connection { |c| c.prefetch_primary_key?(table_name) }
|
||||
end
|
||||
|
||||
# Returns the next value that will be used as the primary key on
|
||||
# an insert statement.
|
||||
def next_sequence_value
|
||||
lease_connection.next_sequence_value(sequence_name)
|
||||
with_connection { |c| c.next_sequence_value(sequence_name) }
|
||||
end
|
||||
|
||||
# Indicates whether the table associated with this class exists
|
||||
|
@ -435,10 +435,10 @@ module ActiveRecord
|
|||
@columns ||= columns_hash.values.freeze
|
||||
end
|
||||
|
||||
def _returning_columns_for_insert # :nodoc:
|
||||
def _returning_columns_for_insert(connection) # :nodoc:
|
||||
@_returning_columns_for_insert ||= begin
|
||||
auto_populated_columns = columns.filter_map do |c|
|
||||
c.name if lease_connection.return_value_after_insert?(c)
|
||||
c.name if connection.return_value_after_insert?(c)
|
||||
end
|
||||
|
||||
auto_populated_columns.empty? ? Array(primary_key) : auto_populated_columns
|
||||
|
@ -523,7 +523,7 @@ module ActiveRecord
|
|||
# end
|
||||
# end
|
||||
def reset_column_information
|
||||
lease_connection.clear_cache!
|
||||
connection_pool.active_connection&.clear_cache!
|
||||
([self] + descendants).each(&:undefine_attribute_methods)
|
||||
schema_cache.clear_data_source_cache!(table_name)
|
||||
|
||||
|
@ -617,8 +617,8 @@ module ActiveRecord
|
|||
end
|
||||
end
|
||||
|
||||
def type_for_column(column)
|
||||
type = lease_connection.lookup_cast_type_from_column(column)
|
||||
def type_for_column(connection, column)
|
||||
type = connection.lookup_cast_type_from_column(column)
|
||||
|
||||
if immutable_strings_by_default && type.respond_to?(:to_immutable_string)
|
||||
type = type.to_immutable_string
|
||||
|
|
|
@ -568,7 +568,7 @@ module ActiveRecord
|
|||
delete_by(primary_key => id_or_array)
|
||||
end
|
||||
|
||||
def _insert_record(values, returning) # :nodoc:
|
||||
def _insert_record(connection, values, returning) # :nodoc:
|
||||
primary_key = self.primary_key
|
||||
primary_key_value = nil
|
||||
|
||||
|
@ -583,12 +583,12 @@ module ActiveRecord
|
|||
|
||||
with_connection do |c|
|
||||
if values.empty?
|
||||
im.insert(c.empty_insert_statement_value(primary_key))
|
||||
im.insert(connection.empty_insert_statement_value(primary_key))
|
||||
else
|
||||
im.insert(values.transform_keys { |name| arel_table[name] })
|
||||
end
|
||||
|
||||
c.insert(
|
||||
connection.insert(
|
||||
im, "#{self} Create", primary_key || false, primary_key_value,
|
||||
returning: returning
|
||||
)
|
||||
|
@ -1255,16 +1255,19 @@ module ActiveRecord
|
|||
def _create_record(attribute_names = self.attribute_names)
|
||||
attribute_names = attributes_for_create(attribute_names)
|
||||
|
||||
returning_columns = self.class._returning_columns_for_insert
|
||||
self.class.with_connection do |connection|
|
||||
returning_columns = self.class._returning_columns_for_insert(connection)
|
||||
|
||||
returning_values = self.class._insert_record(
|
||||
attributes_with_values(attribute_names),
|
||||
returning_columns
|
||||
)
|
||||
returning_values = self.class._insert_record(
|
||||
connection,
|
||||
attributes_with_values(attribute_names),
|
||||
returning_columns
|
||||
)
|
||||
|
||||
returning_columns.zip(returning_values).each do |column, value|
|
||||
_write_attribute(column, value) if !_read_attribute(column)
|
||||
end if returning_values
|
||||
returning_columns.zip(returning_values).each do |column, value|
|
||||
_write_attribute(column, value) if !_read_attribute(column)
|
||||
end if returning_values
|
||||
end
|
||||
|
||||
@new_record = false
|
||||
@previously_new_record = true
|
||||
|
|
|
@ -48,18 +48,25 @@ module ActiveRecord
|
|||
# Note that building your own SQL query string from user input may expose your application to
|
||||
# injection attacks (https://guides.rubyonrails.org/security.html#sql-injection).
|
||||
def find_by_sql(sql, binds = [], preparable: nil, allow_retry: false, &block)
|
||||
_load_from_sql(_query_by_sql(sql, binds, preparable: preparable, allow_retry: allow_retry), &block)
|
||||
result = with_connection do |c|
|
||||
_query_by_sql(c, sql, binds, preparable: preparable, allow_retry: allow_retry)
|
||||
end
|
||||
_load_from_sql(result, &block)
|
||||
end
|
||||
|
||||
# Same as <tt>#find_by_sql</tt> but perform the query asynchronously and returns an ActiveRecord::Promise.
|
||||
def async_find_by_sql(sql, binds = [], preparable: nil, &block)
|
||||
_query_by_sql(sql, binds, preparable: preparable, async: true).then do |result|
|
||||
result = with_connection do |c|
|
||||
_query_by_sql(c, sql, binds, preparable: preparable, async: true)
|
||||
end
|
||||
|
||||
result.then do |result|
|
||||
_load_from_sql(result, &block)
|
||||
end
|
||||
end
|
||||
|
||||
def _query_by_sql(sql, binds = [], preparable: nil, async: false, allow_retry: false) # :nodoc:
|
||||
lease_connection.select_all(sanitize_sql(sql), "#{name} Load", binds, preparable: preparable, async: async, allow_retry: allow_retry)
|
||||
def _query_by_sql(connection, sql, binds = [], preparable: nil, async: false, allow_retry: false) # :nodoc:
|
||||
connection.select_all(sanitize_sql(sql), "#{name} Load", binds, preparable: preparable, async: async, allow_retry: allow_retry)
|
||||
end
|
||||
|
||||
def _load_from_sql(result_set, &block) # :nodoc:
|
||||
|
@ -99,12 +106,16 @@ module ActiveRecord
|
|||
#
|
||||
# * +sql+ - An SQL statement which should return a count query from the database, see the example above.
|
||||
def count_by_sql(sql)
|
||||
lease_connection.select_value(sanitize_sql(sql), "#{name} Count").to_i
|
||||
with_connection do |c|
|
||||
c.select_value(sanitize_sql(sql), "#{name} Count").to_i
|
||||
end
|
||||
end
|
||||
|
||||
# Same as <tt>#count_by_sql</tt> but perform the query asynchronously and returns an ActiveRecord::Promise.
|
||||
def async_count_by_sql(sql)
|
||||
lease_connection.select_value(sanitize_sql(sql), "#{name} Count", async: true).then(&:to_i)
|
||||
with_connection do |c|
|
||||
c.select_value(sanitize_sql(sql), "#{name} Count", async: true).then(&:to_i)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -529,7 +529,9 @@ module ActiveRecord
|
|||
if polymorphic?
|
||||
key = [key, owner._read_attribute(@foreign_type)]
|
||||
end
|
||||
klass.cached_find_by_statement(key, &block)
|
||||
klass.with_connection do |connection|
|
||||
klass.cached_find_by_statement(connection, key, &block)
|
||||
end
|
||||
end
|
||||
|
||||
def join_table
|
||||
|
|
|
@ -263,12 +263,14 @@ module ActiveRecord
|
|||
# and failed due to validation errors it won't be persisted, you get what #create returns in
|
||||
# such situation.
|
||||
def create_or_find_by(attributes, &block)
|
||||
transaction(requires_new: true) { create(attributes, &block) }
|
||||
rescue ActiveRecord::RecordNotUnique
|
||||
if lease_connection.transaction_open?
|
||||
where(attributes).lock.find_by!(attributes)
|
||||
else
|
||||
find_by!(attributes)
|
||||
with_connection do |connection|
|
||||
transaction(requires_new: true) { create(attributes, &block) }
|
||||
rescue ActiveRecord::RecordNotUnique
|
||||
if connection.transaction_open?
|
||||
where(attributes).lock.find_by!(attributes)
|
||||
else
|
||||
find_by!(attributes)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -276,12 +278,14 @@ module ActiveRecord
|
|||
# {create!}[rdoc-ref:Persistence::ClassMethods#create!] so an exception
|
||||
# is raised if the created record is invalid.
|
||||
def create_or_find_by!(attributes, &block)
|
||||
transaction(requires_new: true) { create!(attributes, &block) }
|
||||
rescue ActiveRecord::RecordNotUnique
|
||||
if lease_connection.transaction_open?
|
||||
where(attributes).lock.find_by!(attributes)
|
||||
else
|
||||
find_by!(attributes)
|
||||
with_connection do |connection|
|
||||
transaction(requires_new: true) { create!(attributes, &block) }
|
||||
rescue ActiveRecord::RecordNotUnique
|
||||
if connection.transaction_open?
|
||||
where(attributes).lock.find_by!(attributes)
|
||||
else
|
||||
find_by!(attributes)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -590,18 +594,18 @@ module ActiveRecord
|
|||
values = Arel.sql(klass.sanitize_sql_for_assignment(updates, table.name))
|
||||
end
|
||||
|
||||
arel = eager_loading? ? apply_join_dependency.arel : build_arel
|
||||
arel.source.left = table
|
||||
|
||||
group_values_arel_columns = arel_columns(group_values.uniq)
|
||||
having_clause_ast = having_clause.ast unless having_clause.empty?
|
||||
key = if klass.composite_primary_key?
|
||||
primary_key.map { |pk| table[pk] }
|
||||
else
|
||||
table[primary_key]
|
||||
end
|
||||
stmt = arel.compile_update(values, key, having_clause_ast, group_values_arel_columns)
|
||||
klass.with_connection do |c|
|
||||
arel = eager_loading? ? apply_join_dependency.arel : build_arel(c)
|
||||
arel.source.left = table
|
||||
|
||||
group_values_arel_columns = arel_columns(group_values.uniq)
|
||||
having_clause_ast = having_clause.ast unless having_clause.empty?
|
||||
key = if klass.composite_primary_key?
|
||||
primary_key.map { |pk| table[pk] }
|
||||
else
|
||||
table[primary_key]
|
||||
end
|
||||
stmt = arel.compile_update(values, key, having_clause_ast, group_values_arel_columns)
|
||||
c.update(stmt, "#{klass} Update All").tap { reset }
|
||||
end
|
||||
end
|
||||
|
@ -730,19 +734,19 @@ module ActiveRecord
|
|||
raise ActiveRecordError.new("delete_all doesn't support #{invalid_methods.join(', ')}")
|
||||
end
|
||||
|
||||
arel = eager_loading? ? apply_join_dependency.arel : build_arel
|
||||
arel.source.left = table
|
||||
|
||||
group_values_arel_columns = arel_columns(group_values.uniq)
|
||||
having_clause_ast = having_clause.ast unless having_clause.empty?
|
||||
key = if klass.composite_primary_key?
|
||||
primary_key.map { |pk| table[pk] }
|
||||
else
|
||||
table[primary_key]
|
||||
end
|
||||
stmt = arel.compile_delete(key, having_clause_ast, group_values_arel_columns)
|
||||
|
||||
klass.with_connection do |c|
|
||||
arel = eager_loading? ? apply_join_dependency.arel : build_arel(c)
|
||||
arel.source.left = table
|
||||
|
||||
group_values_arel_columns = arel_columns(group_values.uniq)
|
||||
having_clause_ast = having_clause.ast unless having_clause.empty?
|
||||
key = if klass.composite_primary_key?
|
||||
primary_key.map { |pk| table[pk] }
|
||||
else
|
||||
table[primary_key]
|
||||
end
|
||||
stmt = arel.compile_delete(key, having_clause_ast, group_values_arel_columns)
|
||||
|
||||
c.delete(stmt, "#{klass} Delete All").tap { reset }
|
||||
end
|
||||
end
|
||||
|
@ -947,7 +951,7 @@ module ActiveRecord
|
|||
end
|
||||
|
||||
def alias_tracker(joins = [], aliases = nil) # :nodoc:
|
||||
ActiveRecord::Associations::AliasTracker.create(lease_connection, table.name, joins, aliases)
|
||||
ActiveRecord::Associations::AliasTracker.create(connection_pool, table.name, joins, aliases)
|
||||
end
|
||||
|
||||
class StrictLoadingScope # :nodoc:
|
||||
|
@ -1075,7 +1079,7 @@ module ActiveRecord
|
|||
if where_clause.contradiction?
|
||||
[].freeze
|
||||
elsif eager_loading?
|
||||
with_connection do |c|
|
||||
klass.with_connection do |c|
|
||||
apply_join_dependency do |relation, join_dependency|
|
||||
if relation.null_relation?
|
||||
[].freeze
|
||||
|
@ -1087,7 +1091,9 @@ module ActiveRecord
|
|||
end
|
||||
end
|
||||
else
|
||||
klass._query_by_sql(arel, async: async)
|
||||
klass.with_connection do |c|
|
||||
klass._query_by_sql(c, arel, async: async)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -510,73 +510,73 @@ module ActiveRecord
|
|||
end
|
||||
group_fields = arel_columns(group_fields)
|
||||
|
||||
column_alias_tracker = ColumnAliasTracker.new(lease_connection)
|
||||
@klass.with_connection do |connection|
|
||||
column_alias_tracker = ColumnAliasTracker.new(connection)
|
||||
|
||||
group_aliases = group_fields.map { |field|
|
||||
field = lease_connection.visitor.compile(field) if Arel.arel_node?(field)
|
||||
column_alias_tracker.alias_for(field.to_s.downcase)
|
||||
}
|
||||
group_columns = group_aliases.zip(group_fields)
|
||||
group_aliases = group_fields.map { |field|
|
||||
field = connection.visitor.compile(field) if Arel.arel_node?(field)
|
||||
column_alias_tracker.alias_for(field.to_s.downcase)
|
||||
}
|
||||
group_columns = group_aliases.zip(group_fields)
|
||||
|
||||
column = aggregate_column(column_name)
|
||||
column_alias = column_alias_tracker.alias_for("#{operation} #{column_name.to_s.downcase}")
|
||||
select_value = operation_over_aggregate_column(column, operation, distinct)
|
||||
select_value.as(adapter_class.quote_column_name(column_alias))
|
||||
column = aggregate_column(column_name)
|
||||
column_alias = column_alias_tracker.alias_for("#{operation} #{column_name.to_s.downcase}")
|
||||
select_value = operation_over_aggregate_column(column, operation, distinct)
|
||||
select_value.as(adapter_class.quote_column_name(column_alias))
|
||||
|
||||
select_values = [select_value]
|
||||
select_values += self.select_values unless having_clause.empty?
|
||||
select_values = [select_value]
|
||||
select_values += self.select_values unless having_clause.empty?
|
||||
|
||||
select_values.concat group_columns.map { |aliaz, field|
|
||||
aliaz = adapter_class.quote_column_name(aliaz)
|
||||
if field.respond_to?(:as)
|
||||
field.as(aliaz)
|
||||
else
|
||||
"#{field} AS #{aliaz}"
|
||||
end
|
||||
}
|
||||
|
||||
relation = except(:group).distinct!(false)
|
||||
relation.group_values = group_fields
|
||||
relation.select_values = select_values
|
||||
|
||||
result = skip_query_cache_if_necessary do
|
||||
@klass.with_connection do |c|
|
||||
c.select_all(relation.arel, "#{@klass.name} #{operation.capitalize}", async: @async)
|
||||
end
|
||||
end
|
||||
|
||||
result.then do |calculated_data|
|
||||
if association
|
||||
key_ids = calculated_data.collect { |row| row[group_aliases.first] }
|
||||
key_records = association.klass.base_class.where(association.klass.base_class.primary_key => key_ids)
|
||||
key_records = key_records.index_by(&:id)
|
||||
end
|
||||
|
||||
key_types = group_columns.each_with_object({}) do |(aliaz, col_name), types|
|
||||
types[aliaz] = col_name.try(:type_caster) ||
|
||||
type_for(col_name) do
|
||||
calculated_data.column_types.fetch(aliaz, Type.default_value)
|
||||
end
|
||||
end
|
||||
|
||||
hash_rows = calculated_data.cast_values(key_types).map! do |row|
|
||||
calculated_data.columns.each_with_object({}).with_index do |(col_name, hash), i|
|
||||
hash[col_name] = row[i]
|
||||
select_values.concat group_columns.map { |aliaz, field|
|
||||
aliaz = adapter_class.quote_column_name(aliaz)
|
||||
if field.respond_to?(:as)
|
||||
field.as(aliaz)
|
||||
else
|
||||
"#{field} AS #{aliaz}"
|
||||
end
|
||||
}
|
||||
|
||||
relation = except(:group).distinct!(false)
|
||||
relation.group_values = group_fields
|
||||
relation.select_values = select_values
|
||||
|
||||
result = skip_query_cache_if_necessary do
|
||||
connection.select_all(relation.arel, "#{@klass.name} #{operation.capitalize}", async: @async)
|
||||
end
|
||||
|
||||
if operation != "count"
|
||||
type = column.try(:type_caster) ||
|
||||
lookup_cast_type_from_join_dependencies(column_name.to_s) || Type.default_value
|
||||
type = type.subtype if Enum::EnumType === type
|
||||
end
|
||||
result.then do |calculated_data|
|
||||
if association
|
||||
key_ids = calculated_data.collect { |row| row[group_aliases.first] }
|
||||
key_records = association.klass.base_class.where(association.klass.base_class.primary_key => key_ids)
|
||||
key_records = key_records.index_by(&:id)
|
||||
end
|
||||
|
||||
hash_rows.each_with_object({}) do |row, result|
|
||||
key = group_aliases.map { |aliaz| row[aliaz] }
|
||||
key = key.first if key.size == 1
|
||||
key = key_records[key] if associated
|
||||
key_types = group_columns.each_with_object({}) do |(aliaz, col_name), types|
|
||||
types[aliaz] = col_name.try(:type_caster) ||
|
||||
type_for(col_name) do
|
||||
calculated_data.column_types.fetch(aliaz, Type.default_value)
|
||||
end
|
||||
end
|
||||
|
||||
result[key] = type_cast_calculated_value(row[column_alias], operation, type)
|
||||
hash_rows = calculated_data.cast_values(key_types).map! do |row|
|
||||
calculated_data.columns.each_with_object({}).with_index do |(col_name, hash), i|
|
||||
hash[col_name] = row[i]
|
||||
end
|
||||
end
|
||||
|
||||
if operation != "count"
|
||||
type = column.try(:type_caster) ||
|
||||
lookup_cast_type_from_join_dependencies(column_name.to_s) || Type.default_value
|
||||
type = type.subtype if Enum::EnumType === type
|
||||
end
|
||||
|
||||
hash_rows.each_with_object({}) do |row, result|
|
||||
key = group_aliases.map { |aliaz| row[aliaz] }
|
||||
key = key.first if key.size == 1
|
||||
key = key_records[key] if associated
|
||||
|
||||
result[key] = type_cast_calculated_value(row[column_alias], operation, type)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1570,7 +1570,7 @@ module ActiveRecord
|
|||
|
||||
# Returns the Arel object associated with the relation.
|
||||
def arel(aliases = nil) # :nodoc:
|
||||
@arel ||= build_arel(aliases)
|
||||
@arel ||= with_connection { |c| build_arel(c, aliases) }
|
||||
end
|
||||
|
||||
def construct_join_dependency(associations, join_type) # :nodoc:
|
||||
|
@ -1709,14 +1709,14 @@ module ActiveRecord
|
|||
raise ImmutableRelation if @loaded || @arel
|
||||
end
|
||||
|
||||
def build_arel(aliases = nil)
|
||||
def build_arel(connection, aliases = nil)
|
||||
arel = Arel::SelectManager.new(table)
|
||||
|
||||
build_joins(arel.join_sources, aliases)
|
||||
|
||||
arel.where(where_clause.ast) unless where_clause.empty?
|
||||
arel.having(having_clause.ast) unless having_clause.empty?
|
||||
arel.take(build_cast_value("LIMIT", lease_connection.sanitize_limit(limit_value))) if limit_value
|
||||
arel.take(build_cast_value("LIMIT", connection.sanitize_limit(limit_value))) if limit_value
|
||||
arel.skip(build_cast_value("OFFSET", offset_value.to_i)) if offset_value
|
||||
arel.group(*arel_columns(group_values.uniq)) unless group_values.empty?
|
||||
|
||||
|
|
|
@ -163,13 +163,19 @@ module ActiveRecord
|
|||
def sanitize_sql_array(ary)
|
||||
statement, *values = ary
|
||||
if values.first.is_a?(Hash) && /:\w+/.match?(statement)
|
||||
replace_named_bind_variables(statement, values.first)
|
||||
with_connection do |c|
|
||||
replace_named_bind_variables(c, statement, values.first)
|
||||
end
|
||||
elsif statement.include?("?")
|
||||
replace_bind_variables(statement, values)
|
||||
with_connection do |c|
|
||||
replace_bind_variables(c, statement, values)
|
||||
end
|
||||
elsif statement.blank?
|
||||
statement
|
||||
else
|
||||
statement % values.collect { |value| lease_connection.quote_string(value.to_s) }
|
||||
with_connection do |c|
|
||||
statement % values.collect { |value| c.quote_string(value.to_s) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -193,48 +199,47 @@ module ActiveRecord
|
|||
end
|
||||
|
||||
private
|
||||
def replace_bind_variables(statement, values)
|
||||
def replace_bind_variables(connection, statement, values)
|
||||
raise_if_bind_arity_mismatch(statement, statement.count("?"), values.size)
|
||||
bound = values.dup
|
||||
c = lease_connection
|
||||
statement.gsub(/\?/) do
|
||||
replace_bind_variable(bound.shift, c)
|
||||
replace_bind_variable(connection, bound.shift)
|
||||
end
|
||||
end
|
||||
|
||||
def replace_bind_variable(value, c = lease_connection)
|
||||
def replace_bind_variable(connection, value)
|
||||
if ActiveRecord::Relation === value
|
||||
value.to_sql
|
||||
else
|
||||
quote_bound_value(value, c)
|
||||
quote_bound_value(connection, value)
|
||||
end
|
||||
end
|
||||
|
||||
def replace_named_bind_variables(statement, bind_vars)
|
||||
def replace_named_bind_variables(connection, statement, bind_vars)
|
||||
statement.gsub(/([:\\]?):([a-zA-Z]\w*)/) do |match|
|
||||
if $1 == ":" # skip PostgreSQL casts
|
||||
match # return the whole match
|
||||
elsif $1 == "\\" # escaped literal colon
|
||||
match[1..-1] # return match with escaping backlash char removed
|
||||
elsif bind_vars.include?(match = $2.to_sym)
|
||||
replace_bind_variable(bind_vars[match])
|
||||
replace_bind_variable(connection, bind_vars[match])
|
||||
else
|
||||
raise PreparedStatementInvalid, "missing value for :#{match} in #{statement}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def quote_bound_value(value, c = lease_connection)
|
||||
def quote_bound_value(connection, value)
|
||||
if value.respond_to?(:map) && !value.acts_like?(:string)
|
||||
values = value.map { |v| v.respond_to?(:id_for_database) ? v.id_for_database : v }
|
||||
if values.empty?
|
||||
c.quote(c.cast_bound_value(nil))
|
||||
connection.quote(connection.cast_bound_value(nil))
|
||||
else
|
||||
values.map! { |v| c.quote(c.cast_bound_value(v)) }.join(",")
|
||||
values.map! { |v| connection.quote(connection.cast_bound_value(v)) }.join(",")
|
||||
end
|
||||
else
|
||||
value = value.id_for_database if value.respond_to?(:id_for_database)
|
||||
c.quote(c.cast_bound_value(value))
|
||||
connection.quote(connection.cast_bound_value(value))
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ module ActiveRecord
|
|||
end
|
||||
|
||||
def current_time_from_proper_timezone
|
||||
lease_connection.default_timezone == :utc ? Time.now.utc : Time.now
|
||||
with_connection { |c| c.default_timezone == :utc ? Time.now.utc : Time.now }
|
||||
end
|
||||
|
||||
protected
|
||||
|
|
|
@ -226,7 +226,7 @@ module ActiveRecord
|
|||
|
||||
# Returns the current transaction. See ActiveRecord::Transactions API docs.
|
||||
def current_transaction
|
||||
connection_pool.active_connection&.current_transaction || ConnectionAdapters::NULL_TRANSACTION
|
||||
connection_pool.active_connection&.current_transaction || ConnectionAdapters::TransactionManager::NULL_TRANSACTION
|
||||
end
|
||||
|
||||
def before_commit(*args, &block) # :nodoc:
|
||||
|
|
|
@ -258,7 +258,7 @@ if ActiveRecord::Base.lease_connection.prepared_statements
|
|||
end
|
||||
|
||||
def cached_statement(klass, key)
|
||||
cache = klass.send(:cached_find_by_statement, key) do
|
||||
cache = klass.send(:cached_find_by_statement, @connection, key) do
|
||||
raise "#{klass} has no cached statement by #{key.inspect}"
|
||||
end
|
||||
cache.send(:query_builder).instance_variable_get(:@sql)
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "cases/helper"
|
||||
require "models/post"
|
||||
|
||||
module ActiveRecord
|
||||
class ConnectionHandlingTest < ActiveRecord::TestCase
|
||||
fixtures :posts
|
||||
|
||||
setup do
|
||||
@_permanent_connection_checkout_was = ActiveRecord.permanent_connection_checkout
|
||||
end
|
||||
|
@ -164,6 +167,21 @@ module ActiveRecord
|
|||
|
||||
assert_not_predicate ActiveRecord::Base.connection_pool, :active_connection?
|
||||
end
|
||||
|
||||
test "common APIs don't permanently hold a connection when permanent checkout is deprecated or disallowed" do
|
||||
ActiveRecord.permanent_connection_checkout = :deprecated
|
||||
ActiveRecord::Base.release_connection
|
||||
assert_not_predicate ActiveRecord::Base.connection_pool, :active_connection?
|
||||
|
||||
Post.create!(title: "foo", body: "bar")
|
||||
assert_not_predicate Post.connection_pool, :active_connection?
|
||||
|
||||
Post.first
|
||||
assert_not_predicate Post.connection_pool, :active_connection?
|
||||
|
||||
Post.count
|
||||
assert_not_predicate Post.connection_pool, :active_connection?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -35,8 +35,8 @@ class QueryCacheTest < ActiveRecord::TestCase
|
|||
end
|
||||
|
||||
def teardown
|
||||
Task.lease_connection.clear_query_cache
|
||||
ActiveRecord::Base.lease_connection.disable_query_cache!
|
||||
Task.connection_pool.clear_query_cache
|
||||
ActiveRecord::Base.connection_pool.disable_query_cache!
|
||||
super
|
||||
end
|
||||
|
||||
|
@ -45,10 +45,10 @@ class QueryCacheTest < ActiveRecord::TestCase
|
|||
|
||||
mw = middleware { |env|
|
||||
Post.first
|
||||
query_cache = ActiveRecord::Base.lease_connection.query_cache
|
||||
query_cache = ActiveRecord::Base.connection_pool.query_cache
|
||||
assert_equal 1, query_cache.size, query_cache.inspect
|
||||
Post.lease_connection.execute("SELECT 1")
|
||||
query_cache = ActiveRecord::Base.lease_connection.query_cache
|
||||
query_cache = ActiveRecord::Base.connection_pool.query_cache
|
||||
assert_equal 0, query_cache.size, query_cache.inspect
|
||||
}
|
||||
mw.call({})
|
||||
|
@ -61,10 +61,10 @@ class QueryCacheTest < ActiveRecord::TestCase
|
|||
|
||||
mw = middleware { |env|
|
||||
Post.first
|
||||
query_cache = ActiveRecord::Base.lease_connection.query_cache
|
||||
query_cache = ActiveRecord::Base.connection_pool.query_cache
|
||||
assert_equal 1, query_cache.size, query_cache.inspect
|
||||
Post.lease_connection.exec_query("SELECT 1")
|
||||
query_cache = ActiveRecord::Base.lease_connection.query_cache
|
||||
query_cache = ActiveRecord::Base.connection_pool.query_cache
|
||||
assert_equal 0, query_cache.size, query_cache.inspect
|
||||
}
|
||||
mw.call({})
|
||||
|
@ -77,13 +77,13 @@ class QueryCacheTest < ActiveRecord::TestCase
|
|||
|
||||
mw = middleware { |env|
|
||||
Post.first
|
||||
query_cache = ActiveRecord::Base.lease_connection.query_cache
|
||||
query_cache = ActiveRecord::Base.connection_pool.query_cache
|
||||
assert_equal 1, query_cache.size, query_cache.inspect
|
||||
Post.lease_connection.uncached do
|
||||
# should clear the cache
|
||||
Post.create!(title: "a new post", body: "and a body")
|
||||
end
|
||||
query_cache = ActiveRecord::Base.lease_connection.query_cache
|
||||
query_cache = ActiveRecord::Base.connection_pool.query_cache
|
||||
assert_equal 0, query_cache.size, query_cache.inspect
|
||||
}
|
||||
mw.call({})
|
||||
|
@ -96,12 +96,12 @@ class QueryCacheTest < ActiveRecord::TestCase
|
|||
|
||||
mw = middleware { |env|
|
||||
Post.first
|
||||
query_cache = ActiveRecord::Base.lease_connection.query_cache
|
||||
query_cache = ActiveRecord::Base.connection_pool.query_cache
|
||||
assert_equal 1, query_cache.size, query_cache.inspect
|
||||
Post.lease_connection.uncached do
|
||||
Post.count # shouldn't clear the cache
|
||||
end
|
||||
query_cache = ActiveRecord::Base.lease_connection.query_cache
|
||||
query_cache = ActiveRecord::Base.connection_pool.query_cache
|
||||
assert_equal 1, query_cache.size, query_cache.inspect
|
||||
}
|
||||
mw.call({})
|
||||
|
@ -115,7 +115,7 @@ class QueryCacheTest < ActiveRecord::TestCase
|
|||
mw = middleware { |env|
|
||||
Task.find 1
|
||||
Task.find 1
|
||||
query_cache = ActiveRecord::Base.lease_connection.query_cache
|
||||
query_cache = ActiveRecord::Base.connection_pool.query_cache
|
||||
assert_equal 1, query_cache.size, query_cache.inspect
|
||||
raise "lol borked"
|
||||
}
|
||||
|
@ -287,7 +287,7 @@ class QueryCacheTest < ActiveRecord::TestCase
|
|||
mw = middleware { |env|
|
||||
Task.find 1
|
||||
Task.find 1
|
||||
query_cache = ActiveRecord::Base.lease_connection.query_cache
|
||||
query_cache = ActiveRecord::Base.connection_pool.query_cache
|
||||
assert_equal 1, query_cache.size, query_cache.inspect
|
||||
[200, {}, nil]
|
||||
}
|
||||
|
@ -597,11 +597,11 @@ class QueryCacheTest < ActiveRecord::TestCase
|
|||
|
||||
middleware {
|
||||
assert ActiveRecord::Base.connection_pool.query_cache_enabled
|
||||
assert ActiveRecord::Base.lease_connection.query_cache_enabled
|
||||
assert ActiveRecord::Base.connection_pool.query_cache_enabled
|
||||
|
||||
Thread.new {
|
||||
assert_not ActiveRecord::Base.connection_pool.query_cache_enabled
|
||||
assert_not ActiveRecord::Base.lease_connection.query_cache_enabled
|
||||
assert_not ActiveRecord::Base.connection_pool.query_cache_enabled
|
||||
|
||||
ActiveRecord::Base.connection_handler.clear_active_connections!(:all)
|
||||
}.join
|
||||
|
@ -612,7 +612,7 @@ class QueryCacheTest < ActiveRecord::TestCase
|
|||
middleware {
|
||||
ActiveRecord::Base.connection_handler.connection_pool_list(:all).each do |pool|
|
||||
assert pool.query_cache_enabled
|
||||
assert pool.lease_connection.query_cache_enabled
|
||||
assert pool.with_connection(&:query_cache_enabled)
|
||||
end
|
||||
}.call({})
|
||||
end
|
||||
|
@ -709,11 +709,11 @@ class QueryCacheTest < ActiveRecord::TestCase
|
|||
def test_query_cache_uncached_dirties
|
||||
mw = middleware { |env|
|
||||
Post.first
|
||||
assert_no_changes -> { ActiveRecord::Base.lease_connection.query_cache.size } do
|
||||
assert_no_changes -> { ActiveRecord::Base.connection_pool.query_cache.size } do
|
||||
Post.uncached(dirties: false) { Post.create!(title: "a new post", body: "and a body") }
|
||||
end
|
||||
|
||||
assert_changes -> { ActiveRecord::Base.lease_connection.query_cache.size }, from: 1, to: 0 do
|
||||
assert_changes -> { ActiveRecord::Base.connection_pool.query_cache.size }, from: 1, to: 0 do
|
||||
Post.uncached(dirties: true) { Post.create!(title: "a new post", body: "and a body") }
|
||||
end
|
||||
}
|
||||
|
@ -723,11 +723,11 @@ class QueryCacheTest < ActiveRecord::TestCase
|
|||
def test_query_cache_connection_uncached_dirties
|
||||
mw = middleware { |env|
|
||||
Post.first
|
||||
assert_no_changes -> { ActiveRecord::Base.lease_connection.query_cache.size } do
|
||||
assert_no_changes -> { ActiveRecord::Base.connection_pool.query_cache.size } do
|
||||
Post.lease_connection.uncached(dirties: false) { Post.create!(title: "a new post", body: "and a body") }
|
||||
end
|
||||
|
||||
assert_changes -> { ActiveRecord::Base.lease_connection.query_cache.size }, from: 1, to: 0 do
|
||||
assert_changes -> { ActiveRecord::Base.connection_pool.query_cache.size }, from: 1, to: 0 do
|
||||
Post.lease_connection.uncached(dirties: true) { Post.create!(title: "a new post", body: "and a body") }
|
||||
end
|
||||
}
|
||||
|
@ -737,7 +737,7 @@ class QueryCacheTest < ActiveRecord::TestCase
|
|||
def test_query_cache_uncached_dirties_disabled_with_nested_cache
|
||||
mw = middleware { |env|
|
||||
Post.first
|
||||
assert_changes -> { ActiveRecord::Base.lease_connection.query_cache.size }, from: 1, to: 0 do
|
||||
assert_changes -> { ActiveRecord::Base.connection_pool.query_cache.size }, from: 1, to: 0 do
|
||||
Post.uncached(dirties: false) do
|
||||
Post.cache do
|
||||
Post.create!(title: "a new post", body: "and a body")
|
||||
|
@ -746,7 +746,7 @@ class QueryCacheTest < ActiveRecord::TestCase
|
|||
end
|
||||
|
||||
Post.first
|
||||
assert_changes -> { ActiveRecord::Base.lease_connection.query_cache.size }, from: 1, to: 0 do
|
||||
assert_changes -> { ActiveRecord::Base.connection_pool.query_cache.size }, from: 1, to: 0 do
|
||||
Post.lease_connection.uncached(dirties: false) do
|
||||
Post.lease_connection.cache do
|
||||
Post.create!(title: "a new post", body: "and a body")
|
||||
|
@ -911,36 +911,36 @@ class QueryCacheExpiryTest < ActiveRecord::TestCase
|
|||
end
|
||||
|
||||
def test_find
|
||||
assert_called(Task.lease_connection.query_cache, :clear, times: 1) do
|
||||
assert_not Task.lease_connection.query_cache_enabled
|
||||
assert_called(Task.connection_pool.query_cache, :clear, times: 1) do
|
||||
assert_not Task.connection_pool.query_cache_enabled
|
||||
Task.cache do
|
||||
assert Task.lease_connection.query_cache_enabled
|
||||
assert Task.connection_pool.query_cache_enabled
|
||||
Task.find(1)
|
||||
|
||||
Task.uncached do
|
||||
assert_not Task.lease_connection.query_cache_enabled
|
||||
assert_not Task.connection_pool.query_cache_enabled
|
||||
Task.find(1)
|
||||
end
|
||||
|
||||
assert Task.lease_connection.query_cache_enabled
|
||||
assert Task.connection_pool.query_cache_enabled
|
||||
end
|
||||
assert_not Task.lease_connection.query_cache_enabled
|
||||
assert_not Task.connection_pool.query_cache_enabled
|
||||
end
|
||||
end
|
||||
|
||||
def test_enable_disable
|
||||
assert_called(Task.lease_connection.query_cache, :clear, times: 1) do
|
||||
assert_called(Task.connection_pool.query_cache, :clear, times: 1) do
|
||||
Task.cache { }
|
||||
end
|
||||
|
||||
assert_called(Task.lease_connection.query_cache, :clear, times: 1) do
|
||||
assert_called(Task.connection_pool.query_cache, :clear, times: 1) do
|
||||
Task.cache { Task.cache { } }
|
||||
end
|
||||
end
|
||||
|
||||
def test_update
|
||||
Task.cache do
|
||||
assert_called(Task.lease_connection.query_cache, :clear, times: 1) do
|
||||
assert_called(Task.connection_pool.query_cache, :clear, times: 1) do
|
||||
task = Task.find(1)
|
||||
task.starting = Time.now.utc
|
||||
task.save!
|
||||
|
@ -950,7 +950,7 @@ class QueryCacheExpiryTest < ActiveRecord::TestCase
|
|||
|
||||
def test_destroy
|
||||
Task.cache do
|
||||
assert_called(Task.lease_connection.query_cache, :clear, times: 1) do
|
||||
assert_called(Task.connection_pool.query_cache, :clear, times: 1) do
|
||||
Task.find(1).destroy
|
||||
end
|
||||
end
|
||||
|
@ -958,7 +958,7 @@ class QueryCacheExpiryTest < ActiveRecord::TestCase
|
|||
|
||||
def test_insert
|
||||
Task.cache do
|
||||
assert_called(ActiveRecord::Base.lease_connection.query_cache, :clear, times: 1) do
|
||||
assert_called(ActiveRecord::Base.connection_pool.query_cache, :clear, times: 1) do
|
||||
Task.create!
|
||||
end
|
||||
end
|
||||
|
@ -968,11 +968,11 @@ class QueryCacheExpiryTest < ActiveRecord::TestCase
|
|||
skip unless supports_insert_on_duplicate_skip?
|
||||
|
||||
Task.cache do
|
||||
assert_called(ActiveRecord::Base.lease_connection.query_cache, :clear, times: 1) do
|
||||
assert_called(ActiveRecord::Base.connection_pool.query_cache, :clear, times: 1) do
|
||||
Task.insert({ starting: Time.now })
|
||||
end
|
||||
|
||||
assert_called(ActiveRecord::Base.lease_connection.query_cache, :clear, times: 1) do
|
||||
assert_called(ActiveRecord::Base.connection_pool.query_cache, :clear, times: 1) do
|
||||
Task.insert_all([{ starting: Time.now }])
|
||||
end
|
||||
end
|
||||
|
@ -980,11 +980,11 @@ class QueryCacheExpiryTest < ActiveRecord::TestCase
|
|||
|
||||
def test_insert_all_bang
|
||||
Task.cache do
|
||||
assert_called(ActiveRecord::Base.lease_connection.query_cache, :clear, times: 1) do
|
||||
assert_called(ActiveRecord::Base.connection_pool.query_cache, :clear, times: 1) do
|
||||
Task.insert!({ starting: Time.now })
|
||||
end
|
||||
|
||||
assert_called(ActiveRecord::Base.lease_connection.query_cache, :clear, times: 1) do
|
||||
assert_called(ActiveRecord::Base.connection_pool.query_cache, :clear, times: 1) do
|
||||
Task.insert_all!([{ starting: Time.now }])
|
||||
end
|
||||
end
|
||||
|
@ -994,11 +994,11 @@ class QueryCacheExpiryTest < ActiveRecord::TestCase
|
|||
skip unless supports_insert_on_duplicate_update?
|
||||
|
||||
Task.cache do
|
||||
assert_called(ActiveRecord::Base.lease_connection.query_cache, :clear, times: 1) do
|
||||
assert_called(ActiveRecord::Base.connection_pool.query_cache, :clear, times: 1) do
|
||||
Task.upsert({ starting: Time.now })
|
||||
end
|
||||
|
||||
assert_called(ActiveRecord::Base.lease_connection.query_cache, :clear, times: 1) do
|
||||
assert_called(ActiveRecord::Base.connection_pool.query_cache, :clear, times: 1) do
|
||||
Task.upsert_all([{ starting: Time.now }])
|
||||
end
|
||||
end
|
||||
|
@ -1006,7 +1006,7 @@ class QueryCacheExpiryTest < ActiveRecord::TestCase
|
|||
|
||||
def test_cache_is_expired_by_habtm_update
|
||||
ActiveRecord::Base.cache do
|
||||
assert_called(ActiveRecord::Base.lease_connection.query_cache, :clear, times: 1) do
|
||||
assert_called(ActiveRecord::Base.connection_pool.query_cache, :clear, times: 1) do
|
||||
c = Category.first
|
||||
p = Post.first
|
||||
p.categories << c
|
||||
|
@ -1016,7 +1016,7 @@ class QueryCacheExpiryTest < ActiveRecord::TestCase
|
|||
|
||||
def test_cache_is_expired_by_habtm_delete
|
||||
ActiveRecord::Base.cache do
|
||||
assert_called(ActiveRecord::Base.lease_connection.query_cache, :clear, times: 1) do
|
||||
assert_called(ActiveRecord::Base.connection_pool.query_cache, :clear, times: 1) do
|
||||
p = Post.find(1)
|
||||
assert_predicate p.categories, :any?
|
||||
p.categories.delete_all
|
||||
|
|
|
@ -242,9 +242,13 @@ class SanitizeTest < ActiveRecord::TestCase
|
|||
private
|
||||
def bind(statement, *vars)
|
||||
if vars.first.is_a?(Hash)
|
||||
ActiveRecord::Base.send(:replace_named_bind_variables, statement, vars.first)
|
||||
ActiveRecord::Base.with_connection do |c|
|
||||
ActiveRecord::Base.send(:replace_named_bind_variables, c, statement, vars.first)
|
||||
end
|
||||
else
|
||||
ActiveRecord::Base.send(:replace_bind_variables, statement, vars)
|
||||
ActiveRecord::Base.with_connection do |c|
|
||||
ActiveRecord::Base.send(:replace_bind_variables, c, statement, vars)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue