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-Tag: 3.2.4~6^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=07364aa05ad18b8f1cc8045963308c0f110ef469;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 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