commit f5cd3751d0d747ab5d7c0689ac8c0818c07b8580 Author: Simon Riggs Date: Wed Oct 26 15:47:22 2022 +0100 Rollback on commit diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index bea1d4fc1a..bce7b847d1 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -8846,6 +8846,24 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv; + + default_rollback_on_commit (boolean) + + rollback on commit + + + rollback_on_commit configuration parameter + + + + + This parameter controls whether a COMMIT + will rollback each transaction (on), or + commit each transaction. The default is off. + + + + default_transaction_deferrable (boolean) diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index 7c049b49f5..9790dec0df 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -83,6 +83,9 @@ bool XactReadOnly; bool DefaultXactDeferrable = false; bool XactDeferrable; +bool DefaultXactRollbackOnCommit = false; +bool XactRollbackOnCommit; + int DefaultXactNesting; int XactNesting = XACT_NEST_OFF; int XactNestingLevel = 0; @@ -2057,6 +2060,7 @@ StartTransaction(void) XactIsoLevel = DefaultXactIsoLevel; XactNesting = DefaultXactNesting; XactNestingLevel = 0; + XactRollbackOnCommit = DefaultXactRollbackOnCommit; forceSyncCommit = false; MyXactFlags = 0; @@ -3013,6 +3017,7 @@ SaveTransactionCharacteristics(SavedTransactionCharacteristics *s) s->save_XactReadOnly = XactReadOnly; s->save_XactDeferrable = XactDeferrable; s->save_XactNesting = XactNesting; + s->save_XactRollbackOnCommit = XactRollbackOnCommit; } void @@ -3022,6 +3027,7 @@ RestoreTransactionCharacteristics(const SavedTransactionCharacteristics *s) XactReadOnly = s->save_XactReadOnly; XactDeferrable = s->save_XactDeferrable; XactNesting = s->save_XactNesting; + XactRollbackOnCommit = s->save_XactRollbackOnCommit; } @@ -3915,18 +3921,26 @@ EndTransactionBlock(bool chain) case TBLOCK_INPROGRESS: if (XactNesting == XACT_NEST_OUTER) { - if (XactNestingLevel <= 0) - s->blockState = TBLOCK_END; - else + if (XactNestingLevel > 0) + { ereport(NOTICE, (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION), errmsg("nested COMMIT, level %u", XactNestingLevel))); + XactNestingLevel--; + return true; + } XactNestingLevel--; - return true; + } + if (XactRollbackOnCommit) + { + s->blockState = TBLOCK_ABORT_PENDING; + result = false; } else + { s->blockState = TBLOCK_END; - result = true; + result = true; + } break; /* diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c index 1ddf1d9792..86d7f5e134 100644 --- a/src/backend/utils/misc/guc_tables.c +++ b/src/backend/utils/misc/guc_tables.c @@ -1527,6 +1527,15 @@ struct config_bool ConfigureNamesBool[] = false, check_transaction_deferrable, NULL, NULL }, + { + {"rollback_on_commit", PGC_USERSET, CLIENT_CONN_STATEMENT, + gettext_noop("Whether to rollback the current transaction when a COMMIT statement is issued."), + NULL + }, + &DefaultXactRollbackOnCommit, + false, + NULL, NULL, NULL + }, { {"row_security", PGC_USERSET, CLIENT_CONN_STATEMENT, gettext_noop("Enable row security."), diff --git a/src/include/access/xact.h b/src/include/access/xact.h index 1cdc697fe1..acecc6a161 100644 --- a/src/include/access/xact.h +++ b/src/include/access/xact.h @@ -50,6 +50,8 @@ extern PGDLLIMPORT int XactIsoLevel; extern PGDLLIMPORT int DefaultXactNesting; +extern PGDLLIMPORT bool DefaultXactRollbackOnCommit; + /* * We implement three isolation levels internally. * The two stronger ones use one snapshot per database transaction; @@ -157,6 +159,7 @@ typedef struct SavedTransactionCharacteristics bool save_XactReadOnly; bool save_XactDeferrable; int save_XactNesting; + bool save_XactRollbackOnCommit; } SavedTransactionCharacteristics; diff --git a/src/test/regress/expected/transactions.out b/src/test/regress/expected/transactions.out index cf153a3393..a30c869fc8 100644 --- a/src/test/regress/expected/transactions.out +++ b/src/test/regress/expected/transactions.out @@ -1370,6 +1370,17 @@ SELECT * FROM abc ORDER BY 1; (0 rows) RESET nested_transactions; +SET rollback_on_commit = true; +TRUNCATE abc; +BEGIN; +INSERT INTO abc VALUES (1); +COMMIT; +SELECT * FROM abc ORDER BY 1; + a +--- +(0 rows) + +RESET rollback_on_commit; DROP TABLE abc; -- Test for successful cleanup of an aborted transaction at session exit. -- THIS MUST BE THE LAST TEST IN THIS FILE. diff --git a/src/test/regress/sql/transactions.sql b/src/test/regress/sql/transactions.sql index 4df2d4d382..e6f71d1fad 100644 --- a/src/test/regress/sql/transactions.sql +++ b/src/test/regress/sql/transactions.sql @@ -740,6 +740,16 @@ SELECT * FROM abc ORDER BY 1; RESET nested_transactions; +SET rollback_on_commit = true; + +TRUNCATE abc; +BEGIN; +INSERT INTO abc VALUES (1); +COMMIT; +SELECT * FROM abc ORDER BY 1; + +RESET rollback_on_commit; + DROP TABLE abc; -- Test for successful cleanup of an aborted transaction at session exit.