From 951ec872c703886626c56d08254d38c0cd88fc9e Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Tue, 15 Oct 2002 02:24:16 +0000
Subject: [PATCH] Fix psql to cope with autocommit off, at least during
 startup. Behavior of backslash commands (especially for large objects) may
 still require some thought.

---
 src/bin/psql/command.c   | 12 +++++++----
 src/bin/psql/common.c    | 44 +++++++++++++++++++++++++++-----------
 src/bin/psql/common.h    |  4 ++--
 src/bin/psql/copy.c      |  4 ++--
 src/bin/psql/describe.c  | 46 ++++++++++++++++++++--------------------
 src/bin/psql/large_obj.c | 22 +++++++++----------
 6 files changed, 78 insertions(+), 54 deletions(-)

diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index a9477c68ed9..963c3aed3b1 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -3,7 +3,7 @@
  *
  * Copyright 2000-2002 by PostgreSQL Global Development Group
  *
- * $Header: /cvsroot/pgsql/src/bin/psql/command.c,v 1.82 2002/10/03 17:09:41 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/bin/psql/command.c,v 1.83 2002/10/15 02:24:15 tgl Exp $
  */
 #include "postgres_fe.h"
 #include "command.h"
@@ -1464,13 +1464,17 @@ test_superuser(const char *username)
 	if (!username)
 		return false;
 
+	/*
+	 * Use begin/commit to avoid starting a transaction block if server
+	 * has autocommit off by default.
+	 */
 	initPQExpBuffer(&buf);
-	printfPQExpBuffer(&buf, "SELECT usesuper FROM pg_catalog.pg_user WHERE usename = '%s'", username);
-	res = PSQLexec(buf.data);
+	printfPQExpBuffer(&buf, "BEGIN; SELECT usesuper FROM pg_catalog.pg_user WHERE usename = '%s'; COMMIT", username);
+	res = PSQLexec(buf.data, true);
 	termPQExpBuffer(&buf);
 
 	answer =
