From 07364aa05ad18b8f1cc8045963308c0f110ef469 Mon Sep 17 00:00:00 2001 From: Daniele Varrazzo Date: Wed, 8 Jan 2025 01:21:22 +0100 Subject: [PATCH] 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). --- docs/news.rst | 3 +++ psycopg/psycopg/generators.py | 15 ++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/docs/news.rst b/docs/news.rst index 2e011ad4b..94975446d 100644 --- a/docs/news.rst +++ b/docs/news.rst @@ -17,6 +17,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 5d6554f36..67a31878d 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 -- 2.47.2