commit 18516b98dc050110df739b6f7aa9d5ef99b5fda5
Author: Simon Riggs <simon.riggs@enterprisedb.com>
Date:   Tue Nov 22 15:35:47 2022 +0000

    rollback_on_commit.v2.patch

diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 6ad22a26f8..4dbfd63d01 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -8850,6 +8850,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 c5852bc7ef..9562681ff7 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;
 }
 
 
@@ -4137,6 +4143,12 @@ EndTransactionBlock(bool chain)
 
 	s->chain = chain;
 
+	if (s->blockState == TBLOCK_END && XactRollbackOnCommit)
+	{
+		s->blockState = TBLOCK_ABORT_PENDING;
+		result = false;
+	}
+
 	return result;
 }
 
diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c
index 865013f759..975e149ff8 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -1553,6 +1553,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 fffedf49f4..6c92125d07 100644
--- a/src/test/regress/expected/transactions.out
+++ b/src/test/regress/expected/transactions.out
@@ -1428,6 +1428,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 35ce4ec6ae..325488f6da 100644
--- a/src/test/regress/sql/transactions.sql
+++ b/src/test/regress/sql/transactions.sql
@@ -773,6 +773,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.
