1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Avoid extra BindParam allocation to generate placeholder in queries

In the Active Record usage, a `BindParam` object always has an attribute
object as the value. A `BindParam` object is used to call `add_bind` to
generate placeholder if `prepared_statements: true`.

Since Arel is a part of Active Record now, I think that we can regard an
`ActiveModel::Attribute` object as boundable without wrapping it by a
`BindParam` to avoid extra `BindParam` allocation.
This commit is contained in:
Ryuta Kamizono 2021-03-01 18:14:43 +09:00
parent a8c462d37c
commit 64ca6f608e
7 changed files with 15 additions and 20 deletions

View file

@ -368,7 +368,7 @@ module ActiveRecord
if values.empty? if values.empty?
im.insert(connection.empty_insert_statement_value(primary_key)) im.insert(connection.empty_insert_statement_value(primary_key))
else else
im.insert(_substitute_values(values)) im.insert(values.transform_keys { |name| arel_table[name] })
end end
connection.insert(im, "#{self} Create", primary_key || false, primary_key_value) connection.insert(im, "#{self} Create", primary_key || false, primary_key_value)
@ -386,7 +386,7 @@ module ActiveRecord
end end
um = Arel::UpdateManager.new(arel_table) um = Arel::UpdateManager.new(arel_table)
um.set(_substitute_values(values)) um.set(values.transform_keys { |name| arel_table[name] })
um.wheres = constraints um.wheres = constraints
connection.update(um, "#{self} Update") connection.update(um, "#{self} Update")
@ -425,12 +425,6 @@ module ActiveRecord
def discriminate_class_for_record(record) def discriminate_class_for_record(record)
self self
end end
def _substitute_values(values)
values.map do |name, value|
[ arel_table[name], Arel::Nodes::BindParam.new(value) ]
end
end
end end
# Returns true if this object hasn't been saved yet -- that is, a record # Returns true if this object hasn't been saved yet -- that is, a record

View file

@ -65,8 +65,7 @@ module ActiveRecord
end end
def build_bind_attribute(column_name, value) def build_bind_attribute(column_name, value)
attr = Relation::QueryAttribute.new(column_name, value, table.type(column_name)) Relation::QueryAttribute.new(column_name, value, table.type(column_name))
Arel::Nodes::BindParam.new(attr)
end end
def resolve_arel_attribute(table_name, column_name, &block) def resolve_arel_attribute(table_name, column_name, &block)

View file

@ -1263,8 +1263,7 @@ module ActiveRecord
end end
def build_cast_value(name, value) def build_cast_value(name, value)
cast_value = ActiveModel::Attribute.with_cast_value(name, value, Type.default_value) ActiveModel::Attribute.with_cast_value(name, value, Type.default_value)
Arel::Nodes::BindParam.new(cast_value)
end end
def build_from def build_from

View file

@ -224,11 +224,10 @@ module ActiveRecord
end end
def extract_node_value(node) def extract_node_value(node)
case node if node.respond_to?(:value_before_type_cast)
when Array
node.map { |v| extract_node_value(v) }
when Arel::Nodes::BindParam, Arel::Nodes::Casted, Arel::Nodes::Quoted
node.value_before_type_cast node.value_before_type_cast
elsif Array === node
node.map { |v| extract_node_value(v) }
end end
end end
end end

View file

@ -47,7 +47,7 @@ module Arel # :nodoc: all
def self.build_quoted(other, attribute = nil) def self.build_quoted(other, attribute = nil)
case other case other
when Arel::Nodes::Node, Arel::Attributes::Attribute, Arel::Table, Arel::SelectManager, Arel::Nodes::SqlLiteral when Arel::Nodes::Node, Arel::Attributes::Attribute, Arel::Table, Arel::SelectManager, Arel::Nodes::SqlLiteral, ActiveModel::Attribute
other other
else else
case attribute case attribute

View file

@ -52,7 +52,7 @@ module Arel # :nodoc: all
else else
left = quoted_node(other.begin) left = quoted_node(other.begin)
right = quoted_node(other.end) right = quoted_node(other.end)
Nodes::Between.new(self, left.and(right)) Nodes::Between.new(self, Nodes::And.new([left, right]))
end end
end end

View file

@ -103,7 +103,7 @@ module Arel # :nodoc: all
row.each_with_index do |value, k| row.each_with_index do |value, k|
collector << ", " unless k == 0 collector << ", " unless k == 0
case value case value
when Nodes::SqlLiteral, Nodes::BindParam when Nodes::SqlLiteral, Nodes::BindParam, ActiveModel::Attribute
collector = visit(value, collector) collector = visit(value, collector)
else else
collector << quote(value).to_s collector << quote(value).to_s
@ -585,7 +585,7 @@ module Arel # :nodoc: all
def visit_Arel_Nodes_Assignment(o, collector) def visit_Arel_Nodes_Assignment(o, collector)
case o.right case o.right
when Arel::Nodes::Node, Arel::Attributes::Attribute when Arel::Nodes::Node, Arel::Attributes::Attribute, ActiveModel::Attribute
collector = visit o.left, collector collector = visit o.left, collector
collector << " = " collector << " = "
visit o.right, collector visit o.right, collector
@ -695,6 +695,10 @@ module Arel # :nodoc: all
def bind_block; BIND_BLOCK; end def bind_block; BIND_BLOCK; end
def visit_ActiveModel_Attribute(o, collector)
collector.add_bind(o, &bind_block)
end
def visit_Arel_Nodes_BindParam(o, collector) def visit_Arel_Nodes_BindParam(o, collector)
collector.add_bind(o.value, &bind_block) collector.add_bind(o.value, &bind_block)
end end