From 90434e6f2cf9fb629069b1b3017ea1a2c1ab07eb Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Tue, 2 Jul 2019 13:35:14 -0400
Subject: [PATCH] Fix tab completion of "SET variable TO|=" to not offer bogus
 completions.

Don't think that the context "UPDATE tab SET var =" is a GUC-setting
command.

If we have "SET var =" but the "var" is not a known GUC variable,
don't offer any completions.  The most likely explanation is that
we've misparsed the context and it's not really a GUC-setting command.

Per gripe from Ken Tanzer.  Back-patch to 9.6.  The issue exists
further back, but before 9.6 the code looks very different and it
doesn't actually know whether the "var" name matches anything,
so I desisted from trying to fix it.

Discussion: https://postgr.es/m/CAD3a31XpXzrZA9TT3BqLSHghdTK+=cXjNCE+oL2Zn4+oWoc=qA@mail.gmail.com
---
 src/bin/psql/tab-complete.c | 39 ++++++++++++++++++++++++-------------
 1 file changed, 26 insertions(+), 13 deletions(-)

diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index 83b2b9cee3c..d4738429587 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -3249,8 +3249,13 @@ psql_completion(const char *text, int start, int end)
 	else if (HeadMatches2("ALTER", "DATABASE|FUNCTION|ROLE|USER") &&
 			 TailMatches2("SET", MatchAny))
 		COMPLETE_WITH_LIST2("FROM CURRENT", "TO");
-	/* Suggest possible variable values */
-	else if (TailMatches3("SET", MatchAny, "TO|="))
+
+	/*
+	 * Suggest possible variable values in SET variable TO|=, along with the
+	 * preceding ALTER syntaxes.
+	 */
+	else if (TailMatches3("SET", MatchAny, "TO|=") &&
+			 !TailMatches5("UPDATE", MatchAny, "SET", MatchAny, "TO|="))
 	{
 		/* special cased code for individual GUCs */
 		if (TailMatches2("DateStyle", "TO|="))
@@ -3273,21 +3278,29 @@ psql_completion(const char *text, int start, int end)
 			/* generic, type based, GUC support */
 			char	   *guctype = get_guctype(prev2_wd);
 
-			if (guctype && strcmp(guctype, "enum") == 0)
+			/*
+			 * Note: if we don't recognize the GUC name, it's important to not
+			 * offer any completions, as most likely we've misinterpreted the
+			 * context and this isn't a GUC-setting command at all.
+			 */
+			if (guctype)
 			{
-				char		querybuf[1024];
+				if (strcmp(guctype, "enum") == 0)
+				{
+					char		querybuf[1024];
 
-				snprintf(querybuf, sizeof(querybuf), Query_for_enum, prev2_wd);
-				COMPLETE_WITH_QUERY(querybuf);
-			}
-			else if (guctype && strcmp(guctype, "bool") == 0)
-				COMPLETE_WITH_LIST9("on", "off", "true", "false", "yes", "no",
-									"1", "0", "DEFAULT");
-			else
-				COMPLETE_WITH_CONST("DEFAULT");
+					snprintf(querybuf, sizeof(querybuf),
+							 Query_for_enum, prev2_wd);
+					COMPLETE_WITH_QUERY(querybuf);
+				}
+				else if (strcmp(guctype, "bool") == 0)
+					COMPLETE_WITH_LIST9("on", "off", "true", "false",
+										"yes", "no", "1", "0", "DEFAULT");
+				else
+					COMPLETE_WITH_CONST("DEFAULT");
 
-			if (guctype)
 				free(guctype);
+			}
 		}
 	}
 
-- 
GitLab