Hello, sorry for being a bit late.
The attatched are the new version of the patch.. set.

1. 0001-Suggest-IF-NOT-EXISTS-for-tab-completion-of-psql.patch

 Adds IF (NOT) EXISTS completion. It doesn't fix the issue that
 the case of additional keywords don't follow the input.

2. 0002-Make-added-keywords-for-completion-queries-follow-to.patch

 Fixes the case-don't-follow issue by introducing a new macro set
 ADDLISTn(). This leaves the issue for keywords along with
 attributes.

3. 0003-Make-COMPLETE_WITH_ATTR-to-accept-additional-keyword.patch

  Fixes the issue left after 0002 patch. 
  This patch does the following
  things.
  
  1. Change completion_charp from const char * to PQExpBuffer.
  
  2. Chnage COMPLETE_WITH_QUERY and COMPLETE_WITH_ATTR to accept
     an expression instead of string literal.
  
  3. Replace all additional keyword lists in psql_copmletion with
     ADDLISTn() expression.


At Fri, 01 Apr 2016 11:52:03 +0900 (Tokyo Standard Time), Kyotaro HORIGUCHI 
<horiguchi.kyot...@lab.ntt.co.jp> wrote in 
<20160401.115203.98896697.horiguchi.kyot...@lab.ntt.co.jp>
> > > > I found new warning
> > > >
> > > >  tab-complete.c:1438:87: warning: right-hand operand of comma expression
> > > > has no effect [-Wunused-value]
> > >
> > > Mmm. Google said me that gcc 4.9 does so. I'm using 4.8.5 so I
> > > haven't see the warning.
> > >
> > > https://gcc.gnu.org/gcc-4.9/porting_to.html
> > >
> > > 1436:   else if (HeadMatches2("CREATE", "SCHEMA") &&
> > > 1437:                    SHIFT_TO_LAST1("CREATE") &&
> > > 1438:                    false) {} /* FALL THROUGH */
...
> > > But the right hand value (true) is actually "used" in the
> > > expression (even though not effective). Perhaps (true && false)
> > > was potimized as false and the true is regarded to be unused?
> > > That's stupid.. Using functions instead of macros seems to solve
> > > this but they needed to be wraped by macros as
> > > additional_kw_query(). That's a pain..
...
> This needs to use gcc 4.9 to address, but CentOS7 doesn't have
> devtools-2 repo so now I'm building CentOS6 environment for this
> purpose. Please wait for a while.

Finally I settled it by replacing comma expression with logical
OR or AND expresssion. gcc 4.9 compains for some unused variables
in flex output but it is the another issue.

I forgot to address COMPLETE_WITH_ATTTR but it needed an overhaul
of some macros and changing the type of completion_charp. The
third patch does it but it might be unacceptable..

regards,

-- 
Kyotaro Horiguchi
NTT Open Source Software Center
>From 3c2bbb46749cffc2fd78cdbfdc181128f99993c1 Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi <horiguchi.kyot...@lab.ntt.co.jp>
Date: Fri, 5 Feb 2016 16:50:35 +0900
Subject: [PATCH 1/3] Suggest IF (NOT) EXISTS for tab-completion of psql

This patch lets psql to suggest "IF (NOT) EXISTS". Addition to that,
since this patch introduces some mechanism for syntactical robustness,
it allows psql completion to omit some optional part on matching.
---
 src/bin/psql/tab-complete.c | 625 ++++++++++++++++++++++++++++++++++++--------
 1 file changed, 517 insertions(+), 108 deletions(-)

diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index eb592bb..a0808cf 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -656,6 +656,10 @@ static const SchemaQuery Query_for_list_of_matviews = {
 "   FROM pg_catalog.pg_roles "\
 "  WHERE substring(pg_catalog.quote_ident(rolname),1,%d)='%s'"
 
+#define Query_for_list_of_rules \
+"SELECT pg_catalog.quote_ident(rulename) FROM pg_catalog.pg_rules "\
+" WHERE substring(pg_catalog.quote_ident(rulename),1,%d)='%s'"
+
 #define Query_for_list_of_grant_roles \
 " SELECT pg_catalog.quote_ident(rolname) "\
 "   FROM pg_catalog.pg_roles "\
@@ -763,6 +767,11 @@ static const SchemaQuery Query_for_list_of_matviews = {
 "SELECT pg_catalog.quote_ident(tmplname) FROM pg_catalog.pg_ts_template "\
 " WHERE substring(pg_catalog.quote_ident(tmplname),1,%d)='%s'"
 
+#define Query_for_list_of_triggers \
+"SELECT pg_catalog.quote_ident(tgname) FROM pg_catalog.pg_trigger "\
+" WHERE substring(pg_catalog.quote_ident(tgname),1,%d)='%s' AND "\
+"       NOT tgisinternal"
+
 #define Query_for_list_of_fdws \
 " SELECT pg_catalog.quote_ident(fdwname) "\
 "   FROM pg_catalog.pg_foreign_data_wrapper "\
@@ -907,7 +916,7 @@ static const pgsql_thing_t words_after_create[] = {
 	{"PARSER", Query_for_list_of_ts_parsers, NULL, THING_NO_SHOW},
 	{"POLICY", NULL, NULL},
 	{"ROLE", Query_for_list_of_roles},
-	{"RULE", "SELECT pg_catalog.quote_ident(rulename) FROM pg_catalog.pg_rules WHERE substring(pg_catalog.quote_ident(rulename),1,%d)='%s'"},
+	{"RULE", Query_for_list_of_rules},
 	{"SCHEMA", Query_for_list_of_schemas},
 	{"SEQUENCE", NULL, &Query_for_list_of_sequences},
 	{"SERVER", Query_for_list_of_servers},
@@ -916,7 +925,7 @@ static const pgsql_thing_t words_after_create[] = {
 	{"TEMP", NULL, NULL, THING_NO_DROP},		/* for CREATE TEMP TABLE ... */
 	{"TEMPLATE", Query_for_list_of_ts_templates, NULL, THING_NO_SHOW},
 	{"TEXT SEARCH", NULL, NULL},
-	{"TRIGGER", "SELECT pg_catalog.quote_ident(tgname) FROM pg_catalog.pg_trigger WHERE substring(pg_catalog.quote_ident(tgname),1,%d)='%s' AND NOT tgisinternal"},
+	{"TRIGGER", Query_for_list_of_triggers},
 	{"TYPE", NULL, &Query_for_list_of_datatypes},
 	{"UNIQUE", NULL, NULL, THING_NO_DROP},		/* for CREATE UNIQUE INDEX ... */
 	{"UNLOGGED", NULL, NULL, THING_NO_DROP},	/* for CREATE UNLOGGED TABLE
@@ -945,6 +954,7 @@ static char **complete_from_variables(const char *text,
 					const char *prefix, const char *suffix, bool need_value);
 static char *complete_from_files(const char *text, int state);
 
+static int find_last_index_of(char *w, char **previous_words, int len);
 static char *pg_strdup_keyword_case(const char *s, const char *ref);
 static char *escape_string(const char *text);
 static PGresult *exec_query(const char *query);
@@ -953,6 +963,7 @@ static char **get_previous_words(int point, char **buffer, int *nwords);
 
 static char *get_guctype(const char *varname);
 
+static const pgsql_thing_t *find_thing_entry(char *word);
 #ifdef NOT_USED
 static char *quote_file_name(char *text, int match_type, char *quote_pointer);
 static char *dequote_file_name(char *text, char quote_char);
@@ -1108,6 +1119,9 @@ psql_completion(const char *text, int start, int end)
 	/* The number of words found on the input line. */
 	int			previous_words_count;
 
+	/* The number of prefixing words to be ignored */
+	int			head_shift = 0;
+
 	/*
 	 * For compactness, we use these macros to reference previous_words[].
 	 * Caution: do not access a previous_words[] entry without having checked
@@ -1125,31 +1139,73 @@ psql_completion(const char *text, int start, int end)
 #define prev8_wd  (previous_words[7])
 #define prev9_wd  (previous_words[8])
 
+	/* Move the position of the beginning word for matching macros.  */
+#define HEADSHIFT(n) \
+	((head_shift += n) || true)
+
+	/* Return the number of stored words counting head shift */
+#define WORD_COUNT() (previous_words_count - head_shift)
+
+	/* Return the true index in previous_words for index from the beginning */
+#define HEAD_INDEX(n) \
+	(previous_words_count - head_shift - (n))
+
+	/*
+	 * remove n words from current shifted position, see MidMatchAndRevmove2
+	 * for the reason for the return value
+	 */
+#define COLLAPSE(n) \
+	((memmove(previous_words + HEAD_INDEX(n), previous_words + HEAD_INDEX(0), \
+			 sizeof(char *) * head_shift), \
+	 previous_words_count -= (n)) && false)
+
+	/*
+	 * Find the position the specified word occurs last and shift to there.
+	 * This is used to ignore the words before there.
+	 */
+#define SHIFT_TO_LAST1(p1) \
+	(HEADSHIFT(find_last_index_of(p1, previous_words, previous_words_count))|| \
+	 true)
+
+	/*
+	 * Remove the specified words if they match from the sth word in
+	 * previous_words. This is a bit tricky, COLLAPSE is skipped when
+	 * HeadMatches failed but the last HEADSHIFT anyway should be done.
+	 */
+#define MidMatchAndRemove1(s, p1) \
+	((HEADSHIFT(s) && HeadMatches1(p1) && COLLAPSE(1)) || HEADSHIFT(-s))
+
+#define MidMatchAndRemove2(s, p1, p2) \
+	((HEADSHIFT(s) && HeadMatches2(p1, p2) && COLLAPSE(2)) || HEADSHIFT(-s))
+
+#define MidMatchAndRemove3(s, p1, p2, p3)									\
+	((HEADSHIFT(s) && HeadMatches3(p1, p2, p3) && COLLAPSE(3)) || HEADSHIFT(-s))
+
 	/* Macros for matching the last N words before point, case-insensitively. */
 #define TailMatches1(p1) \
-	(previous_words_count >= 1 && \
+	(WORD_COUNT() >= 1 && \
 	 word_matches(p1, prev_wd))
 
 #define TailMatches2(p2, p1) \
-	(previous_words_count >= 2 && \
+	(WORD_COUNT() >= 2 && \
 	 word_matches(p1, prev_wd) && \
 	 word_matches(p2, prev2_wd))
 
 #define TailMatches3(p3, p2, p1) \
-	(previous_words_count >= 3 && \
+	(WORD_COUNT() >= 3 && \
 	 word_matches(p1, prev_wd) && \
 	 word_matches(p2, prev2_wd) && \
 	 word_matches(p3, prev3_wd))
 
 #define TailMatches4(p4, p3, p2, p1) \
-	(previous_words_count >= 4 && \
+	(WORD_COUNT() >= 4 && \
 	 word_matches(p1, prev_wd) && \
 	 word_matches(p2, prev2_wd) && \
 	 word_matches(p3, prev3_wd) && \
 	 word_matches(p4, prev4_wd))
 
 #define TailMatches5(p5, p4, p3, p2, p1) \
-	(previous_words_count >= 5 && \
+	(WORD_COUNT() >= 5 && \
 	 word_matches(p1, prev_wd) && \
 	 word_matches(p2, prev2_wd) && \
 	 word_matches(p3, prev3_wd) && \
@@ -1157,7 +1213,7 @@ psql_completion(const char *text, int start, int end)
 	 word_matches(p5, prev5_wd))
 
 #define TailMatches6(p6, p5, p4, p3, p2, p1) \
-	(previous_words_count >= 6 && \
+	(WORD_COUNT() >= 6 && \
 	 word_matches(p1, prev_wd) && \
 	 word_matches(p2, prev2_wd) && \
 	 word_matches(p3, prev3_wd) && \
@@ -1166,7 +1222,7 @@ psql_completion(const char *text, int start, int end)
 	 word_matches(p6, prev6_wd))
 
 #define TailMatches7(p7, p6, p5, p4, p3, p2, p1) \
-	(previous_words_count >= 7 && \
+	(WORD_COUNT() >= 7 && \
 	 word_matches(p1, prev_wd) && \
 	 word_matches(p2, prev2_wd) && \
 	 word_matches(p3, prev3_wd) && \
@@ -1176,7 +1232,7 @@ psql_completion(const char *text, int start, int end)
 	 word_matches(p7, prev7_wd))
 
 #define TailMatches8(p8, p7, p6, p5, p4, p3, p2, p1) \
-	(previous_words_count >= 8 && \
+	(WORD_COUNT() >= 8 && \
 	 word_matches(p1, prev_wd) && \
 	 word_matches(p2, prev2_wd) && \
 	 word_matches(p3, prev3_wd) && \
@@ -1187,7 +1243,7 @@ psql_completion(const char *text, int start, int end)
 	 word_matches(p8, prev8_wd))
 
 #define TailMatches9(p9, p8, p7, p6, p5, p4, p3, p2, p1) \
-	(previous_words_count >= 9 && \
+	(WORD_COUNT() >= 9 && \
 	 word_matches(p1, prev_wd) && \
 	 word_matches(p2, prev2_wd) && \
 	 word_matches(p3, prev3_wd) && \
@@ -1200,43 +1256,43 @@ psql_completion(const char *text, int start, int end)
 
 	/* Macros for matching the last N words before point, case-sensitively. */
 #define TailMatchesCS1(p1) \
-	(previous_words_count >= 1 && \
+	(WORD_COUNT() >= 1 && \
 	 word_matches_cs(p1, prev_wd))
 #define TailMatchesCS2(p2, p1) \
-	(previous_words_count >= 2 && \
+	(WORD_COUNT() >= 2 && \
 	 word_matches_cs(p1, prev_wd) && \
 	 word_matches_cs(p2, prev2_wd))
 
 	/*
-	 * Macros for matching N words beginning at the start of the line,
+	 * Macros for matching N words exactly to the line,
 	 * case-insensitively.
 	 */
 #define Matches1(p1) \
-	(previous_words_count == 1 && \
+	(WORD_COUNT() == 1 && \
 	 TailMatches1(p1))
 #define Matches2(p1, p2) \
-	(previous_words_count == 2 && \
+	(WORD_COUNT() == 2 && \
 	 TailMatches2(p1, p2))
 #define Matches3(p1, p2, p3) \
-	(previous_words_count == 3 && \
+	(WORD_COUNT() == 3 && \
 	 TailMatches3(p1, p2, p3))
 #define Matches4(p1, p2, p3, p4) \
-	(previous_words_count == 4 && \
+	(WORD_COUNT() == 4 && \
 	 TailMatches4(p1, p2, p3, p4))
 #define Matches5(p1, p2, p3, p4, p5) \
-	(previous_words_count == 5 && \
+	(WORD_COUNT() == 5 && \
 	 TailMatches5(p1, p2, p3, p4, p5))
 #define Matches6(p1, p2, p3, p4, p5, p6) \
-	(previous_words_count == 6 && \
+	(WORD_COUNT() == 6 && \
 	 TailMatches6(p1, p2, p3, p4, p5, p6))
 #define Matches7(p1, p2, p3, p4, p5, p6, p7) \
-	(previous_words_count == 7 && \
+	(WORD_COUNT() == 7 && \
 	 TailMatches7(p1, p2, p3, p4, p5, p6, p7))
 #define Matches8(p1, p2, p3, p4, p5, p6, p7, p8) \
-	(previous_words_count == 8 && \
+	(WORD_COUNT() == 8 && \
 	 TailMatches8(p1, p2, p3, p4, p5, p6, p7, p8))
 #define Matches9(p1, p2, p3, p4, p5, p6, p7, p8, p9) \
-	(previous_words_count == 9 && \
+	(WORD_COUNT() == 9 && \
 	 TailMatches9(p1, p2, p3, p4, p5, p6, p7, p8, p9))
 
 	/*
@@ -1244,19 +1300,53 @@ psql_completion(const char *text, int start, int end)
 	 * what is after them, case-insensitively.
 	 */
 #define HeadMatches1(p1) \
-	(previous_words_count >= 1 && \
-	 word_matches(p1, previous_words[previous_words_count - 1]))
+	(HEAD_INDEX(1) >=0 && \
+	 word_matches(p1, previous_words[HEAD_INDEX(1)]))
 
 #define HeadMatches2(p1, p2) \
-	(previous_words_count >= 2 && \
-	 word_matches(p1, previous_words[previous_words_count - 1]) && \
-	 word_matches(p2, previous_words[previous_words_count - 2]))
+	(HEAD_INDEX(2) >= 0 && \
+	 word_matches(p1, previous_words[HEAD_INDEX(1)]) &&	\
+	 word_matches(p2, previous_words[HEAD_INDEX(2)]))
 
 #define HeadMatches3(p1, p2, p3) \
-	(previous_words_count >= 3 && \
-	 word_matches(p1, previous_words[previous_words_count - 1]) && \
-	 word_matches(p2, previous_words[previous_words_count - 2]) && \
-	 word_matches(p3, previous_words[previous_words_count - 3]))
+	(HEAD_INDEX(3) >= 0 && \
+	 word_matches(p1, previous_words[HEAD_INDEX(1)]) && \
+	 word_matches(p2, previous_words[HEAD_INDEX(2)]) && \
+	 word_matches(p3, previous_words[HEAD_INDEX(3)]))
+
+#define HeadMatches4(p1, p2, p3, p4) \
+	(HEAD_INDEX(4) >= 0 && \
+	 word_matches(p1, previous_words[HEAD_INDEX(1)]) && \
+	 word_matches(p2, previous_words[HEAD_INDEX(2)]) && \
+	 word_matches(p3, previous_words[HEAD_INDEX(3)]) && \
+	 word_matches(p4, previous_words[HEAD_INDEX(4)]))
+
+#define HeadMatches5(p1, p2, p3, p4, p5) \
+	(HEAD_INDEX(5) >= 0 && \
+	 word_matches(p1, previous_words[HEAD_INDEX(1)]) && \
+	 word_matches(p2, previous_words[HEAD_INDEX(2)]) && \
+	 word_matches(p3, previous_words[HEAD_INDEX(3)]) && \
+	 word_matches(p4, previous_words[HEAD_INDEX(4)]) && \
+	 word_matches(p5, previous_words[HEAD_INDEX(5)]))
+
+#define HeadMatches6(p1, p2, p3, p4, p5, p6)		\
+	(HEAD_INDEX(6) >= 0 && \
+	 word_matches(p1, previous_words[HEAD_INDEX(1)]) && \
+	 word_matches(p2, previous_words[HEAD_INDEX(2)]) && \
+	 word_matches(p3, previous_words[HEAD_INDEX(3)]) && \
+	 word_matches(p4, previous_words[HEAD_INDEX(4)]) && \
+	 word_matches(p5, previous_words[HEAD_INDEX(5)]) && \
+	 word_matches(p6, previous_words[HEAD_INDEX(6)]))
+
+#define HeadMatches7(p1, p2, p3, p4, p5, p6, p7)	\
+	(HEAD_INDEX(7) >= 0 && \
+	 word_matches(p1, previous_words[HEAD_INDEX(1)]) && \
+	 word_matches(p2, previous_words[HEAD_INDEX(2)]) && \
+	 word_matches(p3, previous_words[HEAD_INDEX(3)]) && \
+	 word_matches(p4, previous_words[HEAD_INDEX(4)]) && \
+	 word_matches(p5, previous_words[HEAD_INDEX(5)]) && \
+	 word_matches(p6, previous_words[HEAD_INDEX(6)]) && \
+	 word_matches(p7, previous_words[HEAD_INDEX(7)]))
 
 	/* Known command-starting keywords. */
 	static const char *const sql_commands[] = {
@@ -1328,9 +1418,16 @@ psql_completion(const char *text, int start, int end)
 	else if (previous_words_count == 0)
 		COMPLETE_WITH_LIST(sql_commands);
 
+	/*
+	 * If this is in CREATE SCHEMA, seek to the last CREATE and regard it as
+	 * current command to complete.
+	 */
+	else if (HeadMatches2("CREATE", "SCHEMA") &&
+			 SHIFT_TO_LAST1("CREATE") &&
+			 false) {} /* FALL THROUGH */
 /* CREATE */
 	/* complete with something you can create */
-	else if (TailMatches1("CREATE"))
+	else if (Matches1("CREATE"))
 		matches = completion_matches(text, create_command_generator);
 
 /* DROP, but not DROP embedded in other commands */
@@ -1343,7 +1440,13 @@ psql_completion(const char *text, int start, int end)
 	/* ALTER TABLE */
 	else if (Matches2("ALTER", "TABLE"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
+								   "UNION SELECT 'IF EXISTS'"
 								   "UNION SELECT 'ALL IN TABLESPACE'");
+	/* ALTER TABLE after removing optional words IF EXISTS*/
+	else if (HeadMatches2("ALTER", "TABLE") &&
+			 MidMatchAndRemove2(2, "IF", "EXISTS") &&
+			 Matches2("ALTER", "TABLE"))
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
 
 	/* ALTER something */
 	else if (Matches1("ALTER"))
@@ -1421,6 +1524,17 @@ psql_completion(const char *text, int start, int end)
 	else if (Matches5("ALTER", "FOREIGN", "DATA", "WRAPPER", MatchAny))
 		COMPLETE_WITH_LIST5("HANDLER", "VALIDATOR", "OPTIONS", "OWNER TO", "RENAME TO");
 
+	/* ALTER FOREIGN TABLE */
+	else if (Matches3("ALTER|DROP", "FOREIGN", "TABLE"))
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_foreign_tables,
+								   " UNION SELECT 'IF EXISTS'");
+
+	/* ALTER|DROP FOREIGN TABLE after removing optinal words IF EXISTS */
+	else if (HeadMatches3("ALTER|DROP", "FOREIGN", "TABLE") &&
+			 MidMatchAndRemove2(3, "IF", "EXISTS") &&
+			 Matches3("ALTER|DROP", "FOREIGN", "TABLE"))
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_foreign_tables, NULL);
+
 	/* ALTER FOREIGN TABLE <name> */
 	else if (Matches4("ALTER", "FOREIGN", "TABLE", MatchAny))
 	{
@@ -1432,10 +1546,21 @@ psql_completion(const char *text, int start, int end)
 		COMPLETE_WITH_LIST(list_ALTER_FOREIGN_TABLE);
 	}
 
+	/* ALTER FOREIGN TABLE xxx RENAME */
+	else if (Matches5("ALTER", "FOREIGN", "TABLE", MatchAny, "RENAME"))
+		COMPLETE_WITH_ATTR(prev2_wd, " UNION SELECT 'COLUMN' UNION SELECT 'TO'");
+
 	/* ALTER INDEX */
 	else if (Matches2("ALTER", "INDEX"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes,
+								   "UNION SELECT 'IF EXISTS'"
 								   "UNION SELECT 'ALL IN TABLESPACE'");
+	/* ALTER INDEX after removing optional words IF EXISTS */
+	else if (HeadMatches2("ALTER", "INDEX") &&
+			 MidMatchAndRemove2(2, "IF", "EXISTS") &&
+			 Matches2("ALTER", "INDEX"))
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
+
 	/* ALTER INDEX <name> */
 	else if (Matches3("ALTER", "INDEX", MatchAny))
 		COMPLETE_WITH_LIST4("OWNER TO", "RENAME TO", "SET", "RESET");
@@ -1464,8 +1589,15 @@ psql_completion(const char *text, int start, int end)
 	/* ALTER MATERIALIZED VIEW */
 	else if (Matches3("ALTER", "MATERIALIZED", "VIEW"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews,
+								   "UNION SELECT 'IF EXISTS'"
 								   "UNION SELECT 'ALL IN TABLESPACE'");
 
+	/* ALTER MATERIALIZED VIEW with name after removing optional words */
+	else if (HeadMatches3("ALTER", "MATERIALIZED", "VIEW") &&
+			 MidMatchAndRemove2(3, "IF", "EXISTS") &&
+			 Matches3("ALTER", "MATERIALIZED", "VIEW"))
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, NULL);
+
 	/* ALTER USER,ROLE <name> */
 	else if (Matches3("ALTER", "USER|ROLE", MatchAny) &&
 			 !TailMatches2("USER", "MAPPING"))
@@ -1516,8 +1648,23 @@ psql_completion(const char *text, int start, int end)
 	/* ALTER DOMAIN <sth> DROP */
 	else if (Matches4("ALTER", "DOMAIN", MatchAny, "DROP"))
 		COMPLETE_WITH_LIST3("CONSTRAINT", "DEFAULT", "NOT NULL");
-	/* ALTER DOMAIN <sth> DROP|RENAME|VALIDATE CONSTRAINT */
-	else if (Matches5("ALTER", "DOMAIN", MatchAny, "DROP|RENAME|VALIDATE", "CONSTRAINT"))
+	/* ALTER DOMAIN <sth> RENAME|VALIDATE CONSTRAINT */
+	else if (Matches5("ALTER", "DOMAIN", MatchAny, "RENAME|VALIDATE", "CONSTRAINT"))
+	{
+		completion_info_charp = prev3_wd;
+		COMPLETE_WITH_QUERY(Query_for_constraint_of_type);
+	}
+	/* ALTER DOMAIN <sth> DROP CONSTRAINT */
+	else if (Matches5("ALTER", "DOMAIN", MatchAny, "DROP", "CONSTRAINT"))
+	{
+		completion_info_charp = prev3_wd;
+		COMPLETE_WITH_QUERY(Query_for_constraint_of_type
+							"UNION SELECT 'IF EXISTS'");
+	}
+	/* Try the same match after removing optional words IF EXISTS */
+	else if (HeadMatches5("ALTER", "DOMAIN", MatchAny, "DROP", "CONSTRAINT") &&
+			 MidMatchAndRemove2(5, "IF", "EXISTS") &&
+			 Matches5("ALTER", "DOMAIN", MatchAny, "DROP", "CONSTRAINT"))
 	{
 		completion_info_charp = prev3_wd;
 		COMPLETE_WITH_QUERY(Query_for_constraint_of_type);
@@ -1532,8 +1679,13 @@ psql_completion(const char *text, int start, int end)
 	/* ALTER DOMAIN <sth> SET */
 	else if (Matches4("ALTER", "DOMAIN", MatchAny, "SET"))
 		COMPLETE_WITH_LIST3("DEFAULT", "NOT NULL", "SCHEMA");
-	/* ALTER SEQUENCE <name> */
-	else if (Matches3("ALTER", "SEQUENCE", MatchAny))
+	else if (Matches2("ALTER", "SEQUENCE"))
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences,
+								   " UNION SELECT 'IF EXISTS'");
+	/* ALTER SEQUENCE with name after removing optional words IF EXISTS */
+	else if (HeadMatches2("ALTER", "SEQUENCE") &&
+			 MidMatchAndRemove2(2, "IF", "EXISTS") &&
+			 Matches3("ALTER", "SEQUENCE", MatchAny))
 	{
 		static const char *const list_ALTERSEQUENCE[] =
 		{"INCREMENT", "MINVALUE", "MAXVALUE", "RESTART", "NO", "CACHE", "CYCLE",
@@ -1556,8 +1708,14 @@ psql_completion(const char *text, int start, int end)
 	/* ALTER SYSTEM SET|RESET <name> */
 	else if (Matches3("ALTER", "SYSTEM", "SET|RESET"))
 		COMPLETE_WITH_QUERY(Query_for_list_of_alter_system_set_vars);
-	/* ALTER VIEW <name> */
-	else if (Matches3("ALTER", "VIEW", MatchAny))
+	/* ALTER VIEW */
+	else if (Matches2("ALTER", "VIEW"))
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views,
+								   "UNION SELECT 'IF EXISTS'");
+	/* ALTER VIEW <name> with subcommands after removing optional worlds */
+	else if (HeadMatches2("ALTER", "VIEW") &&
+			 MidMatchAndRemove2(2, "IF", "EXISTS") &&
+			 Matches3("ALTER", "VIEW", MatchAny))
 		COMPLETE_WITH_LIST4("ALTER COLUMN", "OWNER TO", "RENAME TO",
 							"SET SCHEMA");
 	/* ALTER MATERIALIZED VIEW <name> */
@@ -1565,11 +1723,14 @@ psql_completion(const char *text, int start, int end)
 		COMPLETE_WITH_LIST4("ALTER COLUMN", "OWNER TO", "RENAME TO",
 							"SET SCHEMA");
 
-	/* ALTER POLICY <name> */
+	/* ALTER POLICY */
 	else if (Matches2("ALTER", "POLICY"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_policies);
-	/* ALTER POLICY <name> ON */
-	else if (Matches3("ALTER", "POLICY", MatchAny))
+		COMPLETE_WITH_QUERY(Query_for_list_of_policies
+							"UNION SELECT 'IF EXISTS'");
+	/* ALTER POLICY <name> with ON after removing optional words IF EXISTS */
+	else if (HeadMatches2("ALTER", "POLICY") &&
+			 MidMatchAndRemove2(2, "IF", "EXISTS") &&
+			 Matches3("ALTER", "POLICY", MatchAny))
 		COMPLETE_WITH_CONST("ON");
 	/* ALTER POLICY <name> ON <table> */
 	else if (Matches4("ALTER", "POLICY", MatchAny, "ON"))
@@ -1693,8 +1854,10 @@ psql_completion(const char *text, int start, int end)
 	else if (Matches5("ALTER", "TABLE", MatchAny, "ALTER|RENAME", "COLUMN"))
 		COMPLETE_WITH_ATTR(prev3_wd, "");
 
-	/* ALTER TABLE xxx RENAME yyy */
-	else if (Matches5("ALTER", "TABLE", MatchAny, "RENAME", MatchAnyExcept("CONSTRAINT|TO")))
+	/* ALTER [FOREIGN] TABLE xxx RENAME yyy */
+	else if ((HeadMatches2("ALTER", "TABLE") ||
+			  HeadMatches3("ALTER", "FOREIGN", "TABLE")) &&
+			 TailMatches2("RENAME", MatchAnyExcept("CONSTRAINT|TO")))
 		COMPLETE_WITH_CONST("TO");
 
 	/* ALTER TABLE xxx RENAME COLUMN/CONSTRAINT yyy */
@@ -1704,15 +1867,47 @@ psql_completion(const char *text, int start, int end)
 	/* If we have ALTER TABLE <sth> DROP, provide COLUMN or CONSTRAINT */
 	else if (Matches4("ALTER", "TABLE", MatchAny, "DROP"))
 		COMPLETE_WITH_LIST2("COLUMN", "CONSTRAINT");
+	/*  ALTER TABLE DROP COLUMN may take IF EXISTS */
+	else if (Matches5("ALTER", "TABLE", MatchAny, "DROP", "COLUMN"))
+		COMPLETE_WITH_ATTR(prev3_wd, "UNION SELECT 'IF EXISTS'");
+	/* ALTER TABLE <name> with ADD/ALTER/DROP after removing optional words */
+	else if (HeadMatches4("ALTER", "TABLE", MatchAny, "ADD|ALTER|DROP") &&
+			 MidMatchAndRemove1(4, "COLUMN") &&
+			 MidMatchAndRemove2(4, "IF", "EXISTS") &&
+			 Matches4("ALTER", "TABLE", MatchAny, "ADD|ALTER|DROP"))
+		COMPLETE_WITH_ATTR(prev2_wd, "");
 	/* If we have ALTER TABLE <sth> DROP COLUMN, provide list of columns */
 	else if (Matches5("ALTER", "TABLE", MatchAny, "DROP", "COLUMN"))
+		COMPLETE_WITH_ATTR(prev3_wd, "UNION SELECT 'IF EXISTS'");
+	/* Try the same after removing optional words IF EXISTS */
+	else if (HeadMatches5("ALTER", "TABLE", MatchAny, "DROP", "COLUMN") &&
+			 MidMatchAndRemove2(5, "IF", "EXISTS") &&
+			 Matches5("ALTER", "TABLE", MatchAny, "DROP", "COLUMN"))
 		COMPLETE_WITH_ATTR(prev3_wd, "");
 
 	/*
-	 * If we have ALTER TABLE <sth> ALTER|DROP|RENAME|VALIDATE CONSTRAINT,
+	 * If we have ALTER TABLE <sth> ALTER|RENAME|VALIDATE CONSTRAINT,
+	 * provide list of constraints
+	 */
+	else if (Matches5("ALTER", "TABLE", MatchAny, "ALTER|RENAME|VALIDATE", "CONSTRAINT"))
+	{
+		completion_info_charp = prev3_wd;
+		COMPLETE_WITH_QUERY(Query_for_constraint_of_table);
+	}
+	/*
+	 * If we have ALTER TABLE <sth> DROP CONSTRAINT,
 	 * provide list of constraints
 	 */
-	else if (Matches5("ALTER", "TABLE", MatchAny, "ALTER|DROP|RENAME|VALIDATE", "CONSTRAINT"))
+	else if (Matches5("ALTER", "TABLE", MatchAny, "DROP", "CONSTRAINT"))
+	{
+		completion_info_charp = prev3_wd;
+		COMPLETE_WITH_QUERY(Query_for_constraint_of_table
+							"UNION SELECT 'IF EXISTS'");
+	}
+	/* Try the same after removing optional words IF EXISTS */
+	else if (HeadMatches5("ALTER", "TABLE", MatchAny, "DROP", "CONSTRAINT") &&
+			 MidMatchAndRemove2(5, "IF", "EXISTS") &&
+			 Matches5("ALTER", "TABLE", MatchAny, "DROP", "CONSTRAINT"))
 	{
 		completion_info_charp = prev3_wd;
 		COMPLETE_WITH_QUERY(Query_for_constraint_of_table);
@@ -1834,8 +2029,13 @@ psql_completion(const char *text, int start, int end)
 		COMPLETE_WITH_LIST3("OWNER TO", "RENAME TO", "SET SCHEMA");
 	else if (Matches5("ALTER", "TEXT", "SEARCH", "CONFIGURATION", MatchAny))
 		COMPLETE_WITH_LIST6("ADD MAPPING FOR", "ALTER MAPPING",
-							"DROP MAPPING FOR",
-							"OWNER TO", "RENAME TO", "SET SCHEMA");
+							"DROP MAPPING",	"OWNER TO", "RENAME TO", "SET SCHEMA");
+	else if (Matches7("ALTER", "TEXT", "SEARCH", "CONFIGURATION", MatchAny, "DROP", "MAPPING"))
+		COMPLETE_WITH_LIST2("FOR", "IF EXISTS FOR");
+	/* Remove optional words IF EXISTS */
+	else if (HeadMatches7("ALTER", "TEXT", "SEARCH", "CONFIGURATION", MatchAny, "DROP", "MAPPING") &&
+			 MidMatchAndRemove2(7, "IF", "EXISTS") &&
+			 false) {} /* Nothing to do for now */
 
 	/* complete ALTER TYPE <foo> with actions */
 	else if (Matches3("ALTER", "TYPE", MatchAny))
@@ -1845,6 +2045,12 @@ psql_completion(const char *text, int start, int end)
 	/* complete ALTER TYPE <foo> ADD with actions */
 	else if (Matches4("ALTER", "TYPE", MatchAny, "ADD"))
 		COMPLETE_WITH_LIST2("ATTRIBUTE", "VALUE");
+	else if (Matches5("ALTER", "TYPE", MatchAny, "ADD", "VALUE"))
+		COMPLETE_WITH_LIST2("IF NOT EXISTS", "");
+	/* Remove optional words IF NOT EXISTS */
+	else if (HeadMatches5("ALTER", "TYPE", MatchAny, "ADD", "VALUE") &&
+			 MidMatchAndRemove3(5, "IF", "NOT", "EXISTS") &&
+			 false) {} /* Nothing to do for now */
 	/* ALTER TYPE <foo> RENAME	*/
 	else if (Matches4("ALTER", "TYPE", MatchAny, "RENAME"))
 		COMPLETE_WITH_LIST2("ATTRIBUTE", "TO");
@@ -1856,10 +2062,15 @@ psql_completion(const char *text, int start, int end)
 	 * If we have ALTER TYPE <sth> ALTER/DROP/RENAME ATTRIBUTE, provide list
 	 * of attributes
 	 */
-	else if (Matches5("ALTER", "TYPE", MatchAny, "ALTER|DROP|RENAME", "ATTRIBUTE"))
+	else if (Matches5("ALTER", "TYPE", MatchAny, "ALTER|RENAME", "ATTRIBUTE"))
 		COMPLETE_WITH_ATTR(prev3_wd, "");
+	else if (Matches5("ALTER", "TYPE", MatchAny, "DROP", "ATTRIBUTE"))
+		COMPLETE_WITH_ATTR(prev3_wd, " UNION SELECT 'IF EXISTS'");
+	/* Remove optional words IF EXISTS */
+	else if (HeadMatches5("ALTER", "TYPE", MatchAny, "DROP", "ATTRIBUTE") &&
+			 MidMatchAndRemove2(5, "IF", "EXISTS") &&
 	/* ALTER TYPE ALTER ATTRIBUTE <foo> */
-	else if (Matches6("ALTER", "TYPE", MatchAny, "ALTER", "ATTRIBUTE", MatchAny))
+			 Matches6("ALTER", "TYPE", MatchAny, "ALTER", "ATTRIBUTE", MatchAny))
 		COMPLETE_WITH_CONST("TYPE");
 	/* complete ALTER GROUP <foo> */
 	else if (Matches3("ALTER", "GROUP", MatchAny))
@@ -2002,6 +2213,12 @@ psql_completion(const char *text, int start, int end)
 	/* CREATE EXTENSION */
 	/* Complete with available extensions rather than installed ones. */
 	else if (Matches2("CREATE", "EXTENSION"))
+		COMPLETE_WITH_QUERY(Query_for_list_of_available_extensions
+							" UNION SELECT 'IF NOT EXISTS'");
+	/* Try the same after removing optional words IF NOT EXISTS */
+	else if (HeadMatches2("CREATE", "EXTENSION") &&
+			 MidMatchAndRemove3(2, "IF", "NOT", "EXISTS") &&
+			 Matches2("CREATE", "EXTENSION"))
 		COMPLETE_WITH_QUERY(Query_for_list_of_available_extensions);
 	/* CREATE EXTENSION <name> */
 	else if (Matches3("CREATE", "EXTENSION", MatchAny))
@@ -2017,6 +2234,14 @@ psql_completion(const char *text, int start, int end)
 	else if (Matches2("CREATE", "FOREIGN"))
 		COMPLETE_WITH_LIST2("DATA WRAPPER", "TABLE");
 
+	/* CREATE FOREIGN TABLE */
+	else if (Matches3("CREATE", "FOREIGN", "TABLE"))
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_foreign_tables,
+								   " UNION SELECT 'IF NOT EXISTS'");
+	/* Remove optional words IF NOT EXISTS */
+	else if (HeadMatches3("CREATE", "FOREIGN", "TABLE") &&
+			 MidMatchAndRemove3(3, "IF", "NOT", "EXISTS") &&
+			 false) {} /* FALL THROUGH */
 	/* CREATE FOREIGN DATA WRAPPER */
 	else if (Matches5("CREATE", "FOREIGN", "DATA", "WRAPPER", MatchAny))
 		COMPLETE_WITH_LIST3("HANDLER", "VALIDATOR", "OPTIONS");
@@ -2025,23 +2250,37 @@ psql_completion(const char *text, int start, int end)
 	/* First off we complete CREATE UNIQUE with "INDEX" */
 	else if (TailMatches2("CREATE", "UNIQUE"))
 		COMPLETE_WITH_CONST("INDEX");
-	/* If we have CREATE|UNIQUE INDEX, then add "ON", "CONCURRENTLY",
+
+	/* Remove optional word UNIQUE from CREATE UNIQUE INDEX */
+	/* If we have CREATE INDEX, then add "ON", "CONCURRENTLY" or IF NOT EXISTS,
 	   and existing indexes */
-	else if (TailMatches2("CREATE|UNIQUE", "INDEX"))
+	else if (HeadMatches3("CREATE", MatchAny, "INDEX") &&
+			 MidMatchAndRemove1(1, "UNIQUE") &&
+			 Matches2("CREATE", "INDEX"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes,
 								   " UNION SELECT 'ON'"
-								   " UNION SELECT 'CONCURRENTLY'");
-	/* Complete ... INDEX|CONCURRENTLY [<name>] ON with a list of tables  */
-	else if (TailMatches3("INDEX|CONCURRENTLY", MatchAny, "ON") ||
-			 TailMatches2("INDEX|CONCURRENTLY", "ON"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, NULL);
-	/* Complete CREATE|UNIQUE INDEX CONCURRENTLY with "ON" and existing indexes */
-	else if (TailMatches3("CREATE|UNIQUE", "INDEX", "CONCURRENTLY"))
+								   " UNION SELECT 'CONCURRENTLY'"
+								   " UNION SELECT 'IF NOT EXISTS'");
+	/* Complete CREATE INDEX CONCURRENTLY with "ON" or IF NOT EXISTS and
+	 * existing indexes */
+	else if (Matches3("CREATE", "INDEX", "CONCURRENTLY"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes,
+								   " UNION SELECT 'IF NOT EXISTS'"
 								   " UNION SELECT 'ON'");
-	/* Complete CREATE|UNIQUE INDEX [CONCURRENTLY] <sth> with "ON" */
-	else if (TailMatches3("CREATE|UNIQUE", "INDEX", MatchAny) ||
-			 TailMatches4("CREATE|UNIQUE", "INDEX", "CONCURRENTLY", MatchAny))
+
+	/* Remove optional words "CONCURRENTLY",  "IF NOT EXISTS" */
+	else if (HeadMatches2("CREATE", "INDEX") &&
+			 MidMatchAndRemove1(2, "CONCURRENTLY") &&
+			 MidMatchAndRemove3(2, "IF", "NOT", "EXISTS") &&
+			 false) {} /* FALL THROUGH */
+
+	/* Complete CREATE INDEX [<name>] ON with a list of tables */
+	else if (Matches4("CREATE", "INDEX", MatchAny, "ON") ||
+			 Matches3("CREATE", "INDEX", "ON"))
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, NULL);
+
+	/* Complete CREATE INDEX <sth> with "ON" */
+	else if (Matches3("CREATE", "INDEX", MatchAny))
 		COMPLETE_WITH_CONST("ON");
 
 	/*
@@ -2049,17 +2288,16 @@ psql_completion(const char *text, int start, int end)
 	 * should really be in parens)
 	 */
 	else if (TailMatches4("INDEX", MatchAny, "ON", MatchAny) ||
-			 TailMatches3("INDEX|CONCURRENTLY", "ON", MatchAny))
+			 TailMatches3("INDEX", "ON", MatchAny))
 		COMPLETE_WITH_LIST2("(", "USING");
-	else if (TailMatches5("INDEX", MatchAny, "ON", MatchAny, "(") ||
-			 TailMatches4("INDEX|CONCURRENTLY", "ON", MatchAny, "("))
+	else if (Matches5("INDEX", MatchAny, "ON", MatchAny, "(") ||
+			 Matches4("INDEX", "ON", MatchAny, "("))
 		COMPLETE_WITH_ATTR(prev2_wd, "");
 	/* same if you put in USING */
 	else if (TailMatches5("ON", MatchAny, "USING", MatchAny, "("))
 		COMPLETE_WITH_ATTR(prev4_wd, "");
 	/* Complete USING with an index method */
-	else if (TailMatches6("INDEX", MatchAny, MatchAny, "ON", MatchAny, "USING") ||
-			 TailMatches5("INDEX", MatchAny, "ON", MatchAny, "USING") ||
+	else if (TailMatches5("INDEX", MatchAny, "ON", MatchAny, "USING") ||
 			 TailMatches4("INDEX", "ON", MatchAny, "USING"))
 		COMPLETE_WITH_QUERY(Query_for_list_of_access_methods);
 	else if (TailMatches4("ON", MatchAny, "USING", MatchAny) &&
@@ -2113,27 +2351,52 @@ psql_completion(const char *text, int start, int end)
 	else if (TailMatches4("AS", "ON", "SELECT|UPDATE|INSERT|DELETE", "TO"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
 
-/* CREATE SEQUENCE --- is allowed inside CREATE SCHEMA, so use TailMatches */
-	else if (TailMatches3("CREATE", "SEQUENCE", MatchAny) ||
-			 TailMatches4("CREATE", "TEMP|TEMPORARY", "SEQUENCE", MatchAny))
+/* CREATE SEQUENCE, removing optional words TEMPORARY/TEMP */
+	else if (HeadMatches3("CREATE", MatchAny, "SEQUENCE") &&
+			 MidMatchAndRemove1(1, "TEMP|TEMPORARY") &&
+			 Matches2("CREATE", "SEQUENCE"))
+		COMPLETE_WITH_LIST2("IF NOT EXISTS", "");
+	else if(HeadMatches2("CREATE", "SEQUENCE") &&
+			MidMatchAndRemove3(2, "IF", "NOT", "EXISTS") &&
+			Matches3("CREATE", "SEQUENCE", MatchAny))
 		COMPLETE_WITH_LIST8("INCREMENT BY", "MINVALUE", "MAXVALUE", "NO", "CACHE",
 							"CYCLE", "OWNED BY", "START WITH");
-	else if (TailMatches4("CREATE", "SEQUENCE", MatchAny, "NO") ||
-		TailMatches5("CREATE", "TEMP|TEMPORARY", "SEQUENCE", MatchAny, "NO"))
+	else if (Matches4("CREATE", "SEQUENCE", MatchAny, "NO"))
 		COMPLETE_WITH_LIST3("MINVALUE", "MAXVALUE", "CYCLE");
 
 /* CREATE SERVER <name> */
 	else if (Matches3("CREATE", "SERVER", MatchAny))
 		COMPLETE_WITH_LIST3("TYPE", "VERSION", "FOREIGN DATA WRAPPER");
 
-/* CREATE TABLE --- is allowed inside CREATE SCHEMA, so use TailMatches */
+/* CREATE SCHEMA <name> */
+	else if (Matches2("CREATE", "SCHEMA"))
+		COMPLETE_WITH_QUERY(Query_for_list_of_schemas
+							" UNION SELECT 'IF NOT EXISTS'");
+	/* Remove optional words IF NOT EXISTS */
+	else if (HeadMatches2("CREATE", "SCHEMA") &&
+			 MidMatchAndRemove3(2, "IF", "NOT", "EXISTS") &&
+			 false) {} /* FALL THROUGH*/
+
+/* CREATE TABLE  */
 	/* Complete "CREATE TEMP/TEMPORARY" with the possible temp objects */
-	else if (TailMatches2("CREATE", "TEMP|TEMPORARY"))
+	else if (Matches2("CREATE", "TEMP|TEMPORARY"))
 		COMPLETE_WITH_LIST3("SEQUENCE", "TABLE", "VIEW");
 	/* Complete "CREATE UNLOGGED" with TABLE or MATVIEW */
-	else if (TailMatches2("CREATE", "UNLOGGED"))
+	else if (Matches2("CREATE", "UNLOGGED"))
 		COMPLETE_WITH_LIST2("TABLE", "MATERIALIZED VIEW");
 
+	/* CREATE TABLE with name after removing optional words */
+	else if (HeadMatches3("CREATE", MatchAny, "TABLE") &&
+			 MidMatchAndRemove1(1, "TEMP|TEMPORARY|UNLOGGED") &&
+			 Matches2("CREATE", "TABLE"))
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
+								   " UNION SELECT 'IF NOT EXISTS'");
+
+	/* Remove optional words here */
+	else if (HeadMatches2("CREATE", "TABLE") &&
+			 MidMatchAndRemove3(2, "IF", "NOT", "EXISTS") &&
+			 false) {} /* FALL THROUGH */
+
 /* CREATE TABLESPACE */
 	else if (Matches3("CREATE", "TABLESPACE", MatchAny))
 		COMPLETE_WITH_LIST2("OWNER", "LOCATION");
@@ -2147,18 +2410,18 @@ psql_completion(const char *text, int start, int end)
 	else if (Matches5("CREATE", "TEXT", "SEARCH", "CONFIGURATION", MatchAny))
 		COMPLETE_WITH_CONST("(");
 
-/* CREATE TRIGGER --- is allowed inside CREATE SCHEMA, so use TailMatches */
+/* CREATE TRIGGER */
 	/* complete CREATE TRIGGER <name> with BEFORE,AFTER,INSTEAD OF */
-	else if (TailMatches3("CREATE", "TRIGGER", MatchAny))
+	else if (Matches3("CREATE", "TRIGGER", MatchAny))
 		COMPLETE_WITH_LIST3("BEFORE", "AFTER", "INSTEAD OF");
 	/* complete CREATE TRIGGER <name> BEFORE,AFTER with an event */
-	else if (TailMatches4("CREATE", "TRIGGER", MatchAny, "BEFORE|AFTER"))
+	else if (Matches4("CREATE", "TRIGGER", MatchAny, "BEFORE|AFTER"))
 		COMPLETE_WITH_LIST4("INSERT", "DELETE", "UPDATE", "TRUNCATE");
 	/* complete CREATE TRIGGER <name> INSTEAD OF with an event */
-	else if (TailMatches5("CREATE", "TRIGGER", MatchAny, "INSTEAD", "OF"))
+	else if (Matches5("CREATE", "TRIGGER", MatchAny, "INSTEAD", "OF"))
 		COMPLETE_WITH_LIST3("INSERT", "DELETE", "UPDATE");
 	/* complete CREATE TRIGGER <name> BEFORE,AFTER sth with OR,ON */
-	else if (TailMatches5("CREATE", "TRIGGER", MatchAny, "BEFORE|AFTER", MatchAny) ||
+	else if (Matches5("CREATE", "TRIGGER", MatchAny, "BEFORE|AFTER", MatchAny) ||
 	  TailMatches6("CREATE", "TRIGGER", MatchAny, "INSTEAD", "OF", MatchAny))
 		COMPLETE_WITH_LIST2("ON", "OR");
 
@@ -2215,9 +2478,14 @@ psql_completion(const char *text, int start, int end)
 	else if (Matches4("CREATE", "ROLE|USER|GROUP", MatchAny, "IN"))
 		COMPLETE_WITH_LIST2("GROUP", "ROLE");
 
-/* CREATE VIEW --- is allowed inside CREATE SCHEMA, so use TailMatches */
-	/* Complete CREATE VIEW <name> with AS */
-	else if (TailMatches3("CREATE", "VIEW", MatchAny))
+/* CREATE VIEW  */
+	else if (Matches2("CREATE", "VIEW"))
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views,
+								   " UNION SELECT 'IF NOT EXISTS'");
+	/* CREATE VIEW <name> with AS after removing optional words */
+	else if (HeadMatches2("CREATE", "VIEW") &&
+			 MidMatchAndRemove3(2, "IF", "NOT", "EXISTS") &&
+			 Matches3("CREATE", "VIEW", MatchAny))
 		COMPLETE_WITH_CONST("AS");
 	/* Complete "CREATE VIEW <sth> AS with "SELECT" */
 	else if (TailMatches4("CREATE", "VIEW", MatchAny, "AS"))
@@ -2226,6 +2494,15 @@ psql_completion(const char *text, int start, int end)
 /* CREATE MATERIALIZED VIEW */
 	else if (Matches2("CREATE", "MATERIALIZED"))
 		COMPLETE_WITH_CONST("VIEW");
+	else if (Matches3("CREATE", "MATERIALIZED", "VIEW"))
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews,
+								   " UNION SELECT 'IF NOT EXISTS'");
+	/* Try the same after removing optional words IF NOT EXISTS. VIEW will be
+	 * completed afterwards */
+	else if (HeadMatches3("CREATE", "MATERIALIZED", "VIEW") &&
+			 MidMatchAndRemove3(3, "IF", "NOT", "EXISTS") &&
+			 Matches3("CREATE", "MATERIALIZED", "VIEW"))
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, NULL);
 	/* Complete CREATE MATERIALIZED VIEW <name> with AS */
 	else if (Matches4("CREATE", "MATERIALIZED", "VIEW", MatchAny))
 		COMPLETE_WITH_CONST("AS");
@@ -2285,28 +2562,61 @@ psql_completion(const char *text, int start, int end)
 		COMPLETE_WITH_LIST2("CASCADE", "RESTRICT");
 
 	/* help completing some of the variants */
-	else if (Matches3("DROP", "AGGREGATE|FUNCTION", MatchAny))
+	else if (Matches2("DROP", "AGGREGATE"))
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_aggregates,
+								   " UNION SELECT 'IF EXISTS'");
+	else if (Matches2("DROP", "FUNCTION"))
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions,
+								   " UNION SELECT 'IF EXISTS'");
+	/* Try the same after removing optional words IF EXISTS */
+	else if (HeadMatches2("DROP", "AGGREGATE|FUNCTION") &&
+			 MidMatchAndRemove2(2, "IF", "EXISTS") &&
+			 Matches3("DROP", "AGGREGATE|FUNCTION", MatchAny))
 		COMPLETE_WITH_CONST("(");
 	else if (Matches4("DROP", "AGGREGATE|FUNCTION", MatchAny, "("))
 		COMPLETE_WITH_FUNCTION_ARG(prev2_wd);
 	else if (Matches2("DROP", "FOREIGN"))
 		COMPLETE_WITH_LIST2("DATA WRAPPER", "TABLE");
+	else if (Matches4("DROP", "FOREIGN", "DATA", "WRAPPER"))
+		COMPLETE_WITH_QUERY(Query_for_list_of_fdws
+							" UNION SELECT 'IF EXISTS'");
+	/* Try the same after removing optional words IF EXISTS */
+	else if (HeadMatches4("DROP", "FOREIGN", "DATA", "WRAPPER") &&
+			 MidMatchAndRemove2(4, "IF", "EXISTS") &&
+			 false) {} /* FALL THROUGH */
 
 	/* DROP INDEX */
 	else if (Matches2("DROP", "INDEX"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes,
+								   " UNION SELECT 'IF EXISTS'"
 								   " UNION SELECT 'CONCURRENTLY'");
 	else if (Matches3("DROP", "INDEX", "CONCURRENTLY"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
-	else if (Matches3("DROP", "INDEX", MatchAny))
-		COMPLETE_WITH_LIST2("CASCADE", "RESTRICT");
-	else if (Matches4("DROP", "INDEX", "CONCURRENTLY", MatchAny))
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes,
+								   " UNION SELECT 'IF EXISTS'");
+	/* Try the same after optional words CONCURRENTLY and IF NOT EXISTS */
+	else if (HeadMatches2("DROP", "INDEX") &&
+			 MidMatchAndRemove1(2, "CONCURRENTLY") &&
+			 MidMatchAndRemove2(2, "IF", "EXISTS") &&
+			 Matches3("DROP", "INDEX", MatchAny))
 		COMPLETE_WITH_LIST2("CASCADE", "RESTRICT");
 
 	/* DROP MATERIALIZED VIEW */
 	else if (Matches2("DROP", "MATERIALIZED"))
 		COMPLETE_WITH_CONST("VIEW");
+	else if (Matches2("DROP", "VIEW"))
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views,
+								   " UNION SELECT 'IF EXISTS'");
+	/* Remove optional words IF EXISTS  */
+	else if (HeadMatches2("DROP", "VIEW") &&
+			 MidMatchAndRemove2(2, "IF", "EXISTS") &&
+			 false) {} /* FALL THROUGH */
 	else if (Matches3("DROP", "MATERIALIZED", "VIEW"))
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews,
+								   " UNION SELECT 'IF EXISTS'");
+	/* Try the same after removing optional words IF EXISTS */
+	else if (HeadMatches3("DROP", "MATERIALIZED", "VIEW") &&
+			 MidMatchAndRemove2(3, "IF", "EXISTS") &&
+			 Matches3("DROP", "MATERIALIZED", "VIEW"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, NULL);
 
 	/* DROP OWNED BY */
@@ -2319,7 +2629,13 @@ psql_completion(const char *text, int start, int end)
 		COMPLETE_WITH_LIST4("CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE");
 
 	/* DROP TRIGGER */
-	else if (Matches3("DROP", "TRIGGER", MatchAny))
+	else if (Matches2("DROP", "TRIGGER"))
+		COMPLETE_WITH_QUERY(Query_for_list_of_triggers
+							" UNION SELECT 'IF EXISTS'");
+	/* Try the same after removing optional words IF EXISTS */
+	else if (HeadMatches2("DROP", "TRIGGER") &&
+			 MidMatchAndRemove2(2, "IF", "EXISTS") &&
+			 Matches3("DROP", "TRIGGER", MatchAny))
 		COMPLETE_WITH_CONST("ON");
 	else if (Matches4("DROP", "TRIGGER", MatchAny, "ON"))
 	{
@@ -2333,15 +2649,27 @@ psql_completion(const char *text, int start, int end)
 	else if (Matches2("DROP", "EVENT"))
 		COMPLETE_WITH_CONST("TRIGGER");
 	else if (Matches3("DROP", "EVENT", "TRIGGER"))
+		COMPLETE_WITH_QUERY(Query_for_list_of_event_triggers
+							" UNION SELECT 'IF EXISTS'");
+	/* Trye the same after removing optional words IF EXISTS */
+	else if (HeadMatches3("DROP", "EVENT", "TRIGGER") &&
+			 MidMatchAndRemove2(3, "IF", "EXISTS") &&
+			 Matches3("DROP", "EVENT", "TRIGGER"))
 		COMPLETE_WITH_QUERY(Query_for_list_of_event_triggers);
 
-	/* DROP POLICY <name>  */
+	/* DROP POLICY */
 	else if (Matches2("DROP", "POLICY"))
+		COMPLETE_WITH_QUERY(Query_for_list_of_policies
+							" UNION SELECT 'IF EXISTS'");
+	/* Try the same after after removing optional words IF EXISTS */
+	else if (HeadMatches2("DROP", "POLICY") &&
+			 MidMatchAndRemove2(2, "IF", "EXISTS") &&
+			 Matches2("DROP", "POLICY"))
 		COMPLETE_WITH_QUERY(Query_for_list_of_policies);
-	/* DROP POLICY <name> ON */
+	/* DROP POLICY <name> */
 	else if (Matches3("DROP", "POLICY", MatchAny))
 		COMPLETE_WITH_CONST("ON");
-	/* DROP POLICY <name> ON <table> */
+	/* DROP POLICY <name> ON */
 	else if (Matches4("DROP", "POLICY", MatchAny, "ON"))
 	{
 		completion_info_charp = prev2_wd;
@@ -2349,7 +2677,13 @@ psql_completion(const char *text, int start, int end)
 	}
 
 	/* DROP RULE */
-	else if (Matches3("DROP", "RULE", MatchAny))
+	else if (Matches2("DROP", "RULE"))
+		COMPLETE_WITH_QUERY(Query_for_list_of_rules
+							"UNION SELECT 'IF EXISTS'");
+	/* DROP RULE <name>, after removing optional words IF EXISTS */
+	else if (HeadMatches2("DROP", "RULE") &&
+			 MidMatchAndRemove2(2, "IF", "EXISTS") &&
+			 Matches3("DROP", "RULE", MatchAny))
 		COMPLETE_WITH_CONST("ON");
 	else if (Matches4("DROP", "RULE", MatchAny, "ON"))
 	{
@@ -2359,6 +2693,52 @@ psql_completion(const char *text, int start, int end)
 	else if (Matches5("DROP", "RULE", MatchAny, "ON", MatchAny))
 		COMPLETE_WITH_LIST2("CASCADE", "RESTRICT");
 
+	/* IF EXISTS processing for DROP everything else */
+	else if (Matches2("DROP",
+					  "CAST|COLLATION|CONVERSION|DATABASE|DOMAIN|"
+					  "GROUP|LANGUAGE|OPERATOR|ROLE|SCHEMA|SEQUENCE|"
+					  "SERVER|TABLE|TABLESPACE|TYPE|USER") ||
+			 Matches4("DROP", "TEXT", "SEARCH",
+					  "CONFIGURATION|DICTIONARY|PARSER|TEMPLATE"))
+
+	{
+		const pgsql_thing_t *ent = find_thing_entry(prev_wd);
+		char *addition = " UNION SELECT 'IF EXISTS'";
+
+		if (ent)
+		{
+			/* Completing USER needs special treat */
+			if (pg_strcasecmp(prev_wd, "USER") == 0)
+			{
+				COMPLETE_WITH_QUERY(Query_for_list_of_roles 
+									"UNION SELECT 'MAPPING' UNION SELECT 'IF EXISTS'");
+			}
+			else if (ent->query)
+			{
+				char *buf = pg_malloc(strlen(ent->query) +
+									  strlen(addition) + 1);
+				strcpy(buf, ent->query);
+				strcat(buf, addition);
+				COMPLETE_WITH_QUERY(buf);
+				free(buf);
+			}
+			else if (ent->squery)
+				COMPLETE_WITH_SCHEMA_QUERY(*ent->squery,
+										   " UNION SELECT 'IF EXISTS'");
+		}
+	}
+	/* Remove optional IF EXISTS from DROP */
+	else if (HeadMatches2("DROP",
+						  "CAST|COLLATION|CONVERSION|DATABASE|DOMAIN|GROUP|"
+						  "LANGUAGE|OPERATOR|ROLE|SCHEMA|SEQUENCE|SERVER|"
+						  "TABLE|TABLESPACE|TYPE|USER") &&
+			 MidMatchAndRemove2(2, "IF", "EXISTS") &&
+			 false) {} /* FALL THROUGH */
+	else if (HeadMatches4("DROP", "TEXT", "SEARCH",
+						  "CONFIGURATION|DICTIONARY|PARSER|TEMPLATE") &&
+			 MidMatchAndRemove2(4, "IF", "EXISTS") &&
+			 false) {} /* FALL THROUGH */
+
 /* EXECUTE */
 	else if (Matches1("EXECUTE"))
 		COMPLETE_WITH_QUERY(Query_for_list_of_prepared_statements);
@@ -2405,8 +2785,7 @@ psql_completion(const char *text, int start, int end)
 		COMPLETE_WITH_CONST("OPTIONS");
 
 /* FOREIGN TABLE */
-	else if (TailMatches2("FOREIGN", "TABLE") &&
-			 !TailMatches3("CREATE", MatchAny, MatchAny))
+	else if (TailMatches2("FOREIGN", "TABLE"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_foreign_tables, NULL);
 
 /* FOREIGN SERVER */
@@ -2842,8 +3221,13 @@ psql_completion(const char *text, int start, int end)
 		COMPLETE_WITH_CONST("=");
 
 /* USER MAPPING */
-	else if (Matches3("ALTER|CREATE|DROP", "USER", "MAPPING"))
+	else if (Matches3("ALTER|CREATE", "USER", "MAPPING"))
 		COMPLETE_WITH_CONST("FOR");
+	else if (Matches3("DROP", "USER", "MAPPING"))
+		COMPLETE_WITH_LIST2("FOR", "IF EXISTS FOR");
+	else if (HeadMatches3("DROP", "USER", "MAPPING") &&
+			 MidMatchAndRemove2(3, "IF", "EXISTS") &&
+			 false) {} /* FALL THROUGH */
 	else if (Matches4("CREATE", "USER", "MAPPING", "FOR"))
 		COMPLETE_WITH_QUERY(Query_for_list_of_roles
 							" UNION SELECT 'CURRENT_USER'"
@@ -3071,19 +3455,14 @@ psql_completion(const char *text, int start, int end)
 	 */
 	else
 	{
-		int			i;
+		const pgsql_thing_t *ent = find_thing_entry(prev_wd);
 
-		for (i = 0; words_after_create[i].name; i++)
+		if (ent)
 		{
-			if (pg_strcasecmp(prev_wd, words_after_create[i].name) == 0)
-			{
-				if (words_after_create[i].query)
-					COMPLETE_WITH_QUERY(words_after_create[i].query);
-				else if (words_after_create[i].squery)
-					COMPLETE_WITH_SCHEMA_QUERY(*words_after_create[i].squery,
-											   NULL);
-				break;
-			}
+			if (ent->query)
+				COMPLETE_WITH_QUERY(ent->query);
+			else if (ent->squery)
+				COMPLETE_WITH_SCHEMA_QUERY(*ent->squery, NULL);
 		}
 	}
 
@@ -3608,6 +3987,18 @@ complete_from_files(const char *text, int state)
 
 /* HELPER FUNCTIONS */
 
+/*
+ * Return the index (reverse to the index of previous_words) of the tailmost
+ * (topmost in the array) appearance of w.
+ */
+static int
+find_last_index_of(char *w, char **previous_words, int len)
+{
+	int i;
+
+	for (i = 0 ; i < len && !word_matches(w, previous_words[i]) ; i++);
+	return i < len ? (len - i - 1) : 0;
+}
 
 /*
  * Make a pg_strdup copy of s and convert the case according to
@@ -3854,6 +4245,24 @@ get_guctype(const char *varname)
 	return guctype;
 }
 
+/*
+ * Finds the entry in words_after_create[] that matches the word.
+ * NULL if not found.
+ */
+static const pgsql_thing_t *
+find_thing_entry(char *word)
+{
+	int			i;
+
+	for (i = 0; words_after_create[i].name; i++)
+	{
+		if (pg_strcasecmp(word, words_after_create[i].name) == 0)
+			return words_after_create + i;
+	}
+
+	return NULL;
+}
+
 #ifdef NOT_USED
 
 /*
-- 
1.8.3.1

>From 7b1785289fe8c347ee8d46a91ab1d5a205401149 Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi <horiguchi.kyot...@lab.ntt.co.jp>
Date: Tue, 29 Mar 2016 19:01:13 +0900
Subject: [PATCH 2/3] Make added keywords for completion queries follow to
 input.

Currently some keyword shown along with database objects are always in
upper case. This patch changes the behavior so that the case of the
additional keywords follow the setting of COMP_KEYWORD_CASE.
Only COMPLETE_WITH_QUERY/COMPLETE_WITH_SCHEMA_QUERY are fixed.
---
 src/bin/psql/tab-complete.c | 231 +++++++++++++++++++++++++-------------------
 1 file changed, 132 insertions(+), 99 deletions(-)

diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index a0808cf..ea8694c 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -312,6 +312,18 @@ do { \
 	COMPLETE_WITH_LIST_CS(list); \
 } while (0)
 
+#define ADDLIST1(p, s1) additional_kw_query(p, text, 1, s1)
+#define ADDLIST2(p, s1, s2) additional_kw_query(p, text, 2, s1, s2)
+#define ADDLIST3(p, s1, s2, s3) additional_kw_query(p, text, 3, s1, s2, s3)
+#define ADDLIST4(p, s1, s2, s3, s4) \
+	additional_kw_query(p, text, 4, s1, s2, s3, s4)
+#define ADDLIST13(p, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13) \
+	additional_kw_query(p, text, 12, s1, s2, s3, s4, s5, s6, s7,		\
+						s8, s9, s10, s11, s12, s13)
+#define ADDLIST15(p, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15) \
+	additional_kw_query(p, text, 12, s1, s2, s3, s4, s5, s6, s7,		\
+						s8, s9, s10, s11, s12, s13, s14, s15)
+
 /*
  * Assembly instructions for schema queries
  */
@@ -956,6 +968,7 @@ static char *complete_from_files(const char *text, int state);
 
 static int find_last_index_of(char *w, char **previous_words, int len);
 static char *pg_strdup_keyword_case(const char *s, const char *ref);
+static char *additional_kw_query(char *prefix, const char *ref, int n, ...);
 static char *escape_string(const char *text);
 static PGresult *exec_query(const char *query);
 
@@ -1440,8 +1453,8 @@ psql_completion(const char *text, int start, int end)
 	/* ALTER TABLE */
 	else if (Matches2("ALTER", "TABLE"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
-								   "UNION SELECT 'IF EXISTS'"
-								   "UNION SELECT 'ALL IN TABLESPACE'");
+			ADDLIST2("", "IF EXISTS", "ALL IN TABLESPACE"));
+
 	/* ALTER TABLE after removing optional words IF EXISTS*/
 	else if (HeadMatches2("ALTER", "TABLE") &&
 			 MidMatchAndRemove2(2, "IF", "EXISTS") &&
@@ -1527,7 +1540,7 @@ psql_completion(const char *text, int start, int end)
 	/* ALTER FOREIGN TABLE */
 	else if (Matches3("ALTER|DROP", "FOREIGN", "TABLE"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_foreign_tables,
-								   " UNION SELECT 'IF EXISTS'");
+								   ADDLIST1("", "IF EXISTS"));
 
 	/* ALTER|DROP FOREIGN TABLE after removing optinal words IF EXISTS */
 	else if (HeadMatches3("ALTER|DROP", "FOREIGN", "TABLE") &&
@@ -1553,8 +1566,7 @@ psql_completion(const char *text, int start, int end)
 	/* ALTER INDEX */
 	else if (Matches2("ALTER", "INDEX"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes,
-								   "UNION SELECT 'IF EXISTS'"
-								   "UNION SELECT 'ALL IN TABLESPACE'");
+			   ADDLIST2("", "IF EXISTS", "ALL IN TABLESPACE"));
 	/* ALTER INDEX after removing optional words IF EXISTS */
 	else if (HeadMatches2("ALTER", "INDEX") &&
 			 MidMatchAndRemove2(2, "IF", "EXISTS") &&
@@ -1589,8 +1601,7 @@ psql_completion(const char *text, int start, int end)
 	/* ALTER MATERIALIZED VIEW */
 	else if (Matches3("ALTER", "MATERIALIZED", "VIEW"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews,
-								   "UNION SELECT 'IF EXISTS'"
-								   "UNION SELECT 'ALL IN TABLESPACE'");
+			   ADDLIST2("", "IF EXISTS", "ALL IN TABLESPACE"));
 
 	/* ALTER MATERIALIZED VIEW with name after removing optional words */
 	else if (HeadMatches3("ALTER", "MATERIALIZED", "VIEW") &&
@@ -1658,8 +1669,8 @@ psql_completion(const char *text, int start, int end)
 	else if (Matches5("ALTER", "DOMAIN", MatchAny, "DROP", "CONSTRAINT"))
 	{
 		completion_info_charp = prev3_wd;
-		COMPLETE_WITH_QUERY(Query_for_constraint_of_type
-							"UNION SELECT 'IF EXISTS'");
+		COMPLETE_WITH_QUERY(
+			ADDLIST1(Query_for_constraint_of_type, "IF EXISTS"));
 	}
 	/* Try the same match after removing optional words IF EXISTS */
 	else if (HeadMatches5("ALTER", "DOMAIN", MatchAny, "DROP", "CONSTRAINT") &&
@@ -1681,7 +1692,7 @@ psql_completion(const char *text, int start, int end)
 		COMPLETE_WITH_LIST3("DEFAULT", "NOT NULL", "SCHEMA");
 	else if (Matches2("ALTER", "SEQUENCE"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences,
-								   " UNION SELECT 'IF EXISTS'");
+								   ADDLIST1("", "IF EXISTS"));
 	/* ALTER SEQUENCE with name after removing optional words IF EXISTS */
 	else if (HeadMatches2("ALTER", "SEQUENCE") &&
 			 MidMatchAndRemove2(2, "IF", "EXISTS") &&
@@ -1711,7 +1722,7 @@ psql_completion(const char *text, int start, int end)
 	/* ALTER VIEW */
 	else if (Matches2("ALTER", "VIEW"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views,
-								   "UNION SELECT 'IF EXISTS'");
+								   ADDLIST1("", "IF EXISTS"));
 	/* ALTER VIEW <name> with subcommands after removing optional worlds */
 	else if (HeadMatches2("ALTER", "VIEW") &&
 			 MidMatchAndRemove2(2, "IF", "EXISTS") &&
@@ -1725,8 +1736,8 @@ psql_completion(const char *text, int start, int end)
 
 	/* ALTER POLICY */
 	else if (Matches2("ALTER", "POLICY"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_policies
-							"UNION SELECT 'IF EXISTS'");
+		COMPLETE_WITH_QUERY(
+			ADDLIST1(Query_for_list_of_policies, "IF EXISTS"));
 	/* ALTER POLICY <name> with ON after removing optional words IF EXISTS */
 	else if (HeadMatches2("ALTER", "POLICY") &&
 			 MidMatchAndRemove2(2, "IF", "EXISTS") &&
@@ -1901,8 +1912,8 @@ psql_completion(const char *text, int start, int end)
 	else if (Matches5("ALTER", "TABLE", MatchAny, "DROP", "CONSTRAINT"))
 	{
 		completion_info_charp = prev3_wd;
-		COMPLETE_WITH_QUERY(Query_for_constraint_of_table
-							"UNION SELECT 'IF EXISTS'");
+		COMPLETE_WITH_QUERY(
+			ADDLIST1(Query_for_constraint_of_table, "IF EXISTS"));
 	}
 	/* Try the same after removing optional words IF EXISTS */
 	else if (HeadMatches5("ALTER", "TABLE", MatchAny, "DROP", "CONSTRAINT") &&
@@ -2096,7 +2107,8 @@ psql_completion(const char *text, int start, int end)
 		COMPLETE_WITH_LIST4("WORK", "TRANSACTION", "TO SAVEPOINT", "PREPARED");
 /* CLUSTER */
 	else if (Matches1("CLUSTER"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, "UNION SELECT 'VERBOSE'");
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
+								   ADDLIST1("", "VERBOSE"));
 	else if (Matches2("CLUSTER", "VERBOSE"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, NULL);
 	/* If we have CLUSTER <sth>, then add "USING" */
@@ -2158,7 +2170,7 @@ psql_completion(const char *text, int start, int end)
 	 */
 	else if (Matches1("COPY|\\copy"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
-								   " UNION ALL SELECT '('");
+								   ADDLIST1("", "("));
 	/* If we have COPY BINARY, complete with list of tables */
 	else if (Matches2("COPY", "BINARY"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
@@ -2237,7 +2249,7 @@ psql_completion(const char *text, int start, int end)
 	/* CREATE FOREIGN TABLE */
 	else if (Matches3("CREATE", "FOREIGN", "TABLE"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_foreign_tables,
-								   " UNION SELECT 'IF NOT EXISTS'");
+								   ADDLIST1("", "IF NOT EXISTS"));
 	/* Remove optional words IF NOT EXISTS */
 	else if (HeadMatches3("CREATE", "FOREIGN", "TABLE") &&
 			 MidMatchAndRemove3(3, "IF", "NOT", "EXISTS") &&
@@ -2258,15 +2270,12 @@ psql_completion(const char *text, int start, int end)
 			 MidMatchAndRemove1(1, "UNIQUE") &&
 			 Matches2("CREATE", "INDEX"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes,
-								   " UNION SELECT 'ON'"
-								   " UNION SELECT 'CONCURRENTLY'"
-								   " UNION SELECT 'IF NOT EXISTS'");
+				   ADDLIST3("", "ON", "CONCURRENTLY", "IF NOT EXISTS"));
 	/* Complete CREATE INDEX CONCURRENTLY with "ON" or IF NOT EXISTS and
 	 * existing indexes */
 	else if (Matches3("CREATE", "INDEX", "CONCURRENTLY"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes,
-								   " UNION SELECT 'IF NOT EXISTS'"
-								   " UNION SELECT 'ON'");
+								   ADDLIST2("", "IF NOT EXISTS", "ON"));
 
 	/* Remove optional words "CONCURRENTLY",  "IF NOT EXISTS" */
 	else if (HeadMatches2("CREATE", "INDEX") &&
@@ -2370,8 +2379,8 @@ psql_completion(const char *text, int start, int end)
 
 /* CREATE SCHEMA <name> */
 	else if (Matches2("CREATE", "SCHEMA"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_schemas
-							" UNION SELECT 'IF NOT EXISTS'");
+		COMPLETE_WITH_QUERY(
+			ADDLIST1(Query_for_list_of_schemas, "IF NOT EXISTS"));
 	/* Remove optional words IF NOT EXISTS */
 	else if (HeadMatches2("CREATE", "SCHEMA") &&
 			 MidMatchAndRemove3(2, "IF", "NOT", "EXISTS") &&
@@ -2390,7 +2399,7 @@ psql_completion(const char *text, int start, int end)
 			 MidMatchAndRemove1(1, "TEMP|TEMPORARY|UNLOGGED") &&
 			 Matches2("CREATE", "TABLE"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
-								   " UNION SELECT 'IF NOT EXISTS'");
+								   ADDLIST1("", "IF NOT EXISTS"));
 
 	/* Remove optional words here */
 	else if (HeadMatches2("CREATE", "TABLE") &&
@@ -2481,7 +2490,7 @@ psql_completion(const char *text, int start, int end)
 /* CREATE VIEW  */
 	else if (Matches2("CREATE", "VIEW"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views,
-								   " UNION SELECT 'IF NOT EXISTS'");
+								   ADDLIST1("", "IF NOT EXISTS"));
 	/* CREATE VIEW <name> with AS after removing optional words */
 	else if (HeadMatches2("CREATE", "VIEW") &&
 			 MidMatchAndRemove3(2, "IF", "NOT", "EXISTS") &&
@@ -2496,7 +2505,7 @@ psql_completion(const char *text, int start, int end)
 		COMPLETE_WITH_CONST("VIEW");
 	else if (Matches3("CREATE", "MATERIALIZED", "VIEW"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews,
-								   " UNION SELECT 'IF NOT EXISTS'");
+								   ADDLIST1("", "IF NOT EXISTS"));
 	/* Try the same after removing optional words IF NOT EXISTS. VIEW will be
 	 * completed afterwards */
 	else if (HeadMatches3("CREATE", "MATERIALIZED", "VIEW") &&
@@ -2564,10 +2573,10 @@ psql_completion(const char *text, int start, int end)
 	/* help completing some of the variants */
 	else if (Matches2("DROP", "AGGREGATE"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_aggregates,
-								   " UNION SELECT 'IF EXISTS'");
+								   ADDLIST1("", "IF EXISTS"));
 	else if (Matches2("DROP", "FUNCTION"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions,
-								   " UNION SELECT 'IF EXISTS'");
+								   ADDLIST1("", "IF EXISTS"));
 	/* Try the same after removing optional words IF EXISTS */
 	else if (HeadMatches2("DROP", "AGGREGATE|FUNCTION") &&
 			 MidMatchAndRemove2(2, "IF", "EXISTS") &&
@@ -2578,8 +2587,8 @@ psql_completion(const char *text, int start, int end)
 	else if (Matches2("DROP", "FOREIGN"))
 		COMPLETE_WITH_LIST2("DATA WRAPPER", "TABLE");
 	else if (Matches4("DROP", "FOREIGN", "DATA", "WRAPPER"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_fdws
-							" UNION SELECT 'IF EXISTS'");
+		COMPLETE_WITH_QUERY(
+			ADDLIST1(Query_for_list_of_fdws, "IF EXISTS"));
 	/* Try the same after removing optional words IF EXISTS */
 	else if (HeadMatches4("DROP", "FOREIGN", "DATA", "WRAPPER") &&
 			 MidMatchAndRemove2(4, "IF", "EXISTS") &&
@@ -2588,11 +2597,10 @@ psql_completion(const char *text, int start, int end)
 	/* DROP INDEX */
 	else if (Matches2("DROP", "INDEX"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes,
-								   " UNION SELECT 'IF EXISTS'"
-								   " UNION SELECT 'CONCURRENTLY'");
+								   ADDLIST2("", "IF EXISTS","CONCURRENTLY"));
 	else if (Matches3("DROP", "INDEX", "CONCURRENTLY"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes,
-								   " UNION SELECT 'IF EXISTS'");
+								   ADDLIST1("", "IF EXISTS"));
 	/* Try the same after optional words CONCURRENTLY and IF NOT EXISTS */
 	else if (HeadMatches2("DROP", "INDEX") &&
 			 MidMatchAndRemove1(2, "CONCURRENTLY") &&
@@ -2605,14 +2613,14 @@ psql_completion(const char *text, int start, int end)
 		COMPLETE_WITH_CONST("VIEW");
 	else if (Matches2("DROP", "VIEW"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views,
-								   " UNION SELECT 'IF EXISTS'");
+								   ADDLIST1("", "IF EXISTS"));
 	/* Remove optional words IF EXISTS  */
 	else if (HeadMatches2("DROP", "VIEW") &&
 			 MidMatchAndRemove2(2, "IF", "EXISTS") &&
 			 false) {} /* FALL THROUGH */
 	else if (Matches3("DROP", "MATERIALIZED", "VIEW"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews,
-								   " UNION SELECT 'IF EXISTS'");
+								   ADDLIST1("", "IF EXISTS"));
 	/* Try the same after removing optional words IF EXISTS */
 	else if (HeadMatches3("DROP", "MATERIALIZED", "VIEW") &&
 			 MidMatchAndRemove2(3, "IF", "EXISTS") &&
@@ -2630,8 +2638,8 @@ psql_completion(const char *text, int start, int end)
 
 	/* DROP TRIGGER */
 	else if (Matches2("DROP", "TRIGGER"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_triggers
-							" UNION SELECT 'IF EXISTS'");
+		COMPLETE_WITH_QUERY(
+			ADDLIST1(Query_for_list_of_triggers, "IF EXISTS"));
 	/* Try the same after removing optional words IF EXISTS */
 	else if (HeadMatches2("DROP", "TRIGGER") &&
 			 MidMatchAndRemove2(2, "IF", "EXISTS") &&
@@ -2649,8 +2657,8 @@ psql_completion(const char *text, int start, int end)
 	else if (Matches2("DROP", "EVENT"))
 		COMPLETE_WITH_CONST("TRIGGER");
 	else if (Matches3("DROP", "EVENT", "TRIGGER"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_event_triggers
-							" UNION SELECT 'IF EXISTS'");
+		COMPLETE_WITH_QUERY(
+			ADDLIST1(Query_for_list_of_event_triggers, "IF EXISTS"));
 	/* Trye the same after removing optional words IF EXISTS */
 	else if (HeadMatches3("DROP", "EVENT", "TRIGGER") &&
 			 MidMatchAndRemove2(3, "IF", "EXISTS") &&
@@ -2659,8 +2667,8 @@ psql_completion(const char *text, int start, int end)
 
 	/* DROP POLICY */
 	else if (Matches2("DROP", "POLICY"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_policies
-							" UNION SELECT 'IF EXISTS'");
+		COMPLETE_WITH_QUERY(
+			ADDLIST1(Query_for_list_of_policies, "IF EXISTS"));
 	/* Try the same after after removing optional words IF EXISTS */
 	else if (HeadMatches2("DROP", "POLICY") &&
 			 MidMatchAndRemove2(2, "IF", "EXISTS") &&
@@ -2678,8 +2686,8 @@ psql_completion(const char *text, int start, int end)
 
 	/* DROP RULE */
 	else if (Matches2("DROP", "RULE"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_rules
-							"UNION SELECT 'IF EXISTS'");
+		COMPLETE_WITH_QUERY(
+			ADDLIST1(Query_for_list_of_rules, "IF EXISTS"));
 	/* DROP RULE <name>, after removing optional words IF EXISTS */
 	else if (HeadMatches2("DROP", "RULE") &&
 			 MidMatchAndRemove2(2, "IF", "EXISTS") &&
@@ -2710,8 +2718,8 @@ psql_completion(const char *text, int start, int end)
 			/* Completing USER needs special treat */
 			if (pg_strcasecmp(prev_wd, "USER") == 0)
 			{
-				COMPLETE_WITH_QUERY(Query_for_list_of_roles 
-									"UNION SELECT 'MAPPING' UNION SELECT 'IF EXISTS'");
+				COMPLETE_WITH_QUERY(
+					ADDLIST2(Query_for_list_of_roles, "MAPPING", "IF EXISTS"));
 			}
 			else if (ent->query)
 			{
@@ -2724,7 +2732,7 @@ psql_completion(const char *text, int start, int end)
 			}
 			else if (ent->squery)
 				COMPLETE_WITH_SCHEMA_QUERY(*ent->squery,
-										   " UNION SELECT 'IF EXISTS'");
+										   ADDLIST1("", "IF EXISTS"));
 		}
 	}
 	/* Remove optional IF EXISTS from DROP */
@@ -2795,20 +2803,11 @@ psql_completion(const char *text, int start, int end)
 /* GRANT && REVOKE --- is allowed inside CREATE SCHEMA, so use TailMatches */
 	/* Complete GRANT/REVOKE with a list of roles and privileges */
 	else if (TailMatches1("GRANT|REVOKE"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_roles
-							" UNION SELECT 'SELECT'"
-							" UNION SELECT 'INSERT'"
-							" UNION SELECT 'UPDATE'"
-							" UNION SELECT 'DELETE'"
-							" UNION SELECT 'TRUNCATE'"
-							" UNION SELECT 'REFERENCES'"
-							" UNION SELECT 'TRIGGER'"
-							" UNION SELECT 'CREATE'"
-							" UNION SELECT 'CONNECT'"
-							" UNION SELECT 'TEMPORARY'"
-							" UNION SELECT 'EXECUTE'"
-							" UNION SELECT 'USAGE'"
-							" UNION SELECT 'ALL'");
+		COMPLETE_WITH_QUERY(
+			ADDLIST13(Query_for_list_of_roles,
+					  "SELECT", "INSERT", "UPDATE", "DELETE", "TRUNCATE",
+					  "REFERENCES", "TRIGGER", "CREATE", "CONNECT", "TEMPORARY",
+					  "EXECUTE", "USAGE", "ALL"));
 
 	/*
 	 * Complete GRANT/REVOKE <privilege> with "ON", GRANT/REVOKE <role> with
@@ -2837,21 +2836,22 @@ psql_completion(const char *text, int start, int end)
 	 */
 	else if (TailMatches3("GRANT|REVOKE", MatchAny, "ON"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf,
-								   " UNION SELECT 'ALL FUNCTIONS IN SCHEMA'"
-								   " UNION SELECT 'ALL SEQUENCES IN SCHEMA'"
-								   " UNION SELECT 'ALL TABLES IN SCHEMA'"
-								   " UNION SELECT 'DATABASE'"
-								   " UNION SELECT 'DOMAIN'"
-								   " UNION SELECT 'FOREIGN DATA WRAPPER'"
-								   " UNION SELECT 'FOREIGN SERVER'"
-								   " UNION SELECT 'FUNCTION'"
-								   " UNION SELECT 'LANGUAGE'"
-								   " UNION SELECT 'LARGE OBJECT'"
-								   " UNION SELECT 'SCHEMA'"
-								   " UNION SELECT 'SEQUENCE'"
-								   " UNION SELECT 'TABLE'"
-								   " UNION SELECT 'TABLESPACE'"
-								   " UNION SELECT 'TYPE'");
+			   ADDLIST15("",
+						 "ALL FUNCTIONS IN SCHEMA",
+						 "ALL SEQUENCES IN SCHEMA",
+						 "ALL TABLES IN SCHEMA",
+						 "DATABASE",
+						 "DOMAIN",
+						 "FOREIGN DATA WRAPPER",
+						 "FOREIGN SERVER",
+						 "FUNCTION",
+						 "LANGUAGE",
+						 "LARGE OBJECT",
+						 "SCHEMA",
+						 "SEQUENCE",
+						 "TABLE",
+						 "TABLESPACE",
+						 "TYPE"));
 
 	else if (TailMatches4("GRANT|REVOKE", MatchAny, "ON", "ALL"))
 		COMPLETE_WITH_LIST3("FUNCTIONS IN SCHEMA", "SEQUENCES IN SCHEMA",
@@ -2977,7 +2977,7 @@ psql_completion(const char *text, int start, int end)
 	/* Complete LOCK [TABLE] with a list of tables */
 	else if (Matches1("LOCK"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
-								   " UNION SELECT 'TABLE'");
+								   ADDLIST1("", "TABLE"));
 	else if (Matches2("LOCK", "TABLE"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
 
@@ -3043,7 +3043,7 @@ psql_completion(const char *text, int start, int end)
 		COMPLETE_WITH_CONST("VIEW");
 	else if (Matches3("REFRESH", "MATERIALIZED", "VIEW"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews,
-								   " UNION SELECT 'CONCURRENTLY'");
+								   ADDLIST1("", "CONCURRENTLY"));
 	else if (Matches4("REFRESH", "MATERIALIZED", "VIEW", "CONCURRENTLY"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, NULL);
 	else if (Matches4("REFRESH", "MATERIALIZED", "VIEW", MatchAny))
@@ -3119,7 +3119,8 @@ psql_completion(const char *text, int start, int end)
 		COMPLETE_WITH_LIST2("ONLY", "WRITE");
 	/* SET CONSTRAINTS */
 	else if (Matches2("SET", "CONSTRAINTS"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_constraints_with_schema, "UNION SELECT 'ALL'");
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_constraints_with_schema,
+								   ADDLIST1("", "ALL"));
 	/* Complete SET CONSTRAINTS <foo> with DEFERRED|IMMEDIATE */
 	else if (Matches3("SET", "CONSTRAINTS", MatchAny))
 		COMPLETE_WITH_LIST2("DEFERRED", "IMMEDIATE");
@@ -3131,7 +3132,8 @@ psql_completion(const char *text, int start, int end)
 		COMPLETE_WITH_LIST2("AUTHORIZATION", "CHARACTERISTICS AS TRANSACTION");
 	/* Complete SET SESSION AUTHORIZATION with username */
 	else if (Matches3("SET", "SESSION", "AUTHORIZATION"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_roles " UNION SELECT 'DEFAULT'");
+		COMPLETE_WITH_QUERY(
+			ADDLIST1(Query_for_list_of_roles, "DEFAULT"));
 	/* Complete RESET SESSION with AUTHORIZATION */
 	else if (Matches2("RESET", "SESSION"))
 		COMPLETE_WITH_CONST("AUTHORIZATION");
@@ -3157,10 +3159,11 @@ psql_completion(const char *text, int start, int end)
 			COMPLETE_WITH_LIST(my_list);
 		}
 		else if (TailMatches2("search_path", "TO|="))
-			COMPLETE_WITH_QUERY(Query_for_list_of_schemas
-								" AND nspname not like 'pg\\_toast%%' "
-								" AND nspname not like 'pg\\_temp%%' "
-								" UNION SELECT 'DEFAULT' ");
+			COMPLETE_WITH_QUERY(
+				ADDLIST1(Query_for_list_of_schemas
+						 " AND nspname not like 'pg\\_toast%%' "
+						 " AND nspname not like 'pg\\_temp%%' ",
+						 "DEFAULT"));
 		else
 		{
 			/* generic, type based, GUC support */
@@ -3229,10 +3232,9 @@ psql_completion(const char *text, int start, int end)
 			 MidMatchAndRemove2(3, "IF", "EXISTS") &&
 			 false) {} /* FALL THROUGH */
 	else if (Matches4("CREATE", "USER", "MAPPING", "FOR"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_roles
-							" UNION SELECT 'CURRENT_USER'"
-							" UNION SELECT 'PUBLIC'"
-							" UNION SELECT 'USER'");
+		COMPLETE_WITH_QUERY(
+			ADDLIST3(Query_for_list_of_roles, 
+					 "CURRENT_USER", "PUBLIC", "USER"));
 	else if (Matches4("ALTER|DROP", "USER", "MAPPING", "FOR"))
 		COMPLETE_WITH_QUERY(Query_for_list_of_user_mappings);
 	else if (Matches5("CREATE|ALTER|DROP", "USER", "MAPPING", "FOR", MatchAny))
@@ -3246,26 +3248,22 @@ psql_completion(const char *text, int start, int end)
  */
 	else if (Matches1("VACUUM"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
-								   " UNION SELECT 'FULL'"
-								   " UNION SELECT 'FREEZE'"
-								   " UNION SELECT 'ANALYZE'"
-								   " UNION SELECT 'VERBOSE'");
+		   ADDLIST4("", "FULL", "FREEZE", "ANALYZE", "VERBOSE"));
 	else if (Matches2("VACUUM", "FULL|FREEZE"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
-								   " UNION SELECT 'ANALYZE'"
-								   " UNION SELECT 'VERBOSE'");
+		   ADDLIST2("", "ANALYZE", "VERBOSE"));
 	else if (Matches3("VACUUM", "FULL|FREEZE", "ANALYZE"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
-								   " UNION SELECT 'VERBOSE'");
+		   ADDLIST1("", "VERBOSE"));
 	else if (Matches3("VACUUM", "FULL|FREEZE", "VERBOSE"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
-								   " UNION SELECT 'ANALYZE'");
+		   ADDLIST1("", "ANALYZE"));
 	else if (Matches2("VACUUM", "VERBOSE"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
-								   " UNION SELECT 'ANALYZE'");
+		   ADDLIST1("", "ANALYZE"));
 	else if (Matches2("VACUUM", "ANALYZE"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
-								   " UNION SELECT 'VERBOSE'");
+		   ADDLIST1("", "VERBOSE"));
 	else if (HeadMatches1("VACUUM"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, NULL);
 
@@ -4030,6 +4028,41 @@ pg_strdup_keyword_case(const char *s, const char *ref)
 	return ret;
 }
 
+/* Construct codelet to append given keywords  */
+static char *
+additional_kw_query(char *prefix, const char *ref, int n, ...)
+{
+	va_list ap;
+	static PQExpBuffer qbuf = NULL;
+	int i;
+
+	if (qbuf == NULL)
+		qbuf = createPQExpBuffer();
+	else
+		resetPQExpBuffer(qbuf);
+
+	appendPQExpBufferStr(qbuf, prefix);
+
+	/* Construct an additional queriy to append keywords */
+	appendPQExpBufferStr(qbuf, " UNION SELECT * FROM (VALUES ");
+
+	va_start(ap, n);
+	for (i = 0 ; i < n ; i++)
+	{
+		char *item = pg_strdup_keyword_case(va_arg(ap, char *), ref);
+		if (i > 0) appendPQExpBufferChar(qbuf, ',');
+		appendPQExpBufferStr(qbuf, "('");
+		appendPQExpBufferStr(qbuf, item);
+		appendPQExpBufferStr(qbuf, "')");
+		pg_free(item);
+	}
+	va_end(ap);
+
+	appendPQExpBufferStr(qbuf, ") as x");
+
+	return qbuf->data;
+}
+
 
 /*
  * escape_string - Escape argument for use as string literal.
-- 
1.8.3.1

>From bffe79bf5551e6f90916c5a6686ff875fa9965ed Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi <horiguchi.kyot...@lab.ntt.co.jp>
Date: Fri, 1 Apr 2016 17:01:42 +0900
Subject: [PATCH 3/3] Make COMPLETE_WITH_ATTR to accept additional keyword
 query.

So far the previous commit, COMPLETE_WITH_ATTR cannot accept the new
style of additional keyword list. This patch does the following
things.

1. Change completion_charp from const char * to PQExpBuffer.

2. Chnage COMPLETE_WITH_QUERY and COMPLETE_WITH_ATTR to accept
   an expression instead of string literal.

3. Replace all additional keyword lists in psql_copmletion with
   ADDLISTn() expression.

This leaves keywords contained in Query_for_list_of_grant_roles and
Query_for_enum, but it is the another problem.
---
 src/bin/psql/tab-complete.c | 472 ++++++++++++++++++++++----------------------
 1 file changed, 239 insertions(+), 233 deletions(-)

diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index ea8694c..ad488ff 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -125,7 +125,7 @@ static int	completion_max_records;
  * Communication variables set by COMPLETE_WITH_FOO macros and then used by
  * the completion callback functions.  Ugly but there is no better way.
  */
-static const char *completion_charp;	/* to pass a string */
+static PQExpBuffer completion_charp = NULL;		/* to pass a string */
 static const char *const * completion_charpp;	/* to pass a list of strings */
 static const char *completion_info_charp;		/* to pass a second string */
 static const char *completion_info_charp2;		/* to pass a third string */
@@ -143,16 +143,26 @@ static bool completion_case_sensitive;	/* completion is case sensitive */
  * 5) The list of attributes of the given table (possibly schema-qualified).
  * 6/ The list of arguments to the given function (possibly schema-qualified).
  */
-#define COMPLETE_WITH_QUERY(query) \
+#define APPEND_COMP_CHARP(charp) \
+	appendPQExpBufferStr(completion_charp, charp);
+
+#define SET_COMP_CHARP(charp) \
+	resetPQExpBuffer(completion_charp);	\
+	APPEND_COMP_CHARP(charp);
+
+#define COMPLETION_CHARP (completion_charp->data)
+
+#define COMPLETE_WITH_QUERY(query, addon) \
 do { \
-	completion_charp = query; \
+	SET_COMP_CHARP(query);	\
+	APPEND_COMP_CHARP(addon); \
 	matches = completion_matches(text, complete_from_query); \
 } while (0)
 
 #define COMPLETE_WITH_SCHEMA_QUERY(query, addon) \
 do { \
 	completion_squery = &(query); \
-	completion_charp = addon; \
+	SET_COMP_CHARP(addon); \
 	matches = completion_matches(text, complete_from_schema_query); \
 } while (0)
 
@@ -172,7 +182,7 @@ do { \
 
 #define COMPLETE_WITH_CONST(string) \
 do { \
-	completion_charp = string; \
+	SET_COMP_CHARP(string);	\
 	completion_case_sensitive = false; \
 	matches = completion_matches(text, complete_from_const); \
 } while (0)
@@ -190,12 +200,14 @@ do { \
 								false, false, pset.encoding); \
 	if (_completion_table == NULL) \
 	{ \
-		completion_charp = Query_for_list_of_attributes  addon; \
+		SET_COMP_CHARP(Query_for_list_of_attributes); \
+		APPEND_COMP_CHARP(addon);					  \
 		completion_info_charp = relation; \
 	} \
 	else \
 	{ \
-		completion_charp = Query_for_list_of_attributes_with_schema  addon; \
+		SET_COMP_CHARP(Query_for_list_of_attributes_with_schema); \
+		APPEND_COMP_CHARP(addon); \
 		completion_info_charp = _completion_table; \
 		completion_info_charp2 = _completion_schema; \
 	} \
@@ -215,12 +227,12 @@ do { \
 								   false, false, pset.encoding); \
 	if (_completion_function == NULL) \
 	{ \
-		completion_charp = Query_for_list_of_arguments; \
+		SET_COMP_CHARP(Query_for_list_of_arguments); \
 		completion_info_charp = function; \
 	} \
 	else \
 	{ \
-		completion_charp = Query_for_list_of_arguments_with_schema; \
+		SET_COMP_CHARP(Query_for_list_of_arguments_with_schema); \
 		completion_info_charp = _completion_function; \
 		completion_info_charp2 = _completion_schema; \
 	} \
@@ -312,16 +324,16 @@ do { \
 	COMPLETE_WITH_LIST_CS(list); \
 } while (0)
 
-#define ADDLIST1(p, s1) additional_kw_query(p, text, 1, s1)
-#define ADDLIST2(p, s1, s2) additional_kw_query(p, text, 2, s1, s2)
-#define ADDLIST3(p, s1, s2, s3) additional_kw_query(p, text, 3, s1, s2, s3)
-#define ADDLIST4(p, s1, s2, s3, s4) \
-	additional_kw_query(p, text, 4, s1, s2, s3, s4)
-#define ADDLIST13(p, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13) \
-	additional_kw_query(p, text, 12, s1, s2, s3, s4, s5, s6, s7,		\
+#define ADDLIST1(s1) additional_kw_query(text, 1, s1)
+#define ADDLIST2(s1, s2) additional_kw_query(text, 2, s1, s2)
+#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 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)
-#define ADDLIST15(p, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15) \
-	additional_kw_query(p, text, 12, s1, s2, s3, s4, s5, s6, s7,		\
+#define ADDLIST15(s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15) \
+	additional_kw_query(text, 12, s1, s2, s3, s4, s5, s6, s7,		\
 						s8, s9, s10, s11, s12, s13, s14, s15)
 
 /*
@@ -968,7 +980,7 @@ static char *complete_from_files(const char *text, int state);
 
 static int find_last_index_of(char *w, char **previous_words, int len);
 static char *pg_strdup_keyword_case(const char *s, const char *ref);
-static char *additional_kw_query(char *prefix, const char *ref, int n, ...);
+static char *additional_kw_query( const char *ref, int n, ...);
 static char *escape_string(const char *text);
 static PGresult *exec_query(const char *query);
 
@@ -1398,7 +1410,8 @@ psql_completion(const char *text, int start, int end)
 #endif
 
 	/* Clear a few things. */
-	completion_charp = NULL;
+	if (completion_charp == NULL)
+		completion_charp = createPQExpBuffer();
 	completion_charpp = NULL;
 	completion_info_charp = NULL;
 	completion_info_charp2 = NULL;
@@ -1453,13 +1466,13 @@ psql_completion(const char *text, int start, int end)
 	/* ALTER TABLE */
 	else if (Matches2("ALTER", "TABLE"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
-			ADDLIST2("", "IF EXISTS", "ALL IN TABLESPACE"));
+			ADDLIST2("IF EXISTS", "ALL IN TABLESPACE"));
 
 	/* ALTER TABLE after removing optional words IF EXISTS*/
 	else if (HeadMatches2("ALTER", "TABLE") &&
 			 MidMatchAndRemove2(2, "IF", "EXISTS") &&
 			 Matches2("ALTER", "TABLE"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
 
 	/* ALTER something */
 	else if (Matches1("ALTER"))
@@ -1479,7 +1492,7 @@ psql_completion(const char *text, int start, int end)
 		COMPLETE_WITH_LIST2("SET TABLESPACE", "OWNED BY");
 	/* ALTER TABLE,INDEX,MATERIALIZED VIEW ALL IN TABLESPACE xxx OWNED BY */
 	else if (TailMatches6("ALL", "IN", "TABLESPACE", MatchAny, "OWNED", "BY"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_roles);
+		COMPLETE_WITH_QUERY(Query_for_list_of_roles, "");
 	/* ALTER TABLE,INDEX,MATERIALIZED VIEW ALL IN TABLESPACE xxx OWNED BY xxx */
 	else if (TailMatches7("ALL", "IN", "TABLESPACE", MatchAny, "OWNED", "BY", MatchAny))
 		COMPLETE_WITH_CONST("SET TABLESPACE");
@@ -1515,7 +1528,7 @@ psql_completion(const char *text, int start, int end)
 
 	/* ALTER EVENT TRIGGER */
 	else if (Matches3("ALTER", "EVENT", "TRIGGER"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_event_triggers);
+		COMPLETE_WITH_QUERY(Query_for_list_of_event_triggers, "");
 
 	/* ALTER EVENT TRIGGER <name> */
 	else if (Matches4("ALTER", "EVENT", "TRIGGER", MatchAny))
@@ -1540,13 +1553,13 @@ psql_completion(const char *text, int start, int end)
 	/* ALTER FOREIGN TABLE */
 	else if (Matches3("ALTER|DROP", "FOREIGN", "TABLE"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_foreign_tables,
-								   ADDLIST1("", "IF EXISTS"));
+								   ADDLIST1("IF EXISTS"));
 
 	/* ALTER|DROP FOREIGN TABLE after removing optinal words IF EXISTS */
 	else if (HeadMatches3("ALTER|DROP", "FOREIGN", "TABLE") &&
 			 MidMatchAndRemove2(3, "IF", "EXISTS") &&
 			 Matches3("ALTER|DROP", "FOREIGN", "TABLE"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_foreign_tables, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_foreign_tables, "");
 
 	/* ALTER FOREIGN TABLE <name> */
 	else if (Matches4("ALTER", "FOREIGN", "TABLE", MatchAny))
@@ -1561,17 +1574,17 @@ psql_completion(const char *text, int start, int end)
 
 	/* ALTER FOREIGN TABLE xxx RENAME */
 	else if (Matches5("ALTER", "FOREIGN", "TABLE", MatchAny, "RENAME"))
-		COMPLETE_WITH_ATTR(prev2_wd, " UNION SELECT 'COLUMN' UNION SELECT 'TO'");
+		COMPLETE_WITH_ATTR(prev2_wd, ADDLIST2("COLUMN", "TO"));
 
 	/* ALTER INDEX */
 	else if (Matches2("ALTER", "INDEX"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes,
-			   ADDLIST2("", "IF EXISTS", "ALL IN TABLESPACE"));
+			   ADDLIST2("IF EXISTS", "ALL IN TABLESPACE"));
 	/* ALTER INDEX after removing optional words IF EXISTS */
 	else if (HeadMatches2("ALTER", "INDEX") &&
 			 MidMatchAndRemove2(2, "IF", "EXISTS") &&
 			 Matches2("ALTER", "INDEX"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, "");
 
 	/* ALTER INDEX <name> */
 	else if (Matches3("ALTER", "INDEX", MatchAny))
@@ -1601,13 +1614,13 @@ psql_completion(const char *text, int start, int end)
 	/* ALTER MATERIALIZED VIEW */
 	else if (Matches3("ALTER", "MATERIALIZED", "VIEW"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews,
-			   ADDLIST2("", "IF EXISTS", "ALL IN TABLESPACE"));
+			   ADDLIST2("IF EXISTS", "ALL IN TABLESPACE"));
 
 	/* ALTER MATERIALIZED VIEW with name after removing optional words */
 	else if (HeadMatches3("ALTER", "MATERIALIZED", "VIEW") &&
 			 MidMatchAndRemove2(3, "IF", "EXISTS") &&
 			 Matches3("ALTER", "MATERIALIZED", "VIEW"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, "");
 
 	/* ALTER USER,ROLE <name> */
 	else if (Matches3("ALTER", "USER|ROLE", MatchAny) &&
@@ -1663,14 +1676,14 @@ psql_completion(const char *text, int start, int end)
 	else if (Matches5("ALTER", "DOMAIN", MatchAny, "RENAME|VALIDATE", "CONSTRAINT"))
 	{
 		completion_info_charp = prev3_wd;
-		COMPLETE_WITH_QUERY(Query_for_constraint_of_type);
+		COMPLETE_WITH_QUERY(Query_for_constraint_of_type, "");
 	}
 	/* ALTER DOMAIN <sth> DROP CONSTRAINT */
 	else if (Matches5("ALTER", "DOMAIN", MatchAny, "DROP", "CONSTRAINT"))
 	{
 		completion_info_charp = prev3_wd;
-		COMPLETE_WITH_QUERY(
-			ADDLIST1(Query_for_constraint_of_type, "IF EXISTS"));
+		COMPLETE_WITH_QUERY(Query_for_constraint_of_type,
+							ADDLIST1("IF EXISTS"));
 	}
 	/* Try the same match after removing optional words IF EXISTS */
 	else if (HeadMatches5("ALTER", "DOMAIN", MatchAny, "DROP", "CONSTRAINT") &&
@@ -1678,7 +1691,7 @@ psql_completion(const char *text, int start, int end)
 			 Matches5("ALTER", "DOMAIN", MatchAny, "DROP", "CONSTRAINT"))
 	{
 		completion_info_charp = prev3_wd;
-		COMPLETE_WITH_QUERY(Query_for_constraint_of_type);
+		COMPLETE_WITH_QUERY(Query_for_constraint_of_type, "");
 	}
 	/* ALTER DOMAIN <sth> RENAME */
 	else if (Matches4("ALTER", "DOMAIN", MatchAny, "RENAME"))
@@ -1692,7 +1705,7 @@ psql_completion(const char *text, int start, int end)
 		COMPLETE_WITH_LIST3("DEFAULT", "NOT NULL", "SCHEMA");
 	else if (Matches2("ALTER", "SEQUENCE"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences,
-								   ADDLIST1("", "IF EXISTS"));
+								   ADDLIST1("IF EXISTS"));
 	/* ALTER SEQUENCE with name after removing optional words IF EXISTS */
 	else if (HeadMatches2("ALTER", "SEQUENCE") &&
 			 MidMatchAndRemove2(2, "IF", "EXISTS") &&
@@ -1718,11 +1731,11 @@ psql_completion(const char *text, int start, int end)
 		COMPLETE_WITH_LIST2("SET", "RESET");
 	/* ALTER SYSTEM SET|RESET <name> */
 	else 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, "");
 	/* ALTER VIEW */
 	else if (Matches2("ALTER", "VIEW"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views,
-								   ADDLIST1("", "IF EXISTS"));
+								   ADDLIST1("IF EXISTS"));
 	/* ALTER VIEW <name> with subcommands after removing optional worlds */
 	else if (HeadMatches2("ALTER", "VIEW") &&
 			 MidMatchAndRemove2(2, "IF", "EXISTS") &&
@@ -1736,8 +1749,8 @@ psql_completion(const char *text, int start, int end)
 
 	/* ALTER POLICY */
 	else if (Matches2("ALTER", "POLICY"))
-		COMPLETE_WITH_QUERY(
-			ADDLIST1(Query_for_list_of_policies, "IF EXISTS"));
+		COMPLETE_WITH_QUERY(Query_for_list_of_policies,
+							ADDLIST1("IF EXISTS"));
 	/* ALTER POLICY <name> with ON after removing optional words IF EXISTS */
 	else if (HeadMatches2("ALTER", "POLICY") &&
 			 MidMatchAndRemove2(2, "IF", "EXISTS") &&
@@ -1747,14 +1760,14 @@ psql_completion(const char *text, int start, int end)
 	else if (Matches4("ALTER", "POLICY", MatchAny, "ON"))
 	{
 		completion_info_charp = prev2_wd;
-		COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_policy);
+		COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_policy, "");
 	}
 	/* ALTER POLICY <name> ON <table> - show options */
 	else if (Matches5("ALTER", "POLICY", MatchAny, "ON", MatchAny))
 		COMPLETE_WITH_LIST4("RENAME TO", "TO", "USING (", "WITH CHECK (");
 	/* ALTER POLICY <name> ON <table> TO <role> */
 	else if (Matches6("ALTER", "POLICY", MatchAny, "ON", MatchAny, "TO"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
+		COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles, "");
 	/* ALTER POLICY <name> ON <table> USING ( */
 	else if (Matches6("ALTER", "POLICY", MatchAny, "ON", MatchAny, "USING"))
 		COMPLETE_WITH_CONST("(");
@@ -1770,7 +1783,7 @@ psql_completion(const char *text, int start, int end)
 	else if (Matches4("ALTER", "RULE", MatchAny, "ON"))
 	{
 		completion_info_charp = prev2_wd;
-		COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_rule);
+		COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_rule, "");
 	}
 
 	/* ALTER RULE <name> ON <name> */
@@ -1784,14 +1797,14 @@ psql_completion(const char *text, int start, int end)
 	else if (Matches4("ALTER", "TRIGGER", MatchAny, MatchAny))
 	{
 		completion_info_charp = prev2_wd;
-		COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_trigger);
+		COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_trigger, "");
 	}
 
 	/*
 	 * If we have ALTER TRIGGER <sth> ON, then add the correct tablename
 	 */
 	else if (Matches4("ALTER", "TRIGGER", MatchAny, "ON"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
 
 	/* ALTER TRIGGER <name> ON <name> */
 	else if (Matches5("ALTER", "TRIGGER", MatchAny, "ON", MatchAny))
@@ -1818,22 +1831,22 @@ psql_completion(const char *text, int start, int end)
 	else if (Matches5("ALTER", "TABLE", MatchAny, "ENABLE", "RULE"))
 	{
 		completion_info_charp = prev3_wd;
-		COMPLETE_WITH_QUERY(Query_for_rule_of_table);
+		COMPLETE_WITH_QUERY(Query_for_rule_of_table, "");
 	}
 	else if (Matches6("ALTER", "TABLE", MatchAny, "ENABLE", MatchAny, "RULE"))
 	{
 		completion_info_charp = prev4_wd;
-		COMPLETE_WITH_QUERY(Query_for_rule_of_table);
+		COMPLETE_WITH_QUERY(Query_for_rule_of_table, "");
 	}
 	else if (Matches5("ALTER", "TABLE", MatchAny, "ENABLE", "TRIGGER"))
 	{
 		completion_info_charp = prev3_wd;
-		COMPLETE_WITH_QUERY(Query_for_trigger_of_table);
+		COMPLETE_WITH_QUERY(Query_for_trigger_of_table, "");
 	}
 	else if (Matches6("ALTER", "TABLE", MatchAny, "ENABLE", MatchAny, "TRIGGER"))
 	{
 		completion_info_charp = prev4_wd;
-		COMPLETE_WITH_QUERY(Query_for_trigger_of_table);
+		COMPLETE_WITH_QUERY(Query_for_trigger_of_table, "");
 	}
 	/* ALTER TABLE xxx INHERIT */
 	else if (Matches4("ALTER", "TABLE", MatchAny, "INHERIT"))
@@ -1847,21 +1860,21 @@ psql_completion(const char *text, int start, int end)
 	else if (Matches5("ALTER", "TABLE", MatchAny, "DISABLE", "RULE"))
 	{
 		completion_info_charp = prev3_wd;
-		COMPLETE_WITH_QUERY(Query_for_rule_of_table);
+		COMPLETE_WITH_QUERY(Query_for_rule_of_table, "");
 	}
 	else if (Matches5("ALTER", "TABLE", MatchAny, "DISABLE", "TRIGGER"))
 	{
 		completion_info_charp = prev3_wd;
-		COMPLETE_WITH_QUERY(Query_for_trigger_of_table);
+		COMPLETE_WITH_QUERY(Query_for_trigger_of_table, "");
 	}
 
 	/* ALTER TABLE xxx ALTER */
 	else if (Matches4("ALTER", "TABLE", MatchAny, "ALTER"))
-		COMPLETE_WITH_ATTR(prev2_wd, " UNION SELECT 'COLUMN' UNION SELECT 'CONSTRAINT'");
+		COMPLETE_WITH_ATTR(prev2_wd, ADDLIST2("COLUMN", "CONSTRAINT"));
 
 	/* ALTER TABLE xxx RENAME */
 	else if (Matches4("ALTER", "TABLE", MatchAny, "RENAME"))
-		COMPLETE_WITH_ATTR(prev2_wd, " UNION SELECT 'COLUMN' UNION SELECT 'CONSTRAINT' UNION SELECT 'TO'");
+		COMPLETE_WITH_ATTR(prev2_wd, ADDLIST3("COLUMN", "CONSTRAINT", "TO"));
 	else if (Matches5("ALTER", "TABLE", MatchAny, "ALTER|RENAME", "COLUMN"))
 		COMPLETE_WITH_ATTR(prev3_wd, "");
 
@@ -1880,7 +1893,7 @@ psql_completion(const char *text, int start, int end)
 		COMPLETE_WITH_LIST2("COLUMN", "CONSTRAINT");
 	/*  ALTER TABLE DROP COLUMN may take IF EXISTS */
 	else if (Matches5("ALTER", "TABLE", MatchAny, "DROP", "COLUMN"))
-		COMPLETE_WITH_ATTR(prev3_wd, "UNION SELECT 'IF EXISTS'");
+		COMPLETE_WITH_ATTR(prev3_wd, ADDLIST1("IF EXISTS"));
 	/* ALTER TABLE <name> with ADD/ALTER/DROP after removing optional words */
 	else if (HeadMatches4("ALTER", "TABLE", MatchAny, "ADD|ALTER|DROP") &&
 			 MidMatchAndRemove1(4, "COLUMN") &&
@@ -1889,7 +1902,7 @@ psql_completion(const char *text, int start, int end)
 		COMPLETE_WITH_ATTR(prev2_wd, "");
 	/* If we have ALTER TABLE <sth> DROP COLUMN, provide list of columns */
 	else if (Matches5("ALTER", "TABLE", MatchAny, "DROP", "COLUMN"))
-		COMPLETE_WITH_ATTR(prev3_wd, "UNION SELECT 'IF EXISTS'");
+		COMPLETE_WITH_ATTR(prev3_wd, ADDLIST1("IF EXISTS"));
 	/* Try the same after removing optional words IF EXISTS */
 	else if (HeadMatches5("ALTER", "TABLE", MatchAny, "DROP", "COLUMN") &&
 			 MidMatchAndRemove2(5, "IF", "EXISTS") &&
@@ -1903,7 +1916,7 @@ psql_completion(const char *text, int start, int end)
 	else if (Matches5("ALTER", "TABLE", MatchAny, "ALTER|RENAME|VALIDATE", "CONSTRAINT"))
 	{
 		completion_info_charp = prev3_wd;
-		COMPLETE_WITH_QUERY(Query_for_constraint_of_table);
+		COMPLETE_WITH_QUERY(Query_for_constraint_of_table, "");
 	}
 	/*
 	 * If we have ALTER TABLE <sth> DROP CONSTRAINT,
@@ -1912,8 +1925,8 @@ psql_completion(const char *text, int start, int end)
 	else if (Matches5("ALTER", "TABLE", MatchAny, "DROP", "CONSTRAINT"))
 	{
 		completion_info_charp = prev3_wd;
-		COMPLETE_WITH_QUERY(
-			ADDLIST1(Query_for_constraint_of_table, "IF EXISTS"));
+		COMPLETE_WITH_QUERY(Query_for_constraint_of_table,
+							ADDLIST1("IF EXISTS"));
 	}
 	/* Try the same after removing optional words IF EXISTS */
 	else if (HeadMatches5("ALTER", "TABLE", MatchAny, "DROP", "CONSTRAINT") &&
@@ -1921,7 +1934,7 @@ psql_completion(const char *text, int start, int end)
 			 Matches5("ALTER", "TABLE", MatchAny, "DROP", "CONSTRAINT"))
 	{
 		completion_info_charp = prev3_wd;
-		COMPLETE_WITH_QUERY(Query_for_constraint_of_table);
+		COMPLETE_WITH_QUERY(Query_for_constraint_of_table, "");
 	}
 	/* ALTER TABLE ALTER [COLUMN] <foo> */
 	else if (Matches6("ALTER", "TABLE", MatchAny, "ALTER", "COLUMN", MatchAny) ||
@@ -1948,7 +1961,7 @@ psql_completion(const char *text, int start, int end)
 	else if (Matches5("ALTER", "TABLE", MatchAny, "CLUSTER", "ON"))
 	{
 		completion_info_charp = prev3_wd;
-		COMPLETE_WITH_QUERY(Query_for_index_of_table);
+		COMPLETE_WITH_QUERY(Query_for_index_of_table, "");
 	}
 	/* If we have ALTER TABLE <sth> SET, provide list of attributes and '(' */
 	else if (Matches4("ALTER", "TABLE", MatchAny, "SET"))
@@ -1960,7 +1973,7 @@ psql_completion(const char *text, int start, int end)
 	 * tablespaces
 	 */
 	else if (Matches5("ALTER", "TABLE", MatchAny, "SET", "TABLESPACE"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
+		COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces, "");
 	/* If we have ALTER TABLE <sth> SET WITH provide OIDS */
 	else if (Matches5("ALTER", "TABLE", MatchAny, "SET", "WITH"))
 		COMPLETE_WITH_CONST("OIDS");
@@ -2011,7 +2024,7 @@ psql_completion(const char *text, int start, int end)
 	else if (Matches7("ALTER", "TABLE", MatchAny, "REPLICA", "IDENTITY", "USING", "INDEX"))
 	{
 		completion_info_charp = prev5_wd;
-		COMPLETE_WITH_QUERY(Query_for_index_of_table);
+		COMPLETE_WITH_QUERY(Query_for_index_of_table, "");
 	}
 	else if (Matches6("ALTER", "TABLE", MatchAny, "REPLICA", "IDENTITY", "USING"))
 		COMPLETE_WITH_CONST("INDEX");
@@ -2076,7 +2089,7 @@ psql_completion(const char *text, int start, int end)
 	else if (Matches5("ALTER", "TYPE", MatchAny, "ALTER|RENAME", "ATTRIBUTE"))
 		COMPLETE_WITH_ATTR(prev3_wd, "");
 	else if (Matches5("ALTER", "TYPE", MatchAny, "DROP", "ATTRIBUTE"))
-		COMPLETE_WITH_ATTR(prev3_wd, " UNION SELECT 'IF EXISTS'");
+		COMPLETE_WITH_ATTR(prev3_wd, ADDLIST1("IF EXISTS"));
 	/* Remove optional words IF EXISTS */
 	else if (HeadMatches5("ALTER", "TYPE", MatchAny, "DROP", "ATTRIBUTE") &&
 			 MidMatchAndRemove2(5, "IF", "EXISTS") &&
@@ -2091,7 +2104,7 @@ psql_completion(const char *text, int start, int end)
 		COMPLETE_WITH_CONST("USER");
 	/* complete ALTER GROUP <foo> ADD|DROP USER with a user name */
 	else if (Matches5("ALTER", "GROUP", MatchAny, "ADD|DROP", "USER"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_roles);
+		COMPLETE_WITH_QUERY(Query_for_list_of_roles, "");
 
 /* BEGIN, END, ABORT */
 	else if (Matches1("BEGIN|END|ABORT"))
@@ -2108,9 +2121,9 @@ psql_completion(const char *text, int start, int end)
 /* CLUSTER */
 	else if (Matches1("CLUSTER"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
-								   ADDLIST1("", "VERBOSE"));
+								   ADDLIST1("VERBOSE"));
 	else if (Matches2("CLUSTER", "VERBOSE"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, "");
 	/* If we have CLUSTER <sth>, then add "USING" */
 	else if (Matches2("CLUSTER", MatchAnyExcept("VERBOSE|ON")))
 		COMPLETE_WITH_CONST("USING");
@@ -2122,7 +2135,7 @@ psql_completion(const char *text, int start, int end)
 			 Matches4("CLUSTER", "VERBOSE", MatchAny, "USING"))
 	{
 		completion_info_charp = prev2_wd;
-		COMPLETE_WITH_QUERY(Query_for_index_of_table);
+		COMPLETE_WITH_QUERY(Query_for_index_of_table, "");
 	}
 
 /* COMMENT */
@@ -2145,18 +2158,18 @@ psql_completion(const char *text, int start, int end)
 	else if (Matches4("COMMENT", "ON", "TEXT", "SEARCH"))
 		COMPLETE_WITH_LIST4("CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE");
 	else if (Matches3("COMMENT", "ON", "CONSTRAINT"))
-		COMPLETE_WITH_QUERY(Query_for_all_table_constraints);
+		COMPLETE_WITH_QUERY(Query_for_all_table_constraints, "");
 	else if (Matches4("COMMENT", "ON", "CONSTRAINT", MatchAny))
 		COMPLETE_WITH_CONST("ON");
 	else if (Matches5("COMMENT", "ON", "CONSTRAINT", MatchAny, "ON"))
 	{
 		completion_info_charp = prev2_wd;
-		COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_constraint);
+		COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_constraint, "");
 	}
 	else if (Matches4("COMMENT", "ON", "MATERIALIZED", "VIEW"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, "");
 	else if (Matches4("COMMENT", "ON", "EVENT", "TRIGGER"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_event_triggers);
+		COMPLETE_WITH_QUERY(Query_for_list_of_event_triggers, "");
 	else if (Matches4("COMMENT", "ON", MatchAny, MatchAnyExcept("IS")) ||
 		Matches5("COMMENT", "ON", MatchAny, MatchAny, MatchAnyExcept("IS")) ||
 			 Matches6("COMMENT", "ON", MatchAny, MatchAny, MatchAny, MatchAnyExcept("IS")))
@@ -2170,10 +2183,10 @@ psql_completion(const char *text, int start, int end)
 	 */
 	else if (Matches1("COPY|\\copy"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
-								   ADDLIST1("", "("));
+								   ADDLIST1("("));
 	/* If we have COPY BINARY, complete with list of tables */
 	else if (Matches2("COPY", "BINARY"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
 	/* If we have COPY (, complete it with legal commands */
 	else if (Matches2("COPY|\\copy", "("))
 		COMPLETE_WITH_LIST7("SELECT", "TABLE", "VALUES", "INSERT", "UPDATE", "DELETE", "WITH");
@@ -2185,7 +2198,7 @@ psql_completion(const char *text, int start, int end)
 	else if (Matches3("COPY|\\copy", MatchAny, "FROM|TO") ||
 			 Matches4("COPY", "BINARY", MatchAny, "FROM|TO"))
 	{
-		completion_charp = "";
+		SET_COMP_CHARP("");
 		matches = completion_matches(text, complete_from_files);
 	}
 
@@ -2220,18 +2233,18 @@ psql_completion(const char *text, int start, int end)
 							"LC_COLLATE", "LC_CTYPE");
 
 	else if (Matches4("CREATE", "DATABASE", MatchAny, "TEMPLATE"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_template_databases);
+		COMPLETE_WITH_QUERY(Query_for_list_of_template_databases, "");
 
 	/* CREATE EXTENSION */
 	/* Complete with available extensions rather than installed ones. */
 	else if (Matches2("CREATE", "EXTENSION"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_available_extensions
-							" UNION SELECT 'IF NOT EXISTS'");
+		COMPLETE_WITH_QUERY(Query_for_list_of_available_extensions,
+							ADDLIST1("IF NOT EXISTS"));
 	/* Try the same after removing optional words IF NOT EXISTS */
 	else if (HeadMatches2("CREATE", "EXTENSION") &&
 			 MidMatchAndRemove3(2, "IF", "NOT", "EXISTS") &&
 			 Matches2("CREATE", "EXTENSION"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_available_extensions);
+		COMPLETE_WITH_QUERY(Query_for_list_of_available_extensions, "");
 	/* CREATE EXTENSION <name> */
 	else if (Matches3("CREATE", "EXTENSION", MatchAny))
 		COMPLETE_WITH_LIST3("WITH SCHEMA", "CASCADE", "VERSION");
@@ -2239,7 +2252,7 @@ psql_completion(const char *text, int start, int end)
 	else if (Matches4("CREATE", "EXTENSION", MatchAny, "VERSION"))
 	{
 		completion_info_charp = prev2_wd;
-		COMPLETE_WITH_QUERY(Query_for_list_of_available_extension_versions);
+		COMPLETE_WITH_QUERY(Query_for_list_of_available_extension_versions, "");
 	}
 
 	/* CREATE FOREIGN */
@@ -2249,7 +2262,7 @@ psql_completion(const char *text, int start, int end)
 	/* CREATE FOREIGN TABLE */
 	else if (Matches3("CREATE", "FOREIGN", "TABLE"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_foreign_tables,
-								   ADDLIST1("", "IF NOT EXISTS"));
+								   ADDLIST1("IF NOT EXISTS"));
 	/* Remove optional words IF NOT EXISTS */
 	else if (HeadMatches3("CREATE", "FOREIGN", "TABLE") &&
 			 MidMatchAndRemove3(3, "IF", "NOT", "EXISTS") &&
@@ -2270,12 +2283,12 @@ psql_completion(const char *text, int start, int end)
 			 MidMatchAndRemove1(1, "UNIQUE") &&
 			 Matches2("CREATE", "INDEX"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes,
-				   ADDLIST3("", "ON", "CONCURRENTLY", "IF NOT EXISTS"));
+				   ADDLIST3("ON", "CONCURRENTLY", "IF NOT EXISTS"));
 	/* Complete CREATE INDEX CONCURRENTLY with "ON" or IF NOT EXISTS and
 	 * existing indexes */
 	else if (Matches3("CREATE", "INDEX", "CONCURRENTLY"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes,
-								   ADDLIST2("", "IF NOT EXISTS", "ON"));
+								   ADDLIST2("IF NOT EXISTS", "ON"));
 
 	/* Remove optional words "CONCURRENTLY",  "IF NOT EXISTS" */
 	else if (HeadMatches2("CREATE", "INDEX") &&
@@ -2286,7 +2299,7 @@ psql_completion(const char *text, int start, int end)
 	/* Complete CREATE INDEX [<name>] ON with a list of tables */
 	else if (Matches4("CREATE", "INDEX", MatchAny, "ON") ||
 			 Matches3("CREATE", "INDEX", "ON"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, "");
 
 	/* Complete CREATE INDEX <sth> with "ON" */
 	else if (Matches3("CREATE", "INDEX", MatchAny))
@@ -2308,7 +2321,7 @@ psql_completion(const char *text, int start, int end)
 	/* Complete USING with an index method */
 	else if (TailMatches5("INDEX", MatchAny, "ON", MatchAny, "USING") ||
 			 TailMatches4("INDEX", "ON", MatchAny, "USING"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_access_methods);
+		COMPLETE_WITH_QUERY(Query_for_list_of_access_methods, "");
 	else if (TailMatches4("ON", MatchAny, "USING", MatchAny) &&
 			 !TailMatches6("POLICY", MatchAny, MatchAny, MatchAny, MatchAny, MatchAny) &&
 			 !TailMatches4("FOR", MatchAny, MatchAny, MatchAny))
@@ -2320,7 +2333,7 @@ psql_completion(const char *text, int start, int end)
 		COMPLETE_WITH_CONST("ON");
 	/* Complete "CREATE POLICY <name> ON <table>" */
 	else if (Matches4("CREATE", "POLICY", MatchAny, "ON"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
 	/* Complete "CREATE POLICY <name> ON <table> FOR|TO|USING|WITH CHECK" */
 	else if (Matches5("CREATE", "POLICY", MatchAny, "ON", MatchAny))
 		COMPLETE_WITH_LIST4("FOR", "TO", "USING (", "WITH CHECK (");
@@ -2338,7 +2351,7 @@ psql_completion(const char *text, int start, int end)
 		COMPLETE_WITH_LIST3("TO", "USING (", "WITH CHECK (");
 	/* Complete "CREATE POLICY <name> ON <table> TO <role>" */
 	else if (Matches6("CREATE", "POLICY", MatchAny, "ON", MatchAny, "TO"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
+		COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles, "");
 	/* Complete "CREATE POLICY <name> ON <table> USING (" */
 	else if (Matches6("CREATE", "POLICY", MatchAny, "ON", MatchAny, "USING"))
 		COMPLETE_WITH_CONST("(");
@@ -2358,7 +2371,7 @@ psql_completion(const char *text, int start, int end)
 		COMPLETE_WITH_CONST("TO");
 	/* Complete "AS ON <sth> TO" with a table name */
 	else if (TailMatches4("AS", "ON", "SELECT|UPDATE|INSERT|DELETE", "TO"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
 
 /* CREATE SEQUENCE, removing optional words TEMPORARY/TEMP */
 	else if (HeadMatches3("CREATE", MatchAny, "SEQUENCE") &&
@@ -2379,8 +2392,8 @@ psql_completion(const char *text, int start, int end)
 
 /* CREATE SCHEMA <name> */
 	else if (Matches2("CREATE", "SCHEMA"))
-		COMPLETE_WITH_QUERY(
-			ADDLIST1(Query_for_list_of_schemas, "IF NOT EXISTS"));
+		COMPLETE_WITH_QUERY(Query_for_list_of_schemas,
+							ADDLIST1("IF NOT EXISTS"));
 	/* Remove optional words IF NOT EXISTS */
 	else if (HeadMatches2("CREATE", "SCHEMA") &&
 			 MidMatchAndRemove3(2, "IF", "NOT", "EXISTS") &&
@@ -2399,7 +2412,7 @@ psql_completion(const char *text, int start, int end)
 			 MidMatchAndRemove1(1, "TEMP|TEMPORARY|UNLOGGED") &&
 			 Matches2("CREATE", "TABLE"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
-								   ADDLIST1("", "IF NOT EXISTS"));
+								   ADDLIST1("IF NOT EXISTS"));
 
 	/* Remove optional words here */
 	else if (HeadMatches2("CREATE", "TABLE") &&
@@ -2439,10 +2452,10 @@ psql_completion(const char *text, int start, int end)
 	 * tables
 	 */
 	else if (TailMatches6("CREATE", "TRIGGER", MatchAny, "BEFORE|AFTER", MatchAny, "ON"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
 	/* complete CREATE TRIGGER ... INSTEAD OF event ON with a list of views */
 	else if (TailMatches7("CREATE", "TRIGGER", MatchAny, "INSTEAD", "OF", MatchAny, "ON"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, "");
 	/* complete CREATE TRIGGER ... EXECUTE with PROCEDURE */
 	else if (HeadMatches2("CREATE", "TRIGGER") && TailMatches1("EXECUTE"))
 		COMPLETE_WITH_CONST("PROCEDURE");
@@ -2490,7 +2503,7 @@ psql_completion(const char *text, int start, int end)
 /* CREATE VIEW  */
 	else if (Matches2("CREATE", "VIEW"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views,
-								   ADDLIST1("", "IF NOT EXISTS"));
+								   ADDLIST1("IF NOT EXISTS"));
 	/* CREATE VIEW <name> with AS after removing optional words */
 	else if (HeadMatches2("CREATE", "VIEW") &&
 			 MidMatchAndRemove3(2, "IF", "NOT", "EXISTS") &&
@@ -2505,13 +2518,13 @@ psql_completion(const char *text, int start, int end)
 		COMPLETE_WITH_CONST("VIEW");
 	else if (Matches3("CREATE", "MATERIALIZED", "VIEW"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews,
-								   ADDLIST1("", "IF NOT EXISTS"));
+								   ADDLIST1("IF NOT EXISTS"));
 	/* Try the same after removing optional words IF NOT EXISTS. VIEW will be
 	 * completed afterwards */
 	else if (HeadMatches3("CREATE", "MATERIALIZED", "VIEW") &&
 			 MidMatchAndRemove3(3, "IF", "NOT", "EXISTS") &&
 			 Matches3("CREATE", "MATERIALIZED", "VIEW"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, "");
 	/* Complete CREATE MATERIALIZED VIEW <name> with AS */
 	else if (Matches4("CREATE", "MATERIALIZED", "VIEW", MatchAny))
 		COMPLETE_WITH_CONST("AS");
@@ -2542,7 +2555,7 @@ psql_completion(const char *text, int start, int end)
 		COMPLETE_WITH_CONST("FROM");
 	/* Complete DELETE FROM with a list of tables */
 	else if (TailMatches2("DELETE", "FROM"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_updatables, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_updatables, "");
 	/* Complete DELETE FROM <table> */
 	else if (TailMatches3("DELETE", "FROM", MatchAny))
 		COMPLETE_WITH_LIST2("USING", "WHERE");
@@ -2573,10 +2586,10 @@ psql_completion(const char *text, int start, int end)
 	/* help completing some of the variants */
 	else if (Matches2("DROP", "AGGREGATE"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_aggregates,
-								   ADDLIST1("", "IF EXISTS"));
+								   ADDLIST1("IF EXISTS"));
 	else if (Matches2("DROP", "FUNCTION"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions,
-								   ADDLIST1("", "IF EXISTS"));
+								   ADDLIST1("IF EXISTS"));
 	/* Try the same after removing optional words IF EXISTS */
 	else if (HeadMatches2("DROP", "AGGREGATE|FUNCTION") &&
 			 MidMatchAndRemove2(2, "IF", "EXISTS") &&
@@ -2587,8 +2600,8 @@ psql_completion(const char *text, int start, int end)
 	else if (Matches2("DROP", "FOREIGN"))
 		COMPLETE_WITH_LIST2("DATA WRAPPER", "TABLE");
 	else if (Matches4("DROP", "FOREIGN", "DATA", "WRAPPER"))
-		COMPLETE_WITH_QUERY(
-			ADDLIST1(Query_for_list_of_fdws, "IF EXISTS"));
+		COMPLETE_WITH_QUERY(Query_for_list_of_fdws,
+							ADDLIST1("IF EXISTS"));
 	/* Try the same after removing optional words IF EXISTS */
 	else if (HeadMatches4("DROP", "FOREIGN", "DATA", "WRAPPER") &&
 			 MidMatchAndRemove2(4, "IF", "EXISTS") &&
@@ -2597,10 +2610,10 @@ psql_completion(const char *text, int start, int end)
 	/* DROP INDEX */
 	else if (Matches2("DROP", "INDEX"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes,
-								   ADDLIST2("", "IF EXISTS","CONCURRENTLY"));
+								   ADDLIST2("IF EXISTS","CONCURRENTLY"));
 	else if (Matches3("DROP", "INDEX", "CONCURRENTLY"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes,
-								   ADDLIST1("", "IF EXISTS"));
+								   ADDLIST1("IF EXISTS"));
 	/* Try the same after optional words CONCURRENTLY and IF NOT EXISTS */
 	else if (HeadMatches2("DROP", "INDEX") &&
 			 MidMatchAndRemove1(2, "CONCURRENTLY") &&
@@ -2613,33 +2626,33 @@ psql_completion(const char *text, int start, int end)
 		COMPLETE_WITH_CONST("VIEW");
 	else if (Matches2("DROP", "VIEW"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views,
-								   ADDLIST1("", "IF EXISTS"));
+								   ADDLIST1("IF EXISTS"));
 	/* Remove optional words IF EXISTS  */
 	else if (HeadMatches2("DROP", "VIEW") &&
 			 MidMatchAndRemove2(2, "IF", "EXISTS") &&
 			 false) {} /* FALL THROUGH */
 	else if (Matches3("DROP", "MATERIALIZED", "VIEW"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews,
-								   ADDLIST1("", "IF EXISTS"));
+								   ADDLIST1("IF EXISTS"));
 	/* Try the same after removing optional words IF EXISTS */
 	else if (HeadMatches3("DROP", "MATERIALIZED", "VIEW") &&
 			 MidMatchAndRemove2(3, "IF", "EXISTS") &&
 			 Matches3("DROP", "MATERIALIZED", "VIEW"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, "");
 
 	/* DROP OWNED BY */
 	else if (Matches2("DROP", "OWNED"))
 		COMPLETE_WITH_CONST("BY");
 	else if (Matches3("DROP", "OWNED", "BY"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_roles);
+		COMPLETE_WITH_QUERY(Query_for_list_of_roles, "");
 
 	else if (Matches3("DROP", "TEXT", "SEARCH"))
 		COMPLETE_WITH_LIST4("CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE");
 
 	/* DROP TRIGGER */
 	else if (Matches2("DROP", "TRIGGER"))
-		COMPLETE_WITH_QUERY(
-			ADDLIST1(Query_for_list_of_triggers, "IF EXISTS"));
+		COMPLETE_WITH_QUERY(Query_for_list_of_triggers,
+							ADDLIST1("IF EXISTS"));
 	/* Try the same after removing optional words IF EXISTS */
 	else if (HeadMatches2("DROP", "TRIGGER") &&
 			 MidMatchAndRemove2(2, "IF", "EXISTS") &&
@@ -2648,7 +2661,7 @@ psql_completion(const char *text, int start, int end)
 	else if (Matches4("DROP", "TRIGGER", MatchAny, "ON"))
 	{
 		completion_info_charp = prev2_wd;
-		COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_trigger);
+		COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_trigger, "");
 	}
 	else if (Matches5("DROP", "TRIGGER", MatchAny, "ON", MatchAny))
 		COMPLETE_WITH_LIST2("CASCADE", "RESTRICT");
@@ -2657,23 +2670,23 @@ psql_completion(const char *text, int start, int end)
 	else if (Matches2("DROP", "EVENT"))
 		COMPLETE_WITH_CONST("TRIGGER");
 	else if (Matches3("DROP", "EVENT", "TRIGGER"))
-		COMPLETE_WITH_QUERY(
-			ADDLIST1(Query_for_list_of_event_triggers, "IF EXISTS"));
+		COMPLETE_WITH_QUERY(Query_for_list_of_event_triggers,
+							ADDLIST1("IF EXISTS"));
 	/* Trye the same after removing optional words IF EXISTS */
 	else if (HeadMatches3("DROP", "EVENT", "TRIGGER") &&
 			 MidMatchAndRemove2(3, "IF", "EXISTS") &&
 			 Matches3("DROP", "EVENT", "TRIGGER"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_event_triggers);
+		COMPLETE_WITH_QUERY(Query_for_list_of_event_triggers, "");
 
 	/* DROP POLICY */
 	else if (Matches2("DROP", "POLICY"))
-		COMPLETE_WITH_QUERY(
-			ADDLIST1(Query_for_list_of_policies, "IF EXISTS"));
+		COMPLETE_WITH_QUERY(Query_for_list_of_policies,
+							ADDLIST1("IF EXISTS"));
 	/* Try the same after after removing optional words IF EXISTS */
 	else if (HeadMatches2("DROP", "POLICY") &&
 			 MidMatchAndRemove2(2, "IF", "EXISTS") &&
 			 Matches2("DROP", "POLICY"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_policies);
+		COMPLETE_WITH_QUERY(Query_for_list_of_policies, "");
 	/* DROP POLICY <name> */
 	else if (Matches3("DROP", "POLICY", MatchAny))
 		COMPLETE_WITH_CONST("ON");
@@ -2681,13 +2694,13 @@ psql_completion(const char *text, int start, int end)
 	else if (Matches4("DROP", "POLICY", MatchAny, "ON"))
 	{
 		completion_info_charp = prev2_wd;
-		COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_policy);
+		COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_policy, "");
 	}
 
 	/* DROP RULE */
 	else if (Matches2("DROP", "RULE"))
-		COMPLETE_WITH_QUERY(
-			ADDLIST1(Query_for_list_of_rules, "IF EXISTS"));
+		COMPLETE_WITH_QUERY(Query_for_list_of_rules,
+							ADDLIST1("IF EXISTS"));
 	/* DROP RULE <name>, after removing optional words IF EXISTS */
 	else if (HeadMatches2("DROP", "RULE") &&
 			 MidMatchAndRemove2(2, "IF", "EXISTS") &&
@@ -2696,7 +2709,7 @@ psql_completion(const char *text, int start, int end)
 	else if (Matches4("DROP", "RULE", MatchAny, "ON"))
 	{
 		completion_info_charp = prev2_wd;
-		COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_rule);
+		COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_rule, "");
 	}
 	else if (Matches5("DROP", "RULE", MatchAny, "ON", MatchAny))
 		COMPLETE_WITH_LIST2("CASCADE", "RESTRICT");
@@ -2711,15 +2724,15 @@ psql_completion(const char *text, int start, int end)
 
 	{
 		const pgsql_thing_t *ent = find_thing_entry(prev_wd);
-		char *addition = " UNION SELECT 'IF EXISTS'";
+		char *addition = ADDLIST1("IF EXISTS");
 
 		if (ent)
 		{
 			/* Completing USER needs special treat */
 			if (pg_strcasecmp(prev_wd, "USER") == 0)
 			{
-				COMPLETE_WITH_QUERY(
-					ADDLIST2(Query_for_list_of_roles, "MAPPING", "IF EXISTS"));
+				COMPLETE_WITH_QUERY(Query_for_list_of_roles,
+									ADDLIST2("MAPPING", "IF EXISTS"));
 			}
 			else if (ent->query)
 			{
@@ -2727,12 +2740,12 @@ psql_completion(const char *text, int start, int end)
 									  strlen(addition) + 1);
 				strcpy(buf, ent->query);
 				strcat(buf, addition);
-				COMPLETE_WITH_QUERY(buf);
+				COMPLETE_WITH_QUERY(buf, "");
 				free(buf);
 			}
 			else if (ent->squery)
 				COMPLETE_WITH_SCHEMA_QUERY(*ent->squery,
-										   ADDLIST1("", "IF EXISTS"));
+										   ADDLIST1("IF EXISTS"));
 		}
 	}
 	/* Remove optional IF EXISTS from DROP */
@@ -2749,7 +2762,7 @@ psql_completion(const char *text, int start, int end)
 
 /* EXECUTE */
 	else if (Matches1("EXECUTE"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_prepared_statements);
+		COMPLETE_WITH_QUERY(Query_for_list_of_prepared_statements, "");
 
 /* EXPLAIN */
 
@@ -2786,7 +2799,7 @@ psql_completion(const char *text, int start, int end)
 	/* applies in ALTER/DROP FDW and in CREATE SERVER */
 	else if (TailMatches3("FOREIGN", "DATA", "WRAPPER") &&
 			 !TailMatches4("CREATE", MatchAny, MatchAny, MatchAny))
-		COMPLETE_WITH_QUERY(Query_for_list_of_fdws);
+		COMPLETE_WITH_QUERY(Query_for_list_of_fdws, "");
 	/* applies in CREATE SERVER */
 	else if (TailMatches4("FOREIGN", "DATA", "WRAPPER", MatchAny) &&
 			 HeadMatches2("CREATE", "SERVER"))
@@ -2794,18 +2807,17 @@ psql_completion(const char *text, int start, int end)
 
 /* FOREIGN TABLE */
 	else if (TailMatches2("FOREIGN", "TABLE"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_foreign_tables, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_foreign_tables, "");
 
 /* FOREIGN SERVER */
 	else if (TailMatches2("FOREIGN", "SERVER"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_servers);
+		COMPLETE_WITH_QUERY(Query_for_list_of_servers, "");
 
 /* GRANT && REVOKE --- is allowed inside CREATE SCHEMA, so use TailMatches */
 	/* Complete GRANT/REVOKE with a list of roles and privileges */
 	else if (TailMatches1("GRANT|REVOKE"))
-		COMPLETE_WITH_QUERY(
-			ADDLIST13(Query_for_list_of_roles,
-					  "SELECT", "INSERT", "UPDATE", "DELETE", "TRUNCATE",
+		COMPLETE_WITH_QUERY(Query_for_list_of_roles,
+			ADDLIST13("SELECT", "INSERT", "UPDATE", "DELETE", "TRUNCATE",
 					  "REFERENCES", "TRIGGER", "CREATE", "CONNECT", "TEMPORARY",
 					  "EXECUTE", "USAGE", "ALL"));
 
@@ -2836,8 +2848,7 @@ psql_completion(const char *text, int start, int end)
 	 */
 	else if (TailMatches3("GRANT|REVOKE", MatchAny, "ON"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf,
-			   ADDLIST15("",
-						 "ALL FUNCTIONS IN SCHEMA",
+			   ADDLIST15("ALL FUNCTIONS IN SCHEMA",
 						 "ALL SEQUENCES IN SCHEMA",
 						 "ALL TABLES IN SCHEMA",
 						 "DATABASE",
@@ -2869,23 +2880,23 @@ psql_completion(const char *text, int start, int end)
 	else if (TailMatches4("GRANT|REVOKE", MatchAny, "ON", MatchAny))
 	{
 		if (TailMatches1("DATABASE"))
-			COMPLETE_WITH_QUERY(Query_for_list_of_databases);
+			COMPLETE_WITH_QUERY(Query_for_list_of_databases, "");
 		else if (TailMatches1("DOMAIN"))
-			COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains, NULL);
+			COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains, "");
 		else if (TailMatches1("FUNCTION"))
-			COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
+			COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, "");
 		else if (TailMatches1("LANGUAGE"))
-			COMPLETE_WITH_QUERY(Query_for_list_of_languages);
+			COMPLETE_WITH_QUERY(Query_for_list_of_languages, "");
 		else if (TailMatches1("SCHEMA"))
-			COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
+			COMPLETE_WITH_QUERY(Query_for_list_of_schemas, "");
 		else if (TailMatches1("SEQUENCE"))
-			COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences, NULL);
+			COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences, "");
 		else if (TailMatches1("TABLE"))
-			COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf, NULL);
+			COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf, "");
 		else if (TailMatches1("TABLESPACE"))
-			COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
+			COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces, "");
 		else if (TailMatches1("TYPE"))
-			COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes, NULL);
+			COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes, "");
 		else if (TailMatches4("GRANT", MatchAny, MatchAny, MatchAny))
 			COMPLETE_WITH_CONST("TO");
 		else
@@ -2898,7 +2909,7 @@ psql_completion(const char *text, int start, int end)
 	 */
 	else if ((HeadMatches1("GRANT") && TailMatches1("TO")) ||
 			 (HeadMatches1("REVOKE") && TailMatches1("FROM")))
-		COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
+		COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles, "");
 
 	/* Complete "GRANT/REVOKE ... ON * *" with TO/FROM */
 	else if (HeadMatches1("GRANT") && TailMatches3("ON", MatchAny, MatchAny))
@@ -2949,7 +2960,7 @@ psql_completion(const char *text, int start, int end)
 		COMPLETE_WITH_CONST("INTO");
 	/* Complete INSERT INTO with table names */
 	else if (TailMatches2("INSERT", "INTO"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_updatables, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_updatables, "");
 	/* Complete "INSERT INTO <table> (" with attribute names */
 	else if (TailMatches4("INSERT", "INTO", MatchAny, "("))
 		COMPLETE_WITH_ATTR(prev2_wd, "");
@@ -2977,7 +2988,7 @@ psql_completion(const char *text, int start, int end)
 	/* Complete LOCK [TABLE] with a list of tables */
 	else if (Matches1("LOCK"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
-								   ADDLIST1("", "TABLE"));
+								   ADDLIST1("TABLE"));
 	else if (Matches2("LOCK", "TABLE"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
 
@@ -2999,7 +3010,7 @@ psql_completion(const char *text, int start, int end)
 
 /* NOTIFY --- can be inside EXPLAIN, RULE, etc */
 	else if (TailMatches1("NOTIFY"))
-		COMPLETE_WITH_QUERY("SELECT pg_catalog.quote_ident(channel) FROM pg_catalog.pg_listening_channels() AS channel WHERE substring(pg_catalog.quote_ident(channel),1,%d)='%s'");
+		COMPLETE_WITH_QUERY("SELECT pg_catalog.quote_ident(channel) FROM pg_catalog.pg_listening_channels() AS channel WHERE substring(pg_catalog.quote_ident(channel),1,%d)='%s'", "");
 
 /* OPTIONS */
 	else if (TailMatches1("OPTIONS"))
@@ -3007,7 +3018,7 @@ psql_completion(const char *text, int start, int end)
 
 /* OWNER TO  - complete with available roles */
 	else if (TailMatches2("OWNER", "TO"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_roles);
+		COMPLETE_WITH_QUERY(Query_for_list_of_roles, "");
 
 /* ORDER BY */
 	else if (TailMatches3("FROM", MatchAny, "ORDER"))
@@ -3030,11 +3041,11 @@ psql_completion(const char *text, int start, int end)
 	else if (Matches2("REASSIGN", "OWNED"))
 		COMPLETE_WITH_CONST("BY");
 	else if (Matches3("REASSIGN", "OWNED", "BY"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_roles);
+		COMPLETE_WITH_QUERY(Query_for_list_of_roles, "");
 	else if (Matches4("REASSIGN", "OWNED", "BY", MatchAny))
 		COMPLETE_WITH_CONST("TO");
 	else if (Matches5("REASSIGN", "OWNED", "BY", MatchAny, "TO"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_roles);
+		COMPLETE_WITH_QUERY(Query_for_list_of_roles, "");
 
 /* REFRESH MATERIALIZED VIEW */
 	else if (Matches1("REFRESH"))
@@ -3043,9 +3054,9 @@ psql_completion(const char *text, int start, int end)
 		COMPLETE_WITH_CONST("VIEW");
 	else if (Matches3("REFRESH", "MATERIALIZED", "VIEW"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews,
-								   ADDLIST1("", "CONCURRENTLY"));
+								   ADDLIST1("CONCURRENTLY"));
 	else if (Matches4("REFRESH", "MATERIALIZED", "VIEW", "CONCURRENTLY"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, "");
 	else if (Matches4("REFRESH", "MATERIALIZED", "VIEW", MatchAny))
 		COMPLETE_WITH_CONST("WITH");
 	else if (Matches5("REFRESH", "MATERIALIZED", "VIEW", "CONCURRENTLY", MatchAny))
@@ -3063,13 +3074,13 @@ psql_completion(const char *text, int start, int end)
 	else if (Matches1("REINDEX"))
 		COMPLETE_WITH_LIST5("TABLE", "INDEX", "SYSTEM", "SCHEMA", "DATABASE");
 	else if (Matches2("REINDEX", "TABLE"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, "");
 	else if (Matches2("REINDEX", "INDEX"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, "");
 	else if (Matches2("REINDEX", "SCHEMA"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
+		COMPLETE_WITH_QUERY(Query_for_list_of_schemas, "");
 	else if (Matches2("REINDEX", "SYSTEM|DATABASE"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_databases);
+		COMPLETE_WITH_QUERY(Query_for_list_of_databases, "");
 
 /* SECURITY LABEL */
 	else if (Matches1("SECURITY"))
@@ -3098,9 +3109,9 @@ psql_completion(const char *text, int start, int end)
 /* SET, RESET, SHOW */
 	/* Complete with a variable name */
 	else 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, "");
 	else if (Matches1("SHOW"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_show_vars);
+		COMPLETE_WITH_QUERY(Query_for_list_of_show_vars, "");
 	/* Complete "SET TRANSACTION" */
 	else if (Matches2("SET|BEGIN|START", "TRANSACTION") ||
 			 Matches2("BEGIN", "WORK") ||
@@ -3120,20 +3131,20 @@ psql_completion(const char *text, int start, int end)
 	/* SET CONSTRAINTS */
 	else if (Matches2("SET", "CONSTRAINTS"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_constraints_with_schema,
-								   ADDLIST1("", "ALL"));
+								   ADDLIST1("ALL"));
 	/* Complete SET CONSTRAINTS <foo> with DEFERRED|IMMEDIATE */
 	else if (Matches3("SET", "CONSTRAINTS", MatchAny))
 		COMPLETE_WITH_LIST2("DEFERRED", "IMMEDIATE");
 	/* Complete SET ROLE */
 	else if (Matches2("SET", "ROLE"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_roles);
+		COMPLETE_WITH_QUERY(Query_for_list_of_roles, "");
 	/* Complete SET SESSION with AUTHORIZATION or CHARACTERISTICS... */
 	else if (Matches2("SET", "SESSION"))
 		COMPLETE_WITH_LIST2("AUTHORIZATION", "CHARACTERISTICS AS TRANSACTION");
 	/* Complete SET SESSION AUTHORIZATION with username */
 	else if (Matches3("SET", "SESSION", "AUTHORIZATION"))
-		COMPLETE_WITH_QUERY(
-			ADDLIST1(Query_for_list_of_roles, "DEFAULT"));
+		COMPLETE_WITH_QUERY(Query_for_list_of_roles,
+							ADDLIST1("DEFAULT"));
 	/* Complete RESET SESSION with AUTHORIZATION */
 	else if (Matches2("RESET", "SESSION"))
 		COMPLETE_WITH_CONST("AUTHORIZATION");
@@ -3159,11 +3170,10 @@ psql_completion(const char *text, int start, int end)
 			COMPLETE_WITH_LIST(my_list);
 		}
 		else if (TailMatches2("search_path", "TO|="))
-			COMPLETE_WITH_QUERY(
-				ADDLIST1(Query_for_list_of_schemas
-						 " AND nspname not like 'pg\\_toast%%' "
-						 " AND nspname not like 'pg\\_temp%%' ",
-						 "DEFAULT"));
+			COMPLETE_WITH_QUERY(Query_for_list_of_schemas
+								" AND nspname not like 'pg\\_toast%%' "
+								" AND nspname not like 'pg\\_temp%%' ",
+								ADDLIST1("DEFAULT"));
 		else
 		{
 			/* generic, type based, GUC support */
@@ -3174,7 +3184,7 @@ psql_completion(const char *text, int start, int end)
 				char		querybuf[1024];
 
 				snprintf(querybuf, sizeof(querybuf), Query_for_enum, prev2_wd);
-				COMPLETE_WITH_QUERY(querybuf);
+				COMPLETE_WITH_QUERY(querybuf, "");
 			}
 			else if (guctype && strcmp(guctype, "bool") == 0)
 				COMPLETE_WITH_LIST9("on", "off", "true", "false", "yes", "no",
@@ -3193,26 +3203,26 @@ psql_completion(const char *text, int start, int end)
 
 /* TABLE, but not TABLE embedded in other commands */
 	else if (Matches1("TABLE"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_relations, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_relations, "");
 
 /* TABLESAMPLE */
 	else if (TailMatches1("TABLESAMPLE"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_tablesample_methods);
+		COMPLETE_WITH_QUERY(Query_for_list_of_tablesample_methods, "");
 	else if (TailMatches2("TABLESAMPLE", MatchAny))
 		COMPLETE_WITH_CONST("(");
 
 /* TRUNCATE */
 	else if (Matches1("TRUNCATE"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
 
 /* UNLISTEN */
 	else if (Matches1("UNLISTEN"))
-		COMPLETE_WITH_QUERY("SELECT pg_catalog.quote_ident(channel) FROM pg_catalog.pg_listening_channels() AS channel WHERE substring(pg_catalog.quote_ident(channel),1,%d)='%s' UNION SELECT '*'");
+		COMPLETE_WITH_QUERY("SELECT pg_catalog.quote_ident(channel) FROM pg_catalog.pg_listening_channels() AS channel WHERE substring(pg_catalog.quote_ident(channel),1,%d)='%s' UNION SELECT '*'", "");
 
 /* UPDATE --- can be inside EXPLAIN, RULE, etc */
 	/* If prev. word is UPDATE suggest a list of tables */
 	else if (TailMatches1("UPDATE"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_updatables, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_updatables, "");
 	/* Complete UPDATE <table> with "SET" */
 	else if (TailMatches2("UPDATE", MatchAny))
 		COMPLETE_WITH_CONST("SET");
@@ -3232,11 +3242,10 @@ psql_completion(const char *text, int start, int end)
 			 MidMatchAndRemove2(3, "IF", "EXISTS") &&
 			 false) {} /* FALL THROUGH */
 	else if (Matches4("CREATE", "USER", "MAPPING", "FOR"))
-		COMPLETE_WITH_QUERY(
-			ADDLIST3(Query_for_list_of_roles, 
-					 "CURRENT_USER", "PUBLIC", "USER"));
+		COMPLETE_WITH_QUERY(Query_for_list_of_roles,
+							ADDLIST3("CURRENT_USER", "PUBLIC", "USER"));
 	else if (Matches4("ALTER|DROP", "USER", "MAPPING", "FOR"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_user_mappings);
+		COMPLETE_WITH_QUERY(Query_for_list_of_user_mappings, "");
 	else if (Matches5("CREATE|ALTER|DROP", "USER", "MAPPING", "FOR", MatchAny))
 		COMPLETE_WITH_CONST("SERVER");
 	else if (Matches7("CREATE|ALTER", "USER", "MAPPING", "FOR", MatchAny, "SERVER", MatchAny))
@@ -3248,24 +3257,24 @@ psql_completion(const char *text, int start, int end)
  */
 	else if (Matches1("VACUUM"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
-		   ADDLIST4("", "FULL", "FREEZE", "ANALYZE", "VERBOSE"));
+		   ADDLIST4("FULL", "FREEZE", "ANALYZE", "VERBOSE"));
 	else if (Matches2("VACUUM", "FULL|FREEZE"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
-		   ADDLIST2("", "ANALYZE", "VERBOSE"));
+		   ADDLIST2("ANALYZE", "VERBOSE"));
 	else if (Matches3("VACUUM", "FULL|FREEZE", "ANALYZE"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
-		   ADDLIST1("", "VERBOSE"));
+		   ADDLIST1("VERBOSE"));
 	else if (Matches3("VACUUM", "FULL|FREEZE", "VERBOSE"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
-		   ADDLIST1("", "ANALYZE"));
+		   ADDLIST1("ANALYZE"));
 	else if (Matches2("VACUUM", "VERBOSE"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
-		   ADDLIST1("", "ANALYZE"));
+		   ADDLIST1("ANALYZE"));
 	else if (Matches2("VACUUM", "ANALYZE"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
-		   ADDLIST1("", "VERBOSE"));
+		   ADDLIST1("VERBOSE"));
 	else if (HeadMatches1("VACUUM"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, "");
 
 /* WITH [RECURSIVE] */
 
@@ -3279,7 +3288,7 @@ psql_completion(const char *text, int start, int end)
 /* ANALYZE */
 	/* Complete with list of tables */
 	else if (Matches1("ANALYZE"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tmf, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tmf, "");
 
 /* WHERE */
 	/* Simple case of the word before the where being the table name */
@@ -3289,11 +3298,11 @@ psql_completion(const char *text, int start, int end)
 /* ... FROM ... */
 /* TODO: also include SRF ? */
 	else if (TailMatches1("FROM") && !Matches3("COPY|\\copy", MatchAny, "FROM"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf, "");
 
 /* ... JOIN ... */
 	else if (TailMatches1("JOIN"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf, "");
 
 /* Backslash commands */
 /* TODO:  \dc \dd \dl */
@@ -3302,80 +3311,80 @@ psql_completion(const char *text, int start, int end)
 	else if (TailMatchesCS1("\\connect|\\c"))
 	{
 		if (!recognized_connection_string(text))
-			COMPLETE_WITH_QUERY(Query_for_list_of_databases);
+			COMPLETE_WITH_QUERY(Query_for_list_of_databases, "");
 	}
 	else if (TailMatchesCS2("\\connect|\\c", MatchAny))
 	{
 		if (!recognized_connection_string(prev_wd))
-			COMPLETE_WITH_QUERY(Query_for_list_of_roles);
+			COMPLETE_WITH_QUERY(Query_for_list_of_roles, "");
 	}
 	else if (TailMatchesCS1("\\da*"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_aggregates, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_aggregates, "");
 	else if (TailMatchesCS1("\\db*"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
+		COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces, "");
 	else if (TailMatchesCS1("\\dD*"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains, "");
 	else if (TailMatchesCS1("\\des*"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_servers);
+		COMPLETE_WITH_QUERY(Query_for_list_of_servers, "");
 	else if (TailMatchesCS1("\\deu*"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_user_mappings);
+		COMPLETE_WITH_QUERY(Query_for_list_of_user_mappings, "");
 	else if (TailMatchesCS1("\\dew*"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_fdws);
+		COMPLETE_WITH_QUERY(Query_for_list_of_fdws, "");
 	else if (TailMatchesCS1("\\df*"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, "");
 
 	else if (TailMatchesCS1("\\dFd*"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_ts_dictionaries);
+		COMPLETE_WITH_QUERY(Query_for_list_of_ts_dictionaries, "");
 	else if (TailMatchesCS1("\\dFp*"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_ts_parsers);
+		COMPLETE_WITH_QUERY(Query_for_list_of_ts_parsers, "");
 	else if (TailMatchesCS1("\\dFt*"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_ts_templates);
+		COMPLETE_WITH_QUERY(Query_for_list_of_ts_templates, "");
 	/* must be at end of \dF alternatives: */
 	else if (TailMatchesCS1("\\dF*"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_ts_configurations);
+		COMPLETE_WITH_QUERY(Query_for_list_of_ts_configurations, "");
 
 	else if (TailMatchesCS1("\\di*"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, "");
 	else if (TailMatchesCS1("\\dL*"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_languages);
+		COMPLETE_WITH_QUERY(Query_for_list_of_languages, "");
 	else if (TailMatchesCS1("\\dn*"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
+		COMPLETE_WITH_QUERY(Query_for_list_of_schemas, "");
 	else if (TailMatchesCS1("\\dp") || TailMatchesCS1("\\z"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf, "");
 	else if (TailMatchesCS1("\\ds*"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences, "");
 	else if (TailMatchesCS1("\\dt*"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
 	else if (TailMatchesCS1("\\dT*"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes, "");
 	else if (TailMatchesCS1("\\du*") || TailMatchesCS1("\\dg*"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_roles);
+		COMPLETE_WITH_QUERY(Query_for_list_of_roles, "");
 	else if (TailMatchesCS1("\\dv*"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, "");
 	else if (TailMatchesCS1("\\dx*"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_extensions);
+		COMPLETE_WITH_QUERY(Query_for_list_of_extensions, "");
 	else if (TailMatchesCS1("\\dm*"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, "");
 	else if (TailMatchesCS1("\\dE*"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_foreign_tables, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_foreign_tables, "");
 	else if (TailMatchesCS1("\\dy*"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_event_triggers);
+		COMPLETE_WITH_QUERY(Query_for_list_of_event_triggers, "");
 
 	/* must be at end of \d alternatives: */
 	else if (TailMatchesCS1("\\d*"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_relations, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_relations, "");
 
 	else if (TailMatchesCS1("\\ef"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, "");
 	else if (TailMatchesCS1("\\ev"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, "");
 
 	else if (TailMatchesCS1("\\encoding"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_encodings);
+		COMPLETE_WITH_QUERY(Query_for_list_of_encodings, "");
 	else if (TailMatchesCS1("\\h") || TailMatchesCS1("\\help"))
 		COMPLETE_WITH_LIST(sql_commands);
 	else if (TailMatchesCS1("\\password"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_roles);
+		COMPLETE_WITH_QUERY(Query_for_list_of_roles, "");
 	else if (TailMatchesCS1("\\pset"))
 	{
 		static const char *const my_list[] =
@@ -3435,14 +3444,14 @@ psql_completion(const char *text, int start, int end)
 			COMPLETE_WITH_LIST_CS3("default", "verbose", "terse");
 	}
 	else if (TailMatchesCS1("\\sf*"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, "");
 	else if (TailMatchesCS1("\\sv*"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, "");
 	else if (TailMatchesCS1("\\cd|\\e|\\edit|\\g|\\i|\\include|"
 							"\\ir|\\include_relative|\\o|\\out|"
 							"\\s|\\w|\\write|\\lo_import"))
 	{
-		completion_charp = "\\";
+		SET_COMP_CHARP("\\");
 		matches = completion_matches(text, complete_from_files);
 	}
 
@@ -3458,9 +3467,9 @@ psql_completion(const char *text, int start, int end)
 		if (ent)
 		{
 			if (ent->query)
-				COMPLETE_WITH_QUERY(ent->query);
+				COMPLETE_WITH_QUERY(ent->query, "");
 			else if (ent->squery)
-				COMPLETE_WITH_SCHEMA_QUERY(*ent->squery, NULL);
+				COMPLETE_WITH_SCHEMA_QUERY(*ent->squery, "");
 		}
 	}
 
@@ -3718,13 +3727,13 @@ _complete_from_query(int is_schema_query, const char *text, int state)
 							  char_length, e_text);
 
 			/* If an addon query was provided, use it */
-			if (completion_charp)
-				appendPQExpBuffer(&query_buffer, "\n%s", completion_charp);
+			if (COMPLETION_CHARP[0])
+				appendPQExpBuffer(&query_buffer, "\n%s", COMPLETION_CHARP);
 		}
 		else
 		{
 			/* completion_charp is an sprintf-style format string */
-			appendPQExpBuffer(&query_buffer, completion_charp,
+			appendPQExpBuffer(&query_buffer, COMPLETION_CHARP,
 							  char_length, e_text,
 							  e_info_charp, e_info_charp,
 							  e_info_charp2, e_info_charp2);
@@ -3839,18 +3848,17 @@ complete_from_list(const char *text, int state)
 static char *
 complete_from_const(const char *text, int state)
 {
-	Assert(completion_charp != NULL);
 	if (state == 0)
 	{
 		if (completion_case_sensitive)
-			return pg_strdup(completion_charp);
+			return pg_strdup(COMPLETION_CHARP);
 		else
 
 			/*
 			 * If case insensitive matching was requested initially, adjust
 			 * the case according to setting.
 			 */
-			return pg_strdup_keyword_case(completion_charp, text);
+			return pg_strdup_keyword_case(COMPLETION_CHARP, text);
 	}
 	else
 		return NULL;
@@ -3951,7 +3959,7 @@ complete_from_files(const char *text, int state)
 	if (state == 0)
 	{
 		/* Initialization: stash the unquoted input. */
-		unquoted_text = strtokx(text, "", NULL, "'", *completion_charp,
+		unquoted_text = strtokx(text, "", NULL, "'", COMPLETION_CHARP[0],
 								false, true, pset.encoding);
 		/* expect a NULL return for the empty string only */
 		if (!unquoted_text)
@@ -3972,7 +3980,7 @@ complete_from_files(const char *text, int state)
 		 * bother providing a macro to simplify this.
 		 */
 		ret = quote_if_needed(unquoted_match, " \t\r\n\"`",
-							  '\'', *completion_charp, pset.encoding);
+							  '\'', COMPLETION_CHARP[0], pset.encoding);
 		if (ret)
 			free(unquoted_match);
 		else
@@ -4030,7 +4038,7 @@ pg_strdup_keyword_case(const char *s, const char *ref)
 
 /* Construct codelet to append given keywords  */
 static char *
-additional_kw_query(char *prefix, const char *ref, int n, ...)
+additional_kw_query(const char *ref, int n, ...)
 {
 	va_list ap;
 	static PQExpBuffer qbuf = NULL;
@@ -4041,8 +4049,6 @@ additional_kw_query(char *prefix, const char *ref, int n, ...)
 	else
 		resetPQExpBuffer(qbuf);
 
-	appendPQExpBufferStr(qbuf, prefix);
-
 	/* Construct an additional queriy to append keywords */
 	appendPQExpBufferStr(qbuf, " UNION SELECT * FROM (VALUES ");
 
-- 
1.8.3.1

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to