Skip to content

Commit

Permalink
Guard unprepared_statement blocks with the connection lock
Browse files Browse the repository at this point in the history
In system tests, a single database connection is shared among all
the server threads. A call to unprepared_statement temporarily
modifies an instance variable on the connection object, which is
then visible to other concurrently running threads. This leads to
a situation where prepared statements may end up with the wrong
binds.

Addresses rails#36763
  • Loading branch information
97jaz committed Aug 6, 2019
1 parent 170f511 commit 432d9a1
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -258,10 +258,12 @@ def seconds_idle # :nodoc:
end

def unprepared_statement
old_prepared_statements, @prepared_statements = @prepared_statements, false
yield
ensure
@prepared_statements = old_prepared_statements
@lock.synchronize do
old_prepared_statements, @prepared_statements = @prepared_statements, false
yield
ensure
@prepared_statements = old_prepared_statements
end
end

# Returns the human-readable name of the adapter. Use mixed case - one
Expand Down
9 changes: 9 additions & 0 deletions activerecord/test/cases/statement_cache_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,15 @@ def test_unprepared_statements_dont_share_a_cache_with_prepared_statements
assert_not_equal book, other_book
end

def test_unprepared_statements_lock_connection
connection = Book.connection
lock = connection.lock

connection.unprepared_statement do
assert(lock.mon_locked? && lock.mon_owned?)
end
end

def test_find_by_does_not_use_statement_cache_if_table_name_is_changed
book = Book.create(name: "my book")

Expand Down

0 comments on commit 432d9a1

Please sign in to comment.