]> git.ipfire.org Git - thirdparty/psycopg.git/commitdiff
fix: don't clobber an error from the server with a server disconnection
authorDaniele Varrazzo <daniele.varrazzo@gmail.com>
Wed, 8 Jan 2025 00:21:22 +0000 (01:21 +0100)
committerDaniele Varrazzo <daniele.varrazzo@gmail.com>
Wed, 8 Jan 2025 12:41:56 +0000 (13:41 +0100)
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
psycopg/psycopg/generators.py

index d222448c5969dbe9df580373063f9ce2683a5197..463d774291f5ff9a388e40307562dd415d408ce1 100644 (file)
@@ -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
index 8eee7ccca370cadda7370c552c658fc7861ef560..1eeb46712522d81d09e77c0bac56113ae57ef493 100644 (file)
@@ -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