-		(PQntuples(res) > 0 && PQnfields(res) > 0
+		(res && PQntuples(res) > 0 && PQnfields(res) > 0
 		 && !PQgetisnull(res, 0, 0)
 		 && PQgetvalue(res, 0, 0)
 		 && strcmp(PQgetvalue(res, 0, 0), "t") == 0);
diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c
index c451640ee0d..46186e55692 100644
--- a/src/bin/psql/common.c
+++ b/src/bin/psql/common.c
@@ -3,7 +3,7 @@
  *
  * Copyright 2000 by PostgreSQL Global Development Group
  *
- * $Header: /cvsroot/pgsql/src/bin/psql/common.c,v 1.46 2002/10/03 17:09:41 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/bin/psql/common.c,v 1.47 2002/10/15 02:24:16 tgl Exp $
  */
 #include "postgres_fe.h"
 
@@ -204,12 +204,19 @@ handle_sigint(SIGNAL_ARGS)
  *
  * This is the way to send "backdoor" queries (those not directly entered
  * by the user). It is subject to -E but not -e.
+ *
+ * If the given querystring generates multiple PGresults, normally the last
+ * one is returned to the caller.  However, if ignore_command_ok is TRUE,
+ * then PGresults with status PGRES_COMMAND_OK are ignored.  This is intended
+ * mainly to allow locutions such as "begin; select ...; commit".
  */
 PGresult *
-PSQLexec(const char *query)
+PSQLexec(const char *query, bool ignore_command_ok)
 {
-	PGresult   *res;
+	PGresult   *res = NULL;
+	PGresult   *newres;
 	const char *var;
+	ExecStatusType rstatus;
 
 	if (!pset.db)
 	{
@@ -230,18 +237,31 @@ PSQLexec(const char *query)
 		return NULL;
 
 	cancelConn = pset.db;
-	res = PQexec(pset.db, query);
-	if (PQresultStatus(res) == PGRES_COPY_IN)
-		copy_in_state = true;
+	if (PQsendQuery(pset.db, query))
+	{
+		while ((newres = PQgetResult(pset.db)) != NULL)
+		{
+			if (ignore_command_ok &&
+				PQresultStatus(newres) == PGRES_COMMAND_OK)
+			{
+				PQclear(newres);
+				continue;
+			}
+			PQclear(res);
+			res = newres;
+		}
+	}
+	rstatus = PQresultStatus(res);
 	/* keep cancel connection for copy out state */
-	if (PQresultStatus(res) != PGRES_COPY_OUT)
+	if (rstatus != PGRES_COPY_OUT)
 		cancelConn = NULL;
+	if (rstatus == PGRES_COPY_IN)
+		copy_in_state = true;
 
-	if (res && (PQresultStatus(res) == PGRES_COMMAND_OK ||
-				PQresultStatus(res) == PGRES_TUPLES_OK ||
-				PQresultStatus(res) == PGRES_COPY_IN ||
-				PQresultStatus(res) == PGRES_COPY_OUT)
-		)
+	if (res && (rstatus == PGRES_COMMAND_OK ||
+				rstatus == PGRES_TUPLES_OK ||
+				rstatus == PGRES_COPY_IN ||
+				rstatus == PGRES_COPY_OUT))
 		return res;
 	else
 	{
diff --git a/src/bin/psql/common.h b/src/bin/psql/common.h
index f11a7981278..a5b0881245c 100644
--- a/src/bin/psql/common.h
+++ b/src/bin/psql/common.h
@@ -3,7 +3,7 @@
  *
  * Copyright 2000 by PostgreSQL Global Development Group
  *
- * $Header: /cvsroot/pgsql/src/bin/psql/common.h,v 1.18 2002/07/06 20:12:30 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/bin/psql/common.h,v 1.19 2002/10/15 02:24:16 tgl Exp $
  */
 #ifndef COMMON_H
 #define COMMON_H
@@ -33,7 +33,7 @@ extern PGconn *cancelConn;
 extern void handle_sigint(SIGNAL_ARGS);
 #endif   /* not WIN32 */
 
-extern PGresult *PSQLexec(const char *query);
+extern PGresult *PSQLexec(const char *query, bool ignore_command_ok);
 
 extern bool SendQuery(const char *query);
 
diff --git a/src/bin/psql/copy.c b/src/bin/psql/copy.c
index 926641f5f41..7e1b05d5fe8 100644
--- a/src/bin/psql/copy.c
+++ b/src/bin/psql/copy.c
@@ -3,7 +3,7 @@
  *
  * Copyright 2000 by PostgreSQL Global Development Group
  *
- * $Header: /cvsroot/pgsql/src/bin/psql/copy.c,v 1.26 2002/10/03 17:09:41 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/bin/psql/copy.c,v 1.27 2002/10/15 02:24:16 tgl Exp $
  */
 #include "postgres_fe.h"
 #include "copy.h"
@@ -324,7 +324,7 @@ do_copy(const char *args)
 		return false;
 	}
 
-	result = PSQLexec(query.data);
+	result = PSQLexec(query.data, false);
 	termPQExpBuffer(&query);
 
 	switch (PQresultStatus(result))
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index 9c4c93c0df4..017afbc83c7 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -3,7 +3,7 @@
  *
  * Copyright 2000-2002 by PostgreSQL Global Development Group
  *
- * $Header: /cvsroot/pgsql/src/bin/psql/describe.c,v 1.69 2002/09/22 20:44:22 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/bin/psql/describe.c,v 1.70 2002/10/15 02:24:16 tgl Exp $
  */
 #include "postgres_fe.h"
 #include "describe.h"
@@ -91,7 +91,7 @@ describeAggregates(const char *pattern, bool verbose)
 
 	appendPQExpBuffer(&buf, "ORDER BY 1, 2, 3;");
 
-	res = PSQLexec(buf.data);
+	res = PSQLexec(buf.data, false);
 	termPQExpBuffer(&buf);
 	if (!res)
 		return false;
@@ -161,7 +161,7 @@ describeFunctions(const char *pattern, bool verbose)
 
 	appendPQExpBuffer(&buf, "ORDER BY 2, 3, 1, 4;");
 
-	res = PSQLexec(buf.data);
+	res = PSQLexec(buf.data, false);
 	termPQExpBuffer(&buf);
 	if (!res)
 		return false;
@@ -229,7 +229,7 @@ describeTypes(const char *pattern, bool verbose)
 
 	appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
 
-	res = PSQLexec(buf.data);
+	res = PSQLexec(buf.data, false);
 	termPQExpBuffer(&buf);
 	if (!res)
 		return false;
@@ -276,7 +276,7 @@ describeOperators(const char *pattern)
 
 	appendPQExpBuffer(&buf, "ORDER BY 1, 2, 3, 4;");
 
-	res = PSQLexec(buf.data);
+	res = PSQLexec(buf.data, false);
 	termPQExpBuffer(&buf);
 	if (!res)
 		return false;
@@ -321,7 +321,7 @@ listAllDbs(bool verbose)
 		  "\n  LEFT JOIN pg_catalog.pg_user u ON d.datdba = u.usesysid\n"
 					  "ORDER BY 1;");
 
-	res = PSQLexec(buf.data);
+	res = PSQLexec(buf.data, false);
 	termPQExpBuffer(&buf);
 	if (!res)
 		return false;
@@ -374,7 +374,7 @@ permissionsList(const char *pattern)
 
 	appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
 
-	res = PSQLexec(buf.data);
+	res = PSQLexec(buf.data, false);
 	if (!res)
 	{
 		termPQExpBuffer(&buf);
@@ -532,7 +532,7 @@ objectDescription(const char *pattern)
 
 	appendPQExpBuffer(&buf, "ORDER BY 1, 2, 3;");
 
-	res = PSQLexec(buf.data);
+	res = PSQLexec(buf.data, false);
 	termPQExpBuffer(&buf);
 	if (!res)
 		return false;
@@ -576,7 +576,7 @@ describeTableDetails(const char *pattern, bool verbose)
 
 	appendPQExpBuffer(&buf, "ORDER BY 2, 3;");
 
-	res = PSQLexec(buf.data);
+	res = PSQLexec(buf.data, false);
 	termPQExpBuffer(&buf);
 	if (!res)
 		return false;
@@ -655,7 +655,7 @@ describeOneTableDetails(const char *schemaname,
 	 "SELECT relhasindex, relkind, relchecks, reltriggers, relhasrules\n"
 					  "FROM pg_catalog.pg_class WHERE oid = '%s'",
 					  oid);
-	res = PSQLexec(buf.data);
+	res = PSQLexec(buf.data, false);
 	if (!res)
 		goto error_return;
 
@@ -711,7 +711,7 @@ describeOneTableDetails(const char *schemaname,
 		appendPQExpBuffer(&buf, " AND a.attrelid = i.indexrelid");
 	appendPQExpBuffer(&buf, "\nORDER BY a.attnum");
 
-	res = PSQLexec(buf.data);
+	res = PSQLexec(buf.data, false);
 	if (!res)
 		goto error_return;
 
@@ -721,7 +721,7 @@ describeOneTableDetails(const char *schemaname,
 		PGresult   *result;
 
 		printfPQExpBuffer(&buf, "SELECT pg_catalog.pg_get_viewdef('%s'::pg_catalog.oid)", oid);
-		result = PSQLexec(buf.data);
+		result = PSQLexec(buf.data, false);
 		if (!result)
 			goto error_return;
 
@@ -763,7 +763,7 @@ describeOneTableDetails(const char *schemaname,
 							   "WHERE d.adrelid = '%s' AND d.adnum = %s",
 								  oid, PQgetvalue(res, i, 4));
 
-				result = PSQLexec(buf.data);
+				result = PSQLexec(buf.data, false);
 
 				if (cells[i * cols + 2][0])
 					strcat(cells[i * cols + 2], " ");
@@ -830,7 +830,7 @@ describeOneTableDetails(const char *schemaname,
 						  "AND i.indrelid = c2.oid",
 						  oid);
 
-		result = PSQLexec(buf.data);
+		result = PSQLexec(buf.data, false);
 		if (!result)
 			goto error_return;
 		else if (PQntuples(result) != 1)
@@ -886,7 +886,7 @@ describeOneTableDetails(const char *schemaname,
 							  "FROM pg_catalog.pg_rewrite r\n"
 				   "WHERE r.ev_class = '%s' AND r.rulename != '_RETURN'",
 							  oid);
-			result = PSQLexec(buf.data);
+			result = PSQLexec(buf.data, false);
 			if (!result)
 				goto error_return;
 			else
@@ -944,7 +944,7 @@ describeOneTableDetails(const char *schemaname,
 							  "WHERE c.oid = '%s' AND c.oid = i.indrelid AND i.indexrelid = c2.oid\n"
 							  "ORDER BY i.indisprimary DESC, i.indisunique DESC, c2.relname",
 							  oid);
-			result1 = PSQLexec(buf.data);
+			result1 = PSQLexec(buf.data, false);
 			if (!result1)
 				goto error_return;
 			else
@@ -959,7 +959,7 @@ describeOneTableDetails(const char *schemaname,
 							  "FROM pg_catalog.pg_constraint r\n"
 						   "WHERE r.conrelid = '%s' AND r.contype = 'c'",
 							  oid);
-			result2 = PSQLexec(buf.data);
+			result2 = PSQLexec(buf.data, false);
 			if (!result2)
 				goto error_return;
 			else
@@ -974,7 +974,7 @@ describeOneTableDetails(const char *schemaname,
 							  "FROM pg_catalog.pg_rewrite r\n"
 							  "WHERE r.ev_class = '%s'",
 							  oid);
-			result3 = PSQLexec(buf.data);
+			result3 = PSQLexec(buf.data, false);
 			if (!result3)
 				goto error_return;
 			else
@@ -994,7 +994,7 @@ describeOneTableDetails(const char *schemaname,
 							  "   JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
 							  "   WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))",
 							  oid);
-			result4 = PSQLexec(buf.data);
+			result4 = PSQLexec(buf.data, false);
 			if (!result4)
 				goto error_return;
 			else
@@ -1010,7 +1010,7 @@ describeOneTableDetails(const char *schemaname,
 							  "FROM pg_catalog.pg_constraint r\n"
 						   "WHERE r.conrelid = '%s' AND r.contype = 'f'",
 							  oid);
-			result5 = PSQLexec(buf.data);
+			result5 = PSQLexec(buf.data, false);
 			if (!result5)
 				goto error_return;
 			else
@@ -1206,7 +1206,7 @@ describeUsers(const char *pattern)
 
 	appendPQExpBuffer(&buf, "ORDER BY 1;");
 
-	res = PSQLexec(buf.data);
+	res = PSQLexec(buf.data, false);
 	termPQExpBuffer(&buf);
 	if (!res)
 		return false;
@@ -1312,7 +1312,7 @@ listTables(const char *tabtypes, const char *pattern, bool verbose)
 
 	appendPQExpBuffer(&buf, "ORDER BY 1,2;");
 
-	res = PSQLexec(buf.data);
+	res = PSQLexec(buf.data, false);
 	termPQExpBuffer(&buf);
 	if (!res)
 		return false;
@@ -1374,7 +1374,7 @@ listDomains(const char *pattern)
 
 	appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
 
-	res = PSQLexec(buf.data);
+	res = PSQLexec(buf.data, false);
 	termPQExpBuffer(&buf);
 	if (!res)
 		return false;
diff --git a/src/bin/psql/large_obj.c b/src/bin/psql/large_obj.c
index 9bf51622cc4..fbe8a32a183 100644
--- a/src/bin/psql/large_obj.c
+++ b/src/bin/psql/large_obj.c
@@ -3,7 +3,7 @@
  *
  * Copyright 2000-2002 by PostgreSQL Global Development Group
  *
- * $Header: /cvsroot/pgsql/src/bin/psql/large_obj.c,v 1.22 2002/10/03 17:09:41 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/bin/psql/large_obj.c,v 1.23 2002/10/15 02:24:16 tgl Exp $
  */
 #include "postgres_fe.h"
 #include "large_obj.h"
@@ -53,7 +53,7 @@ handle_transaction(void)
 	notice[0] = '\0';
 	old_notice_hook = PQsetNoticeProcessor(pset.db, _my_notice_handler, NULL);
 
-	res = PSQLexec(commit ? "COMMIT" : "ROLLBACK");
+	res = PSQLexec(commit ? "COMMIT" : "ROLLBACK", false);
 	if (!res)
 		return false;
 
@@ -104,7 +104,7 @@ do_lo_export(const char *loid_arg, const char *filename_arg)
 		if (!handle_transaction())
 			return false;
 
-		if (!(res = PSQLexec("BEGIN")))
+		if (!(res = PSQLexec("BEGIN", false)))
 			return false;
 
 		PQclear(res);
@@ -125,7 +125,7 @@ do_lo_export(const char *loid_arg, const char *filename_arg)
 
 	if (own_transaction)
 	{
-		if (!(res = PSQLexec("COMMIT")))
+		if (!(res = PSQLexec("COMMIT", false)))
 		{
 			res = PQexec(pset.db, "ROLLBACK");
 			PQclear(res);
@@ -171,7 +171,7 @@ do_lo_import(const char *filename_arg, const char *comment_arg)
 		if (!handle_transaction())
 			return false;
 
-		if (!(res = PSQLexec("BEGIN")))
+		if (!(res = PSQLexec("BEGIN", false)))
 			return false;
 
 		PQclear(res);
@@ -222,7 +222,7 @@ do_lo_import(const char *filename_arg, const char *comment_arg)
 		}
 		strcpy(bufptr, "')");
 
-		if (!(res = PSQLexec(cmdbuf)))
+		if (!(res = PSQLexec(cmdbuf, false)))
 		{
 			if (own_transaction)
 			{
@@ -239,7 +239,7 @@ do_lo_import(const char *filename_arg, const char *comment_arg)
 
 	if (own_transaction)
 	{
-		if (!(res = PSQLexec("COMMIT")))
+		if (!(res = PSQLexec("COMMIT", false)))
 		{
 			res = PQexec(pset.db, "ROLLBACK");
 			PQclear(res);
@@ -288,7 +288,7 @@ do_lo_unlink(const char *loid_arg)
 		if (!handle_transaction())
 			return false;
 
-		if (!(res = PSQLexec("BEGIN")))
+		if (!(res = PSQLexec("BEGIN", false)))
 			return false;
 
 		PQclear(res);
@@ -314,7 +314,7 @@ do_lo_unlink(const char *loid_arg)
 		sprintf(buf, "DELETE FROM pg_catalog.pg_description WHERE objoid = '%u' "
 				"AND classoid = 'pg_catalog.pg_largeobject'::regclass",
 				loid);
-		if (!(res = PSQLexec(buf)))
+		if (!(res = PSQLexec(buf, false)))
 		{
 			if (own_transaction)
 			{
@@ -327,7 +327,7 @@ do_lo_unlink(const char *loid_arg)
 
 	if (own_transaction)
 	{
-		if (!(res = PSQLexec("COMMIT")))
+		if (!(res = PSQLexec("COMMIT", false)))
 		{
 			res = PQexec(pset.db, "ROLLBACK");
 			PQclear(res);
@@ -362,7 +362,7 @@ do_lo_list(void)
 			 "ORDER BY \"ID\"",
 			 gettext("Description"));
 
-	res = PSQLexec(buf);
+	res = PSQLexec(buf, false);
 	if (!res)
 		return false;
 
-- 
GitLab