aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2023-09-21 23:11:31 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2023-09-21 23:11:31 -0400
commit7cabb20a95aeea441c82552246732ea507f71469 (patch)
tree93567c95c01c93b38ecef0a65f4ac04c30fd64fb
parentc50ad79f609c8a66eef3e58afd97b6987df59f96 (diff)
downloadpostgresql-7cabb20a95aeea441c82552246732ea507f71469.tar.gz
postgresql-7cabb20a95aeea441c82552246732ea507f71469.zip
Fix COMMIT/ROLLBACK AND CHAIN in the presence of subtransactions.
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
-rw-r--r--src/backend/access/transam/xact.c4
-rw-r--r--src/test/regress/expected/transactions.out40
-rw-r--r--src/test/regress/sql/transactions.sql11
3 files changed, 53 insertions, 2 deletions
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index b304a85d080..08b118da366 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -2913,8 +2913,8 @@ CommitTransactionCommand(void)
{
TransactionState s = CurrentTransactionState;
- if (s->chain)
- SaveTransactionCharacteristics();
+ /* Must save in case we need to restore below */
+ SaveTransactionCharacteristics();
switch (s->blockState)
{
diff --git a/src/test/regress/expected/transactions.out b/src/test/regress/expected/transactions.out
index e2ee8807142..2a5d743c4bd 100644
--- a/src/test/regress/expected/transactions.out
+++ b/src/test/regress/expected/transactions.out
@@ -815,6 +815,46 @@ SHOW transaction_deferrable;
(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;
SHOW transaction_isolation;
diff --git a/src/test/regress/sql/transactions.sql b/src/test/regress/sql/transactions.sql
index acb7cc1c8dd..50ea1ded9b8 100644
--- a/src/test/regress/sql/transactions.sql
+++ b/src/test/regress/sql/transactions.sql
@@ -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;