New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Avoid race condition with unprepared_statement #36871
Conversation
Done |
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
I think it is better to change the |
@rafaelfranca Sure |
@rafaelfranca Actually, making this (simply) thread-local is a breaking change. Concretely, I think |
Sorry -- I should clarify: that test breaks when it's run as part of the suite. It passes when run individually, precisely because in the latter case, the |
Right, we could have a db config option, but the value inside the instance of the connection should only be set to the current thread, not to all threads. Something like this should work:
|
That's in fact what I did (or something equivalent): def prepared_statements # :nodoc:
Thread.current.fetch(:prepared_statements, @default_prepared_statements)
end
def prepared_statements=(prepared_statements) # :nodoc:
Thread.current[:prepared_statements] = prepared_statements
end That's breaking behavior. |
The problem is that once the thread-local is set, the setting now applies to all connections in the current thread, not just the connection it was called on. [Edit] That means, for example, that it would apply across different connection pools that connect to different databases, regardless of what was in their connection configuration. Possibly, this value could be in a thread-keyed map in the pool, instead of the individual connection. And the connection could delegate to the pool. That's assuming that there's never a case where two different connections from the same pool are used in the same thread with different prepared statement statuses. |
Closing in favor of #36949 |
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 #36763