提交 b571c4f3 编写于 作者: R Ryuta Kamizono

Fallback to unprepared statement only when bind params limit is exceeded

This is a follow up and/or an alternative of #33844.

Unlike #33844, this would attempt to construct unprepared statement only
when bind params limit (mysql2 65535, pg 65535, sqlite3 249999) is
exceeded.

I only defined 65535 as the limit, not defined 249999 for sqlite3, since
it is an edge case, I'm not excited to add less worth extra code.
上级 18303838
......@@ -71,6 +71,11 @@ def joins_per_query
256
end
deprecate :joins_per_query
private
def bind_params_length
65535
end
end
end
end
......@@ -46,11 +46,16 @@ def cacheable_query(klass, arel) # :nodoc:
def select_all(arel, name = nil, binds = [], preparable: nil)
arel = arel_from_relation(arel)
sql, binds = to_sql_and_binds(arel, binds)
if !prepared_statements || (arel.is_a?(String) && preparable.nil?)
preparable = false
elsif binds.length > bind_params_length
sql, binds = unprepared_statement { to_sql_and_binds(arel) }
preparable = false
else
preparable = visitor.preparable
end
if prepared_statements && preparable
select_prepared(sql, name, binds)
else
......
......@@ -57,14 +57,10 @@ def build(attribute, value)
end
def build_bind_attribute(column_name, value)
attr = build_query_attribute(column_name, value)
attr = Relation::QueryAttribute.new(column_name.to_s, value, table.type(column_name))
Arel::Nodes::BindParam.new(attr)
end
def build_query_attribute(column_name, value)
Relation::QueryAttribute.new(column_name.to_s, value, table.type(column_name))
end
protected
def expand_from_hash(attributes)
return ["1=0"] if attributes.empty?
......
......@@ -22,8 +22,8 @@ def call(attribute, value)
when 1 then predicate_builder.build(attribute, values.first)
else
values.map! do |v|
attr = predicate_builder.build_query_attribute(attribute.name, v)
attr.value_for_database if attr.boundable?
bind = predicate_builder.build_bind_attribute(attribute.name, v)
bind if bind.value.boundable?
end.compact!
values.empty? ? NullPredicate : attribute.in(values)
end
......
......@@ -34,6 +34,12 @@ def teardown
ActiveSupport::Notifications.unsubscribe(@subscription)
end
def test_too_many_binds
bind_params_length = @connection.send(:bind_params_length)
topics = Topic.where(id: (1 .. bind_params_length + 1).to_a)
assert_equal Topic.count, topics.count
end
def test_bind_from_join_in_subquery
subquery = Author.joins(:thinking_posts).where(name: "David")
scope = Author.from(subquery, "authors").where(id: 1)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册