From d015dcbe4eeaebe6084983945ef68a642c38e0e1 Mon Sep 17 00:00:00 2001
From: Bruce Momjian <bruce@momjian.us>
Date: Wed, 9 Oct 2002 04:59:38 +0000
Subject: [PATCH] Have SET not start transaction when autocommit off, with doc
 updates.

---
 doc/src/sgml/ref/reset.sgml |  8 +++++++-
 doc/src/sgml/ref/set.sgml   |  8 +++++++-
 doc/src/sgml/runtime.sgml   | 38 ++++++++++++++++++++++++++-----------
 src/backend/tcop/postgres.c | 31 +++++++++++++++++++++---------
 4 files changed, 63 insertions(+), 22 deletions(-)

diff --git a/doc/src/sgml/ref/reset.sgml b/doc/src/sgml/ref/reset.sgml
index 1af55703cd3..a21aa0239fb 100644
--- a/doc/src/sgml/ref/reset.sgml
+++ b/doc/src/sgml/ref/reset.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/reset.sgml,v 1.15 2002/09/21 18:32:54 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/reset.sgml,v 1.16 2002/10/09 04:59:38 momjian Exp $
 PostgreSQL documentation
 -->
 
@@ -66,6 +66,12 @@ SET <replaceable class="parameter">variable</replaceable> TO DEFAULT
    switches, or per-database or per-user default settings.  See the
    <citetitle>Administrator's Guide</citetitle> for details.
   </para>
+
+  <para>
+   See the <command>SHOW</> manual page for details on the transaction
+   behavior of <command>RESET</>.
+  </para>
+
  </refsect1>
 
  <refsect1>
diff --git a/doc/src/sgml/ref/set.sgml b/doc/src/sgml/ref/set.sgml
index bc3688a5652..1c9bd31e1e9 100644
--- a/doc/src/sgml/ref/set.sgml
+++ b/doc/src/sgml/ref/set.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/set.sgml,v 1.65 2002/09/21 18:32:54 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/set.sgml,v 1.66 2002/10/09 04:59:38 momjian Exp $
 PostgreSQL documentation
 -->
 
@@ -108,6 +108,12 @@ SET [ SESSION | LOCAL ] TIME ZONE { <replaceable class="PARAMETER">timezone</rep
    is committed) the <command>SET</command> value will take effect.
   </para>
 
+  <para>
+   With <literal>autocommit</> set to <literal>off</>, <command>SET</>
+   does not start a new transaction block. See the
+   <literal>autocommit</> section of the documentation for details.
+  </para>
+
   <para>
    Here are additional details about a few of the parameters that can be set:
 
diff --git a/doc/src/sgml/runtime.sgml b/doc/src/sgml/runtime.sgml
index a7215c89ce0..2936e9b4c70 100644
--- a/doc/src/sgml/runtime.sgml
+++ b/doc/src/sgml/runtime.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/runtime.sgml,v 1.143 2002/10/03 02:26:49 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/runtime.sgml,v 1.144 2002/10/09 04:59:38 momjian Exp $
 -->
 
 <Chapter Id="runtime">
@@ -1235,16 +1235,32 @@ env PGOPTIONS='-c geqo=off' psql
 	that is not inside an explicit transaction block (that is, unless a
 	<command>BEGIN</> with no matching <command>COMMIT</> has been
 	given).
-	If set to false, <productname>PostgreSQL</productname> will commit
-	the effects of commands only on receiving an explicit
-	<command>COMMIT</> command.  This mode can also be thought of as
-	implicitly issuing <command>BEGIN</> whenever a command is received
-	and <productname>PostgreSQL</productname> is not already inside
-	a transaction block.
-	The default is true, for compatibility with historical
-	<productname>PostgreSQL</productname> behavior.  But for maximum
-	compatibility with the SQL specification, set it to false.
-       </para>
+	If set to false, <productname>PostgreSQL</productname> will
+	commit the commands only when receiving an explicit
+	<command>COMMIT</> command. This mode can also be thought of as
+	implicitly issuing <command>BEGIN</> whenever a command is
+	received that is not already inside a transaction block. The
+	default is true, for compatibility with historical
+	<productname>PostgreSQL</productname> behavior. However, for
+	maximum compatibility with the SQL specification, set it to
+	false.
+       </para>
+       <note>
+        <para>
+	 With <varname>autocommit</> set to false, <command>SET</>,
+	 <command>SHOW</>, and <command>RESET</> do not start new
+	 transaction blocks. They are run in their own transactions.
+	 Once another command is issued, multi-statement transaction
+	 behavior begins and any <command>SET</>, <command>SHOW</>, or
+	 <command>RESET</> commands are considered to be part of the
+	 transaction, i.e. they are committed or rolled back depending
+	 on the completion status of the transaction. To have
+	 <command>SET</>, <command>SHOW</>, and <command>RESET</>
+	 commands at the start of a transaction, use <command>BEGIN</>
+	 first.
+        </para>
+       </note>
+
       </listitem>
      </varlistentry>
 
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index f3bd34fde27..1b603266095 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.299 2002/10/08 17:17:19 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.300 2002/10/09 04:59:38 momjian Exp $
  *
  * NOTES
  *	  this is the "main" module of the postgres backend and
