From 1553be4a0bdff56214902a26fa62f0c09be15f6b Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Sun, 19 Dec 2004 19:39:47 +0000
Subject: [PATCH] Prevent evaluation of backticks while discarding unwanted
 arguments after an unknown or failed psql backslash command, and also while
 discarding "extra" arguments of a putatively valid backslash command. In the
 case of an unknown/failed command, make sure we discard the whole rest of the
 line, rather than trying to resume at the next backslash.  Per discussion
 with Thomer Gil.

---
 src/bin/psql/command.c  | 22 ++++++++++++++++------
 src/bin/psql/psqlscan.h |  5 +++--
 src/bin/psql/psqlscan.l | 40 +++++++++++++++++++++++++++-------------
 3 files changed, 46 insertions(+), 21 deletions(-)

diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index c6ad507ca8..6388f20dd7 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2000-2004, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.137 2004/11/30 20:00:34 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.138 2004/12/19 19:39:47 tgl Exp $
  */
 #include "postgres_fe.h"
 #include "command.h"
@@ -127,13 +127,23 @@ HandleSlashCmds(PsqlScanState scan_state,
 		status = CMD_ERROR;
 	}
 
-	/* eat the rest of the options, if any */
-	while ((arg = psql_scan_slash_option(scan_state,
-										 OT_NORMAL, NULL, false)))
+	if (status != CMD_ERROR)
 	{
-		if (status != CMD_ERROR)
+		/* eat any remaining arguments after a valid command */
+		/* note we suppress evaluation of backticks here */
+		while ((arg = psql_scan_slash_option(scan_state,
+											 OT_VERBATIM, NULL, false)))
+		{
 			psql_error("\\%s: extra argument \"%s\" ignored\n", cmd, arg);
-		free(arg);
+			free(arg);
+		}
+	}
+	else
+	{
+		/* silently throw away rest of line after an erroneous command */
+		while ((arg = psql_scan_slash_option(scan_state,
+											 OT_WHOLE_LINE, NULL, false)))
+			free(arg);
 	}
 
 	/* if there is a trailing \\, swallow it */
diff --git a/src/bin/psql/psqlscan.h b/src/bin/psql/psqlscan.h
index a4cb945a23..7b506a5a11 100644
--- a/src/bin/psql/psqlscan.h
+++ b/src/bin/psql/psqlscan.h
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2000-2004, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/bin/psql/psqlscan.h,v 1.3 2004/08/29 05:06:54 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/psqlscan.h,v 1.4 2004/12/19 19:39:47 tgl Exp $
  */
 #ifndef PSQLSCAN_H
 #define PSQLSCAN_H
@@ -32,7 +32,8 @@ enum slash_option_type
 	OT_SQLID,					/* treat as SQL identifier */
 	OT_SQLIDHACK,				/* SQL identifier, but don't downcase */
 	OT_FILEPIPE,				/* it's a filename or pipe */
-	OT_WHOLE_LINE				/* just snarf the rest of the line */
+	OT_WHOLE_LINE,				/* just snarf the rest of the line */
+	OT_VERBATIM					/* literal (no backticks or variables) */
 };
 
 
diff --git a/src/bin/psql/psqlscan.l b/src/bin/psql/psqlscan.l
index 6311ffab17..de738958d1 100644
--- a/src/bin/psql/psqlscan.l
+++ b/src/bin/psql/psqlscan.l
@@ -31,7 +31,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/bin/psql/psqlscan.l,v 1.7 2004/08/29 04:13:02 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/bin/psql/psqlscan.l,v 1.8 2004/12/19 19:39:47 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -723,24 +723,38 @@ other			.
 				}
 
 "`"				{
-					*option_quote = '`';
-					BEGIN(xslashbackquote);
+					if (option_type == OT_VERBATIM)
+					{
+						/* in verbatim mode, backquote is not special */
+						ECHO;
+						BEGIN(xslashdefaultarg);
+					}
+					else
+					{
+						*option_quote = '`';
+						BEGIN(xslashbackquote);
+					}
 				}
 
 :[A-Za-z0-9_]*	{
 					/* Possible psql variable substitution */
-					const char *value;
+					if (option_type == OT_VERBATIM)
+						ECHO;
+					else
+					{
+						const char *value;
 
-					value = GetVariable(pset.vars, yytext + 1);
+						value = GetVariable(pset.vars, yytext + 1);
 
-					/*
-					 * The variable value is just emitted without any
-					 * further examination.  This is consistent with the
-					 * pre-8.0 code behavior, if not with the way that
-					 * variables are handled outside backslash commands.
-					 */
-					if (value)
-						appendPQExpBufferStr(output_buf, value);
+						/*
+						 * The variable value is just emitted without any
+						 * further examination.  This is consistent with the
+						 * pre-8.0 code behavior, if not with the way that
+						 * variables are handled outside backslash commands.
+						 */
+						if (value)
+							appendPQExpBufferStr(output_buf, value);
+					}
 
 					*option_quote = ':';