提交 72005ad0 编写于 作者: R Ryuta Kamizono

Refactor `preparable` to be had the state in Arel collectors

上级 cea27af0
...@@ -14,31 +14,32 @@ def to_sql(arel_or_sql_string, binds = []) ...@@ -14,31 +14,32 @@ def to_sql(arel_or_sql_string, binds = [])
sql sql
end end
def to_sql_and_binds(arel_or_sql_string, binds = []) # :nodoc: def to_sql_and_binds(arel_or_sql_string, binds = [], preparable = nil) # :nodoc:
if arel_or_sql_string.respond_to?(:ast) if arel_or_sql_string.respond_to?(:ast)
unless binds.empty? unless binds.empty?
raise "Passing bind parameters with an arel AST is forbidden. " \ raise "Passing bind parameters with an arel AST is forbidden. " \
"The values must be stored on the AST directly" "The values must be stored on the AST directly"
end end
collector = collector()
if prepared_statements if prepared_statements
collector.preparable = true
sql, binds = visitor.compile(arel_or_sql_string.ast, collector) sql, binds = visitor.compile(arel_or_sql_string.ast, collector)
if binds.length > bind_params_length if binds.length > bind_params_length
unprepared_statement do unprepared_statement do
sql, binds = to_sql_and_binds(arel_or_sql_string) return to_sql_and_binds(arel_or_sql_string)
visitor.preparable = false
end end
end end
preparable = collector.preparable
else else
sql = visitor.compile(arel_or_sql_string.ast, collector) sql = visitor.compile(arel_or_sql_string.ast, collector)
end end
[sql.freeze, binds] [sql.freeze, binds, preparable]
else else
visitor.preparable = false if prepared_statements
arel_or_sql_string = arel_or_sql_string.dup.freeze unless arel_or_sql_string.frozen? arel_or_sql_string = arel_or_sql_string.dup.freeze unless arel_or_sql_string.frozen?
[arel_or_sql_string, binds] [arel_or_sql_string, binds, preparable]
end end
end end
private :to_sql_and_binds private :to_sql_and_binds
...@@ -60,11 +61,7 @@ def cacheable_query(klass, arel) # :nodoc: ...@@ -60,11 +61,7 @@ def cacheable_query(klass, arel) # :nodoc:
# Returns an ActiveRecord::Result instance. # Returns an ActiveRecord::Result instance.
def select_all(arel, name = nil, binds = [], preparable: nil) def select_all(arel, name = nil, binds = [], preparable: nil)
arel = arel_from_relation(arel) arel = arel_from_relation(arel)
sql, binds = to_sql_and_binds(arel, binds) sql, binds, preparable = to_sql_and_binds(arel, binds, preparable)
if preparable.nil?
preparable = prepared_statements ? visitor.preparable : false
end
if prepared_statements && preparable if prepared_statements && preparable
select_prepared(sql, name, binds) select_prepared(sql, name, binds)
......
...@@ -96,11 +96,7 @@ def clear_query_cache ...@@ -96,11 +96,7 @@ def clear_query_cache
def select_all(arel, name = nil, binds = [], preparable: nil) def select_all(arel, name = nil, binds = [], preparable: nil)
if @query_cache_enabled && !locked?(arel) if @query_cache_enabled && !locked?(arel)
arel = arel_from_relation(arel) arel = arel_from_relation(arel)
sql, binds = to_sql_and_binds(arel, binds) sql, binds, preparable = to_sql_and_binds(arel, binds, preparable)
if preparable.nil?
preparable = prepared_statements ? visitor.preparable : false
end
cache_sql(sql, name, binds) { super(sql, name, binds, preparable: preparable) } cache_sql(sql, name, binds) { super(sql, name, binds, preparable: preparable) }
else else
......
# frozen_string_literal: true # frozen_string_literal: true
require "set" require "set"
require "active_record/connection_adapters/determine_if_preparable_visitor"
require "active_record/connection_adapters/schema_cache" require "active_record/connection_adapters/schema_cache"
require "active_record/connection_adapters/sql_type_metadata" require "active_record/connection_adapters/sql_type_metadata"
require "active_record/connection_adapters/abstract/schema_dumper" require "active_record/connection_adapters/abstract/schema_dumper"
...@@ -95,12 +94,9 @@ def initialize(connection, logger = nil, config = {}) # :nodoc: ...@@ -95,12 +94,9 @@ def initialize(connection, logger = nil, config = {}) # :nodoc:
@statements = build_statement_pool @statements = build_statement_pool
@lock = ActiveSupport::Concurrency::LoadInterlockAwareMonitor.new @lock = ActiveSupport::Concurrency::LoadInterlockAwareMonitor.new
if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true }) @prepared_statements = self.class.type_cast_config_to_boolean(
@prepared_statements = true config.fetch(:prepared_statements, true)
@visitor.extend(DetermineIfPreparableVisitor) )
else
@prepared_statements = false
end
@advisory_locks_enabled = self.class.type_cast_config_to_boolean( @advisory_locks_enabled = self.class.type_cast_config_to_boolean(
config.fetch(:advisory_locks, true) config.fetch(:advisory_locks, true)
......
# frozen_string_literal: true
module ActiveRecord
module ConnectionAdapters
module DetermineIfPreparableVisitor
attr_accessor :preparable
def accept(object, collector)
@preparable = true
super
end
def visit_Arel_Nodes_In(o, collector)
@preparable = false
super
end
def visit_Arel_Nodes_NotIn(o, collector)
@preparable = false
super
end
def visit_Arel_Nodes_SqlLiteral(o, collector)
@preparable = false
super
end
end
end
end
...@@ -57,6 +57,8 @@ def sql_for(binds, connection) ...@@ -57,6 +57,8 @@ def sql_for(binds, connection)
end end
class PartialQueryCollector class PartialQueryCollector
attr_accessor :preparable
def initialize def initialize
@parts = [] @parts = []
@binds = [] @binds = []
......
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
module Arel # :nodoc: all module Arel # :nodoc: all
module Collectors module Collectors
class Composite class Composite
attr_accessor :preparable
def initialize(left, right) def initialize(left, right)
@left = left @left = left
@right = right @right = right
......
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
module Arel # :nodoc: all module Arel # :nodoc: all
module Collectors module Collectors
class SQLString < PlainString class SQLString < PlainString
attr_accessor :preparable
def initialize(*) def initialize(*)
super super
@bind_index = 1 @bind_index = 1
......
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
module Arel # :nodoc: all module Arel # :nodoc: all
module Collectors module Collectors
class SubstituteBinds class SubstituteBinds
attr_accessor :preparable
def initialize(quoter, delegate_collector) def initialize(quoter, delegate_collector)
@quoter = quoter @quoter = quoter
@delegate = delegate_collector @delegate = delegate_collector
......
...@@ -510,6 +510,7 @@ def visit_Arel_Table(o, collector) ...@@ -510,6 +510,7 @@ def visit_Arel_Table(o, collector)
end end
def visit_Arel_Nodes_In(o, collector) def visit_Arel_Nodes_In(o, collector)
collector.preparable = false
attr, values = o.left, o.right attr, values = o.left, o.right
if Array === values if Array === values
...@@ -525,6 +526,7 @@ def visit_Arel_Nodes_In(o, collector) ...@@ -525,6 +526,7 @@ def visit_Arel_Nodes_In(o, collector)
end end
def visit_Arel_Nodes_NotIn(o, collector) def visit_Arel_Nodes_NotIn(o, collector)
collector.preparable = false
attr, values = o.left, o.right attr, values = o.left, o.right
if Array === values if Array === values
...@@ -656,14 +658,18 @@ def visit_Arel_Attributes_Attribute(o, collector) ...@@ -656,14 +658,18 @@ def visit_Arel_Attributes_Attribute(o, collector)
collector << quote_table_name(join_name) << "." << quote_column_name(o.name) collector << quote_table_name(join_name) << "." << quote_column_name(o.name)
end end
def literal(o, collector); collector << o.to_s; end
def visit_Arel_Nodes_BindParam(o, collector) def visit_Arel_Nodes_BindParam(o, collector)
collector.add_bind(o.value) { "?" } collector.add_bind(o.value) { "?" }
end end
alias :visit_Arel_Nodes_SqlLiteral :literal def visit_Arel_Nodes_SqlLiteral(o, collector)
alias :visit_Integer :literal collector.preparable = false
collector << o.to_s
end
def visit_Integer(o, collector)
collector << o.to_s
end
def unsupported(o, collector) def unsupported(o, collector)
raise UnsupportedVisitError.new(o) raise UnsupportedVisitError.new(o)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册