commit f5cd3751d0d747ab5d7c0689ac8c0818c07b8580
Author: Simon Riggs <simon.riggs@enterprisedb.com>
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;
       </listitem>
      </varlistentry>
 
+     <varlistentry id="guc-rollback-on-commit" xreflabel="default_rollback_on_commit">
+      <term><varname>default_rollback_on_commit</varname> (<type>boolean</type>)
+      <indexterm>
+       <primary>rollback on commit</primary>
+      </indexterm>
+      <indexterm>
+       <primary><varname>rollback_on_commit</varname> configuration parameter</primary>
+      </indexterm>
+      </term>
+      <listitem>
+        <para>
+        This parameter controls whether a <command>COMMIT</command>
+        will rollback each transaction (<literal>on</literal>), or
+        commit each transaction. The default is <literal>off</literal>.
+       </para>
+      </listitem>
+     </varlistentry>
+
      <varlistentry id="guc-default-transaction-deferrable" xreflabel="default_transaction_deferrable">
       <term><varname>default_transaction_deferrable</varname> (<type>boolean</type>)
       <indexterm>
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.
