From: Daniele Varrazzo Date: Wed, 8 Jan 2025 00:21:22 +0000 (+0100) Subject: fix: don't clobber an error from the server with a server disconnection X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e5121d95b81f14efb011460c70973966f112c5d5;p=thirdparty%2Fpsycopg.git fix: don't clobber an error from the server with a server disconnection The server error is assumed to contain more information, as it is returned as a result, whereas a communication error caused by a server disconnection will only make available the error message. Close #988 (but we need to fix the Cython side too). --- diff --git a/docs/news.rst b/docs/news.rst index d222448c5..463d77429 100644 --- a/docs/news.rst +++ b/docs/news.rst @@ -23,6 +23,9 @@ Psycopg 3.2.4 (unreleased) is not running (:ticket:`#962`). - Make sure that the notifies callback is called during the use of the `~Connection.notifies()` generator (:ticket:`#972`). +- Raise `~errors.IdleInTransactionSessionTimeout` instead of a generic + `OperationalError` upon hitting an idle-in-transaction timeout + (:ticket:`#988`). Current release diff --git a/psycopg/psycopg/generators.py b/psycopg/psycopg/generators.py index 8eee7ccca..1eeb46712 100644 --- a/psycopg/psycopg/generators.py +++ b/psycopg/psycopg/generators.py @@ -46,6 +46,7 @@ COMMAND_OK = pq.ExecStatus.COMMAND_OK COPY_OUT = pq.ExecStatus.COPY_OUT COPY_IN = pq.ExecStatus.COPY_IN COPY_BOTH = pq.ExecStatus.COPY_BOTH +FATAL_ERROR = pq.ExecStatus.FATAL_ERROR PIPELINE_SYNC = pq.ExecStatus.PIPELINE_SYNC WAIT_R = Wait.R @@ -176,7 +177,19 @@ def _fetch_many(pgconn: PGconn) -> PQGen[list[PGresult]]: """ results: list[PGresult] = [] while True: - res = yield from _fetch(pgconn) + try: + res = yield from _fetch(pgconn) + except e.DatabaseError: + # What might have happened here is that a previuos error + # disconnected the connection, for example a idle in transaction + # timeout. Check if we had received an error before, and raise it + # as exception, because it should contain more details. See #988. + for res in results: + if res.status == FATAL_ERROR: + raise e.error_from_result(res, encoding=pgconn._encoding) from None + else: + raise + if not res: break