@@ -76,6 +76,7 @@ char	   *debug_query_string; /* for pgmonitor and
 CommandDest whereToSendOutput = Debug;
 
 extern int	StatementTimeout;
+extern bool autocommit;
 
 static bool dontExecute = false;
 
@@ -122,7 +123,7 @@ static int	ReadCommand(StringInfo inBuf);
 static List *pg_parse_query(StringInfo query_string, Oid *typev, int nargs);
 static List *pg_analyze_and_rewrite(Node *parsetree);
 static void start_xact_command(void);
-static void finish_xact_command(void);
+static void finish_xact_command(bool forceCommit);
 static void SigHupHandler(SIGNAL_ARGS);
 static void FloatExceptionHandler(SIGNAL_ARGS);
 static const char *CreateCommandTag(Node *parsetree);
@@ -825,7 +826,7 @@ pg_exec_query_string(StringInfo query_string,	/* string to execute */
 			 */
 			if (isTransactionStmt)
 			{
-				finish_xact_command();
+				finish_xact_command(false);
 				xact_started = false;
 			}
 		}						/* end loop over queries generated from a
@@ -843,7 +844,19 @@ pg_exec_query_string(StringInfo query_string,	/* string to execute */
 		 */
 		if (lnext(parsetree_item) == NIL && xact_started)
 		{
-			finish_xact_command();
+			/*
+			 *	Don't allow SET/SHOW/RESET to start a new transaction
+			 *	with autocommit off.  We do this by forcing a COMMIT
+			 *	when these commands start a transaction.
+			 */
+			if (autocommit ||
+				IsTransactionState() ||
+				(strcmp(commandTag, "SET") != 0 &&
+				 strcmp(commandTag, "SHOW") != 0 &&
+				 strcmp(commandTag, "RESET") != 0))
+				finish_xact_command(false);
+			else
+				finish_xact_command(true);
 			xact_started = false;
 		}
 
@@ -878,7 +891,7 @@ pg_exec_query_string(StringInfo query_string,	/* string to execute */
 	 * will only happen if the querystring was empty.)
 	 */
 	if (xact_started)
-		finish_xact_command();
+		finish_xact_command(false);
 
 	if (save_Log_duration)
 	{
@@ -907,7 +920,7 @@ start_xact_command(void)
 }
 
 static void
-finish_xact_command(void)
+finish_xact_command(bool forceCommit)
 {
 	/* Invoke IMMEDIATE constraint triggers */
 	DeferredTriggerEndQuery();
@@ -915,7 +928,7 @@ finish_xact_command(void)
 	/* Now commit the command */
 	elog(DEBUG1, "CommitTransactionCommand");
 
-	CommitTransactionCommand(false);
+	CommitTransactionCommand(forceCommit);
 
 #ifdef SHOW_MEMORY_STATS
 	/* Print mem stats at each commit for leak tracking */
@@ -1720,7 +1733,7 @@ PostgresMain(int argc, char *argv[], const char *username)
 	if (!IsUnderPostmaster)
 	{
 		puts("\nPOSTGRES backend interactive interface ");
-		puts("$Revision: 1.299 $ $Date: 2002/10/08 17:17:19 $\n");
+		puts("$Revision: 1.300 $ $Date: 2002/10/09 04:59:38 $\n");
 	}
 
 	/*
@@ -1923,7 +1936,7 @@ PostgresMain(int argc, char *argv[], const char *username)
 				}
 
 				/* commit the function-invocation transaction */
-				finish_xact_command();
+				finish_xact_command(false);
 				break;
 
 				/*
-- 
GitLab