-
Notifications
You must be signed in to change notification settings - Fork 419
Invalidate statement cache on schema changes affecting statement result. #103
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
Conversation
asyncpg/connection.py
Outdated
@@ -226,6 +226,9 @@ def transaction(self, *, isolation='read_committed', readonly=False, | |||
if not state.closed: | |||
return state | |||
|
|||
return await self._prepare_statement(query, timeout, cache) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't split the _get_statement
method please.
asyncpg/exceptions/_base.py
Outdated
|
||
|
||
class InvalidCachedStatementError(AsyncpgError): | ||
"""Cached statement is not longer valid.""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo: not -> no
181f8a1
to
51a01e9
Compare
asyncpg/prepared_stmt.py
Outdated
if e.server_source_function == 'RevalidateCachedQuery': | ||
# Handle query plan rejection due to schema or config changes. | ||
# See comment in Connection._do_execute. | ||
raise exceptions.InvalidCachedStatementError( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we move this logic to PostgresMessage.new()
?
asyncpg/protocol/protocol.pyx
Outdated
@@ -121,7 +121,7 @@ cdef class BaseProtocol(CoreProtocol): | |||
return self.settings | |||
|
|||
def is_in_transaction(self): | |||
return self.xact_status == PQTRANS_INTRANS | |||
return self.xact_status in (PQTRANS_INTRANS, PQTRANS_INERROR) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a comment here why PQTRANS_INERROR
?
51a01e9
to
33c592d
Compare
asyncpg/connection.py
Outdated
# connection belongs to (if any). | ||
# | ||
# Note that we specifically do not rely on the error | ||
# message, as it is localizable. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
outdated comment
if self._protocol.is_in_transaction(): | ||
raise | ||
else: | ||
stmt = await self._get_statement(query, timeout) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a comment explaining that we only do 1 retry.
9d14705
to
47ce1c4
Compare
tests/test_cache_invalidation.py
Outdated
finally: | ||
await self.con.execute('DROP TABLE tab1') | ||
await pool.release(con2) | ||
await pool.release(con1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don't need to release connections if you're closing the pool
PostgreSQL will raise an exception when it detects that the result type of the query has changed from when the statement was prepared. This may happen, for example, after an ALTER TABLE or SET search_path. When this happens, and there is no transaction running, we can simply re-prepare the statement and try again. If the transaction _is_ running, this error will put it into an error state, and we have no choice but to raise an exception. The original error is somewhat cryptic, so we raise a custom InvalidCachedStatementError with the original server exception as context. In either case we clear the statement cache for this connection and all other connections of the pool this connection belongs to (if any). See #72 and #76 for discussion. Fixes: #72.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we can update the docs describing what to do if you see InvalidCachedStatementError
exception? (i.e. you can disable the statement cache).
47ce1c4
to
baf5ce7
Compare
PostgreSQL will raise an exception when it detects that the result type of the
query has changed from when the statement was prepared. This may happen, for
example, after an ALTER TABLE or SET search_path.
When this happens, and there is no transaction running, we can simply
re-prepare the statement and try again.
If the transaction is running, this error will put it into an error state,
and we have no choice but to raise an exception. The original error is
somewhat cryptic, so we raise a custom InvalidCachedStatementError with the
original server exception as context.
In either case we clear the statement cache for this connection and all other
connections of the pool this connection belongs to (if any).
See #72 and #76 for discussion.
Fixes: #72.