]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Fix COMMIT/ROLLBACK AND CHAIN in the presence of subtransactions.
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 22 Sep 2023 03:11:31 +0000 (23:11 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 22 Sep 2023 03:11:31 +0000 (23:11 -0400)
In older branches, COMMIT/ROLLBACK AND CHAIN failed to propagate
the current transaction's properties to the new transaction if
there was any open subtransaction (unreleased savepoint).
Instead, some previous transaction's properties would be restored.
This is because the "if (s->chain)" check in CommitTransactionCommand
examined the wrong instance of the "chain" flag and falsely
concluded that it didn't need to save transaction properties.

Our regression tests would have noticed this, except they used
identical transaction properties for multiple tests in a row,
so that the faulty behavior was not distinguishable from correct
behavior.

Commit 12d768e70 fixed the problem in v15 and later, but only rather
accidentally, because I removed the "if (s->chain)" test to avoid a
compiler warning, while not realizing that the warning was flagging a
real bug.

In v14 and before, remove the if-test and save transaction properties
unconditionally; just as in the newer branches, that's not expensive
enough to justify thinking harder.

Add the comment and extra regression test to v15 and later to
forestall any future recurrence, but there's no live bug in those
branches.

Patch by me, per bug #18118 from Liu Xiang.  Back-patch to v12 where
the AND CHAIN feature was added.

Discussion: https://postgr.es/m/18118-4b72fcbb903aace6@postgresql.org

src/backend/access/transam/xact.c
src/test/regress/expected/transactions.out
src/test/regress/sql/transactions.sql

index bf551b0395ff63bb5d809eb8ee169d0c69fc5e9a..305cad499ec938b9ad1ac50dfa27337b199d76c2 100644 (file)
@@ -2961,8 +2961,8 @@ CommitTransactionCommand(void)
 {
        TransactionState s = CurrentTransactionState;
 
-       if (s->chain)
-               SaveTransactionCharacteristics();
+       /* Must save in case we need to restore below */
+       SaveTransactionCharacteristics();
 
        switch (s->blockState)
        {
index 77af8b13fc84696c39975df10bf9e534b9a15811..c83debedd32d38c4441c6bef610dd62e4297887e 100644 (file)
@@ -814,6 +814,46 @@ SHOW transaction_deferrable;
  on
 (1 row)
 
+COMMIT;
+START TRANSACTION ISOLATION LEVEL READ COMMITTED, READ WRITE, DEFERRABLE;
+SHOW transaction_isolation;
+ transaction_isolation 
+-----------------------
+ read committed
+(1 row)
+
+SHOW transaction_read_only;
+ transaction_read_only 
+-----------------------
+ off
+(1 row)
+
+SHOW transaction_deferrable;
+ transaction_deferrable 
+------------------------
+ on
+(1 row)
+
+SAVEPOINT x;
+COMMIT AND CHAIN;  -- TBLOCK_SUBCOMMIT
+SHOW transaction_isolation;
+ transaction_isolation 
+-----------------------
+ read committed
+(1 row)
+
+SHOW transaction_read_only;
+ transaction_read_only 
+-----------------------
+ off
+(1 row)
+
+SHOW transaction_deferrable;
+ transaction_deferrable 
+------------------------
+ on
+(1 row)
+
 COMMIT;
 -- different mix of options just for fun
 START TRANSACTION ISOLATION LEVEL SERIALIZABLE, READ WRITE, NOT DEFERRABLE;
index ad0fd44e70cd0ac4fbd8dc0980e1f73b24e90f81..0b2ad4922cf6f589f9ba91a03ead5f372e8df524 100644 (file)
@@ -469,6 +469,17 @@ SHOW transaction_read_only;
 SHOW transaction_deferrable;
 COMMIT;
 
+START TRANSACTION ISOLATION LEVEL READ COMMITTED, READ WRITE, DEFERRABLE;
+SHOW transaction_isolation;
+SHOW transaction_read_only;
+SHOW transaction_deferrable;
+SAVEPOINT x;
+COMMIT AND CHAIN;  -- TBLOCK_SUBCOMMIT
+SHOW transaction_isolation;
+SHOW transaction_read_only;
+SHOW transaction_deferrable;
+COMMIT;
+
 -- different mix of options just for fun
 START TRANSACTION ISOLATION LEVEL SERIALIZABLE, READ WRITE, NOT DEFERRABLE;
 SHOW transaction_isolation;