mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Check if the SQL is not a prepared statement
When the adapter is with prepared statement disabled and the binds array is not empty the connection adapter will try to set the binds values and will fail. Now we are checking if the adapter has the prepared statement disabled. Fixes #12023
This commit is contained in:
parent
3d60e9d550
commit
f13b278568
10 changed files with 29 additions and 7 deletions
|
@ -1,3 +1,9 @@
|
||||||
|
* Fix inserts with prepared statements disabled.
|
||||||
|
|
||||||
|
Fixes #12023.
|
||||||
|
|
||||||
|
*Rafael Mendonça França*
|
||||||
|
|
||||||
* Setting a has_one association on a new record no longer causes an empty
|
* Setting a has_one association on a new record no longer causes an empty
|
||||||
transaction.
|
transaction.
|
||||||
|
|
||||||
|
|
|
@ -377,7 +377,7 @@ module ActiveRecord
|
||||||
def sql_for_insert(sql, pk, id_value, sequence_name, binds)
|
def sql_for_insert(sql, pk, id_value, sequence_name, binds)
|
||||||
[sql, binds]
|
[sql, binds]
|
||||||
end
|
end
|
||||||
|
|
||||||
def last_inserted_id(result)
|
def last_inserted_id(result)
|
||||||
row = result.rows.first
|
row = result.rows.first
|
||||||
row && row.first
|
row && row.first
|
||||||
|
|
|
@ -97,6 +97,7 @@ module ActiveRecord
|
||||||
@pool = pool
|
@pool = pool
|
||||||
@schema_cache = SchemaCache.new self
|
@schema_cache = SchemaCache.new self
|
||||||
@visitor = nil
|
@visitor = nil
|
||||||
|
@prepared_statements = false
|
||||||
end
|
end
|
||||||
|
|
||||||
def valid_type?(type)
|
def valid_type?(type)
|
||||||
|
@ -440,6 +441,10 @@ module ActiveRecord
|
||||||
# override in derived class
|
# override in derived class
|
||||||
ActiveRecord::StatementInvalid.new(message, exception)
|
ActiveRecord::StatementInvalid.new(message, exception)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def without_prepared_statement?(binds)
|
||||||
|
@prepared_statements || binds.empty?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -174,6 +174,7 @@ module ActiveRecord
|
||||||
@quoted_column_names, @quoted_table_names = {}, {}
|
@quoted_column_names, @quoted_table_names = {}, {}
|
||||||
|
|
||||||
if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true })
|
if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true })
|
||||||
|
@prepared_statements = true
|
||||||
@visitor = Arel::Visitors::MySQL.new self
|
@visitor = Arel::Visitors::MySQL.new self
|
||||||
else
|
else
|
||||||
@visitor = unprepared_visitor
|
@visitor = unprepared_visitor
|
||||||
|
|
|
@ -229,7 +229,7 @@ module ActiveRecord
|
||||||
|
|
||||||
alias exec_without_stmt exec_query
|
alias exec_without_stmt exec_query
|
||||||
|
|
||||||
# Returns an ActiveRecord::Result instance.
|
# Returns an ActiveRecord::Result instance.
|
||||||
def select(sql, name = nil, binds = [])
|
def select(sql, name = nil, binds = [])
|
||||||
exec_query(sql, name)
|
exec_query(sql, name)
|
||||||
end
|
end
|
||||||
|
|
|
@ -283,7 +283,7 @@ module ActiveRecord
|
||||||
# always be empty, since the bind variables will have been already
|
# always be empty, since the bind variables will have been already
|
||||||
# substituted and removed from binds by BindVisitor, so this will
|
# substituted and removed from binds by BindVisitor, so this will
|
||||||
# effectively disable prepared statement usage completely.
|
# effectively disable prepared statement usage completely.
|
||||||
if binds.empty?
|
if without_prepared_statement?(binds)
|
||||||
result_set, affected_rows = exec_without_stmt(sql, name)
|
result_set, affected_rows = exec_without_stmt(sql, name)
|
||||||
else
|
else
|
||||||
result_set, affected_rows = exec_stmt(sql, name, binds)
|
result_set, affected_rows = exec_stmt(sql, name, binds)
|
||||||
|
|
|
@ -135,8 +135,8 @@ module ActiveRecord
|
||||||
|
|
||||||
def exec_query(sql, name = 'SQL', binds = [])
|
def exec_query(sql, name = 'SQL', binds = [])
|
||||||
log(sql, name, binds) do
|
log(sql, name, binds) do
|
||||||
result = binds.empty? ? exec_no_cache(sql, binds) :
|
result = without_prepared_statement?(binds) ? exec_no_cache(sql, binds) :
|
||||||
exec_cache(sql, binds)
|
exec_cache(sql, binds)
|
||||||
|
|
||||||
types = {}
|
types = {}
|
||||||
fields = result.fields
|
fields = result.fields
|
||||||
|
|
|
@ -531,6 +531,7 @@ module ActiveRecord
|
||||||
super(connection, logger)
|
super(connection, logger)
|
||||||
|
|
||||||
if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true })
|
if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true })
|
||||||
|
@prepared_statements = true
|
||||||
@visitor = Arel::Visitors::PostgreSQL.new self
|
@visitor = Arel::Visitors::PostgreSQL.new self
|
||||||
else
|
else
|
||||||
@visitor = unprepared_visitor
|
@visitor = unprepared_visitor
|
||||||
|
|
|
@ -113,6 +113,7 @@ module ActiveRecord
|
||||||
@config = config
|
@config = config
|
||||||
|
|
||||||
if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true })
|
if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true })
|
||||||
|
@prepared_statements = true
|
||||||
@visitor = Arel::Visitors::SQLite.new self
|
@visitor = Arel::Visitors::SQLite.new self
|
||||||
else
|
else
|
||||||
@visitor = unprepared_visitor
|
@visitor = unprepared_visitor
|
||||||
|
@ -293,8 +294,8 @@ module ActiveRecord
|
||||||
def exec_query(sql, name = nil, binds = [])
|
def exec_query(sql, name = nil, binds = [])
|
||||||
log(sql, name, binds) do
|
log(sql, name, binds) do
|
||||||
|
|
||||||
# Don't cache statements without bind values
|
# Don't cache statements if they are not prepared
|
||||||
if binds.empty?
|
if without_prepared_statement?(binds)
|
||||||
stmt = @connection.prepare(sql)
|
stmt = @connection.prepare(sql)
|
||||||
cols = stmt.columns
|
cols = stmt.columns
|
||||||
records = stmt.to_a
|
records = stmt.to_a
|
||||||
|
|
|
@ -565,6 +565,14 @@ class BasicsTest < ActiveRecord::TestCase
|
||||||
assert_equal [topic_2, topic_1].sort, [topic_1, topic_2]
|
assert_equal [topic_2, topic_1].sort, [topic_1, topic_2]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_create_without_prepared_statement
|
||||||
|
topic = Topic.connection.unprepared_statement do
|
||||||
|
Topic.create(:title => 'foo')
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal topic, Topic.find(topic.id)
|
||||||
|
end
|
||||||
|
|
||||||
def test_comparison_with_different_objects
|
def test_comparison_with_different_objects
|
||||||
topic = Topic.create
|
topic = Topic.create
|
||||||
category = Category.create(:name => "comparison")
|
category = Category.create(:name => "comparison")
|
||||||
|
|
Loading…
Reference in a new issue