Permalink
Browse files

Prepared statements shouldn't share a cache with unprepared statements

When prepared statements are enabled, the statement cache caches the SQL
directly, including the bind parameters. If a similar query is run later
with prepared statements disabled, we need to use a separate cache
instead of trying to share the same one.

Fixes #24351
  • Loading branch information...
sgrif committed Mar 31, 2016
1 parent 7b82e1c commit 3af40b71f34c70a274e261cd6e6468c613de648e
Showing with 16 additions and 3 deletions.
  1. +4 −3 activerecord/lib/active_record/core.rb
  2. +12 −0 activerecord/test/cases/statement_cache_test.rb
@@ -136,7 +136,7 @@ def allocate
end
def initialize_find_by_cache # :nodoc:
@find_by_statement_cache = {}.extend(Mutex_m)
@find_by_statement_cache = { true => {}.extend(Mutex_m), false => {}.extend(Mutex_m) }
end
def inherited(child_class) # :nodoc:
@@ -280,8 +280,9 @@ def type_caster # :nodoc:
private
def cached_find_by_statement(key, &block) # :nodoc:
@find_by_statement_cache[key] || @find_by_statement_cache.synchronize {
@find_by_statement_cache[key] ||= StatementCache.create(connection, &block)
cache = @find_by_statement_cache[connection.prepared_statements]
cache[key] || cache.synchronize {
cache[key] ||= StatementCache.create(connection, &block)
}
end
@@ -94,5 +94,17 @@ def test_statement_cache_values_differ
additional_books = cache.execute([], Book, Book.connection)
assert first_books != additional_books
end
def test_unprepared_statements_dont_share_a_cache_with_prepared_statements
Book.create(name: "my book")
Book.create(name: "my other book")
book = Book.find_by(name: "my book")
other_book = Book.connection.unprepared_statement do
Book.find_by(name: "my other book")
end
refute_equal book, other_book
end
end
end

0 comments on commit 3af40b7

Please sign in to comment.