Skip to content

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

Merged
merged 1 commit into from
Mar 30, 2017

Conversation

elprans
Copy link
Member

@elprans elprans commented Mar 30, 2017

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.

@elprans elprans requested a review from 1st1 March 30, 2017 17:56
@elprans elprans self-assigned this Mar 30, 2017
@@ -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)
Copy link
Member

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.



class InvalidCachedStatementError(AsyncpgError):
"""Cached statement is not longer valid."""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: not -> no

@elprans elprans force-pushed the invalidate-cache-on-schema-change branch 2 times, most recently from 181f8a1 to 51a01e9 Compare March 30, 2017 18:02
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(
Copy link
Member

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()?

@@ -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)
Copy link
Member

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?

@elprans elprans force-pushed the invalidate-cache-on-schema-change branch from 51a01e9 to 33c592d Compare March 30, 2017 19:04
# connection belongs to (if any).
#
# Note that we specifically do not rely on the error
# message, as it is localizable.
Copy link
Member

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)
Copy link
Member

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.

@elprans elprans force-pushed the invalidate-cache-on-schema-change branch 2 times, most recently from 9d14705 to 47ce1c4 Compare March 30, 2017 19:16
finally:
await self.con.execute('DROP TABLE tab1')
await pool.release(con2)
await pool.release(con1)
Copy link
Member

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.
Copy link
Member

@1st1 1st1 left a 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).

@elprans elprans force-pushed the invalidate-cache-on-schema-change branch from 47ce1c4 to baf5ce7 Compare March 30, 2017 19:36
@elprans elprans merged commit 749d857 into master Mar 30, 2017
@elprans elprans deleted the invalidate-cache-on-schema-change branch March 30, 2017 19:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants