From 8d68e7102e2200bb99fa913fa936f9bd16b52092 Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi <horiguchi.kyotaro@lab.ntt.co.jp>
Date: Fri, 16 Sep 2016 11:36:13 +0900
Subject: [PATCH 3/6] Fix suggested keywords to follow input in tab-completion
 session 2

The prevous fix left some completions unfixed. This commit moves
keywords of Query_for_list_of_set_vars/alter_system_set_vars/show_vars
out of the constant and process the keywords as the same as other
syntaxes.

Role name is a bother. PUBLIC, CURRENT_USER, SESSION_USER are
certainly roles and the last two are used in many places. In this
patch I renamed Query_for_list_of_roles to
Query_for_list_of_true_roles and added Query_for_list_of_roles that
having CURRENT_USER and SESSION_USER. But this might be too much.
---
 src/bin/psql/tab-complete-macros.h |   2 +
 src/bin/psql/tab-complete.c        | 100 ++++++++++++++++++++++---------------
 2 files changed, 62 insertions(+), 40 deletions(-)

diff --git a/src/bin/psql/tab-complete-macros.h b/src/bin/psql/tab-complete-macros.h
index 3e91bbe..3597004 100644
--- a/src/bin/psql/tab-complete-macros.h
+++ b/src/bin/psql/tab-complete-macros.h
@@ -437,6 +437,8 @@ do { \
 #define ADDLIST3(s1, s2, s3) additional_kw_query(text, 3, s1, s2, s3)
 #define ADDLIST4(s1, s2, s3, s4) \
 	additional_kw_query(text, 4, s1, s2, s3, s4)
+#define ADDLIST6(s1, s2, s3, s4, s5, s6)				\
+	additional_kw_query(text, 6, s1, s2, s3, s4, s5, s6)
 #define ADDLIST13(s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13) \
 	additional_kw_query(text, 12, s1, s2, s3, s4, s5, s6, s7,		\
 						s8, s9, s10, s11, s12, s13)
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index 85bb363..3af623c 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -449,43 +449,38 @@ static const SchemaQuery Query_for_list_of_matviews = {
 " WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s'"
 
 #define Query_for_list_of_alter_system_set_vars \
-"SELECT name FROM "\
-" (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings "\
-"  WHERE context != 'internal') ss "\
-" WHERE substring(name,1,%d)='%s'"\
-" UNION ALL SELECT 'all' ss"
-
-#define Query_for_list_of_set_vars \
-"SELECT name FROM "\
-" (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings "\
-"  WHERE context IN ('user', 'superuser') "\
-"  UNION ALL SELECT 'constraints' "\
-"  UNION ALL SELECT 'transaction' "\
-"  UNION ALL SELECT 'session' "\
-"  UNION ALL SELECT 'role' "\
-"  UNION ALL SELECT 'tablespace' "\
-"  UNION ALL SELECT 'all') ss "\
+"SELECT name FROM "													\
+" (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings " \
+"  WHERE context != 'internal') ss "								\
 " WHERE substring(name,1,%d)='%s'"
 
+#define Query_for_list_of_set_vars									 \
+"SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings " \
+"  WHERE context IN ('user', 'superuser') "							\
+"   AND substring(name,1,%d)='%s'"
+
 #define Query_for_list_of_show_vars \
-"SELECT name FROM "\
-" (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings "\
-"  UNION ALL SELECT 'session authorization' "\
-"  UNION ALL SELECT 'all') ss "\
+"SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings " \
 " WHERE substring(name,1,%d)='%s'"
 
-#define Query_for_list_of_roles \
+#define Query_for_list_of_true_roles \
 " SELECT pg_catalog.quote_ident(rolname) "\
 "   FROM pg_catalog.pg_roles "\
 "  WHERE substring(pg_catalog.quote_ident(rolname),1,%d)='%s'"
 
+#define Query_for_list_of_roles \
+	concatenate_strings(												\
+		" SELECT pg_catalog.quote_ident(rolname) "						\
+		 "   FROM pg_catalog.pg_roles "									\
+		 "  WHERE substring(pg_catalog.quote_ident(rolname),1,%d)='%s'",	\
+		ADDLIST2("CURRENT_USER", "SESSION_USER"))
+
 #define Query_for_list_of_grant_roles \
-" SELECT pg_catalog.quote_ident(rolname) "\
-"   FROM pg_catalog.pg_roles "\
-"  WHERE substring(pg_catalog.quote_ident(rolname),1,%d)='%s'"\
-" UNION ALL SELECT 'PUBLIC'"\
-" UNION ALL SELECT 'CURRENT_USER'"\
-" UNION ALL SELECT 'SESSION_USER'"
+	concatenate_strings(												\
+		" SELECT pg_catalog.quote_ident(rolname) "						\
+		 "   FROM pg_catalog.pg_roles "									\
+		 "  WHERE substring(pg_catalog.quote_ident(rolname),1,%d)='%s'",	\
+		ADDLIST3("PUBLIC", "CURRENT_USER", "SESSION_USER"))
 
 /* the silly-looking length condition is just to eat up the current word */
 #define Query_for_table_owning_index \
@@ -681,13 +676,13 @@ static const SchemaQuery Query_for_list_of_matviews = {
 "         WHERE pg_catalog.quote_ident(polname)='%s')"
 
 #define Query_for_enum \
-" SELECT name FROM ( "\
-"   SELECT pg_catalog.quote_ident(pg_catalog.unnest(enumvals)) AS name "\
-"     FROM pg_catalog.pg_settings "\
-"    WHERE pg_catalog.lower(name)=pg_catalog.lower('%s') "\
-"    UNION ALL " \
-"   SELECT 'DEFAULT' ) ss "\
-"  WHERE pg_catalog.substring(name,1,%%d)='%%s'"
+	concatenate_strings( \
+		" SELECT name FROM ( "											\
+	"   SELECT pg_catalog.quote_ident(pg_catalog.unnest(enumvals)) AS name " \
+	"     FROM pg_catalog.pg_settings "									\
+	"    WHERE pg_catalog.lower(name)=pg_catalog.lower('%s')) ss "		\
+	"  WHERE pg_catalog.substring(name,1,%%d)='%%s'", \
+		ADDLIST1("DEFAULT"))
 
 /*
  * This is a list of all "things" in Pgsql, which can show up after CREATE or
@@ -727,7 +722,7 @@ static const pgsql_thing_t words_after_create[] = {
 	{"FOREIGN DATA WRAPPER", NULL, NULL},
 	{"FOREIGN TABLE", NULL, NULL},
 	{"FUNCTION", NULL, &Query_for_list_of_functions},
-	{"GROUP", Query_for_list_of_roles},
+	{"GROUP", Query_for_list_of_true_roles},
 	{"LANGUAGE", Query_for_list_of_languages},
 	{"INDEX", NULL, &Query_for_list_of_indexes},
 	{"MATERIALIZED VIEW", NULL, &Query_for_list_of_matviews},
@@ -736,7 +731,7 @@ static const pgsql_thing_t words_after_create[] = {
 	{"OWNED", NULL, NULL, THING_NO_CREATE},		/* for DROP OWNED BY ... */
 	{"PARSER", Query_for_list_of_ts_parsers, NULL, THING_NO_SHOW},
 	{"POLICY", NULL, NULL},
-	{"ROLE", Query_for_list_of_roles},
+	{"ROLE", Query_for_list_of_true_roles},
 	{"RULE", "SELECT pg_catalog.quote_ident(rulename) FROM pg_catalog.pg_rules WHERE substring(pg_catalog.quote_ident(rulename),1,%d)='%s'"},
 	{"SCHEMA", Query_for_list_of_schemas},
 	{"SEQUENCE", NULL, &Query_for_list_of_sequences},
@@ -751,7 +746,7 @@ static const pgsql_thing_t words_after_create[] = {
 	{"UNIQUE", NULL, NULL, THING_NO_DROP},		/* for CREATE UNIQUE INDEX ... */
 	{"UNLOGGED", NULL, NULL, THING_NO_DROP},	/* for CREATE UNLOGGED TABLE
 												 * ... */
-	{"USER", Query_for_list_of_roles},
+	{"USER", Query_for_list_of_true_roles},
 	{"USER MAPPING FOR", NULL, NULL},
 	{"VIEW", NULL, &Query_for_list_of_views},
 	{NULL}						/* end of list */
@@ -776,6 +771,7 @@ static char **complete_from_variables(const char *text,
 static char *complete_from_files(const char *text, int state);
 
 static char *pg_strdup_keyword_case(const char *s, const char *ref);
+static char *concatenate_strings(const char *s1, const char *s2);
 static char *additional_kw_query( const char *ref, int n, ...);
 static char *escape_string(const char *text);
 static PGresult *exec_query(const char *query);
@@ -1296,7 +1292,8 @@ psql_completion_internal(const char *text, char **previous_words,
 		COMPLETE_WITH_LIST2("SET", "RESET");
 	/* ALTER SYSTEM SET|RESET <name> */
 	if (Matches3("ALTER", "SYSTEM", "SET|RESET"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_alter_system_set_vars);
+		COMPLETE_WITH_QUERY(Query_for_list_of_alter_system_set_vars,
+							ADDLIST1("ALL"));
 	/* ALTER VIEW <name> */
 	if (Matches3("ALTER", "VIEW", MatchAny))
 		COMPLETE_WITH_LIST4("ALTER COLUMN", "OWNER TO", "RENAME TO",
@@ -2470,9 +2467,12 @@ psql_completion_internal(const char *text, char **previous_words,
 /* SET, RESET, SHOW */
 	/* Complete with a variable name */
 	if (TailMatches1("SET|RESET") && !TailMatches3("UPDATE", MatchAny, "SET"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_set_vars);
+		COMPLETE_WITH_QUERY(Query_for_list_of_set_vars,
+							ADDLIST6("CONSTRAINTS", "TRANSACTION", "SESSION",
+									 "ROLE", "TABLESPACE", "ALL"));
 	if (Matches1("SHOW"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_show_vars);
+		COMPLETE_WITH_QUERY(Query_for_list_of_show_vars, 
+							ADDLIST2("SESSION AUTHORIZATION", "ALL"));
 	/* Complete "SET TRANSACTION" */
 	if (Matches2("SET", "TRANSACTION"))
 		COMPLETE_WITH_LIST5("SNAPSHOT", "ISOLATION LEVEL", "READ", "DEFERRABLE", "NOT DEFERRABLE");
@@ -3397,6 +3397,26 @@ pg_strdup_keyword_case(const char *s, const char *ref)
 	return ret;
 }
 
+/*
+ * Returns concatenated string.
+ * Note: the internal buffer is static so this cannot be called recursively.
+ */
+static char *
+concatenate_strings(const char *s1, const char *s2)
+{
+	static PQExpBuffer qbuf = NULL;
+	
+	if (qbuf == NULL)
+		qbuf = createPQExpBuffer();
+	else
+		resetPQExpBuffer(qbuf);
+
+	appendPQExpBufferStr(qbuf, s1);
+	appendPQExpBufferStr(qbuf, s2);
+
+	return qbuf->data;
+}
+
 /* Construct codelet to append given keywords  */
 static char *
 additional_kw_query(const char *ref, int n, ...)
-- 
2.9.2

