]> git.ipfire.org Git - thirdparty/psycopg.git/commitdiff
fix: fix nested transaction entering in pipeline mode
authorDaniele Varrazzo <daniele.varrazzo@gmail.com>
Mon, 9 May 2022 13:23:51 +0000 (15:23 +0200)
committerDaniele Varrazzo <daniele.varrazzo@gmail.com>
Mon, 9 May 2022 13:23:51 +0000 (15:23 +0200)
If the connection is idle, it might be that we are missing results.
Receive them to align the connection state to what the transaction
object expects, otherwise the assert in _push_savepoint() will fail.

psycopg/psycopg/transaction.py
tests/test_pipeline.py
tests/test_pipeline_async.py

index 35ef973d861093cdd540e0e1a90de2fe8924f1db..3477f8cfeb251667f9dfdaaf90f60a26cf564623 100644 (file)
@@ -90,6 +90,16 @@ class BaseTransaction(Generic[ConnectionType]):
             raise TypeError("transaction blocks can be used only once")
         self._entered = True
 
+        # If we are in pipeline mode and connection idle, we might be in a
+        # nested statement but we haven't received yet the result to go
+        # INTRANS. This would make _push_savepoint() fail. If so, synchronize
+        # with the server.
+        if (
+            self._conn._pipeline
+            and self.pgconn.transaction_status == TransactionStatus.IDLE
+        ):
+            yield from self._conn._pipeline._sync_gen()
+
         self._push_savepoint()
         for command in self._get_enter_commands():
             yield from self._conn._exec_command(command)
index ba3d3d6ef202b8b269dbc9d837401462dc9c213f..b20359f8c5c6dc385721f073a7d57d76417eb68d 100644 (file)
@@ -398,6 +398,16 @@ def test_transaction_nested(conn):
         assert r == "inner"
 
 
+def test_transaction_nested_no_statement(conn):
+    with conn.pipeline():
+        with conn.transaction():
+            with conn.transaction():
+                cur = conn.execute("select 1")
+
+        (r,) = cur.fetchone()
+        assert r == 1
+
+
 def test_outer_transaction(conn):
     with conn.transaction():
         with conn.pipeline():
index 6f774a5bdbf82e4c768dcac8d83a3a9bfe81883e..5d7e669dd3a3e11ba45173ba825d5f1a97fc2bbc 100644 (file)
@@ -400,6 +400,16 @@ async def test_transaction_nested(aconn):
         assert r == "inner"
 
 
+async def test_transaction_nested_no_statement(aconn):
+    async with aconn.pipeline():
+        async with aconn.transaction():
+            async with aconn.transaction():
+                cur = await aconn.execute("select 1")
+
+        (r,) = await cur.fetchone()
+        assert r == 1
+
+
 async def test_outer_transaction(aconn):
     async with aconn.transaction():
         async with aconn.pipeline():