agora inbox for [email protected]  
help / color / mirror / Atom feed
From: Kyotaro Horiguchi <[email protected]>
Subject: [PATCH 02/17] Make keywords' case follow to input
Date: Wed, 14 Sep 2016 12:48:16 +0900

Currently some keywords suggested 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.

COMPLETE_WITH_ATTR needs completion_charp to be appendable, so this
patch changes it to a PQExpBuffer and adjust COMPLET_WITH_* macros to
that change.

Since COMPLETE_WITH_(QUERY|SCHEMA_QUERY|ATTR) are not given addons in
most cases so each of them are split into two macros that requires
addons (suffixed by _KW) and that don't.

This leaves keywords contained in Query_for_list_of_grant_roles and
Query_for_enum, but it is another problem.
---
 src/bin/psql/tab-complete-macros.h |  75 ++++++--
 src/bin/psql/tab-complete.c        | 354 +++++++++++++++++++++----------------
 2 files changed, 259 insertions(+), 170 deletions(-)

diff --git a/src/bin/psql/tab-complete-macros.h b/src/bin/psql/tab-complete-macros.h
index 97ffcd1..e0cbf49 100644
--- a/src/bin/psql/tab-complete-macros.h
+++ b/src/bin/psql/tab-complete-macros.h
@@ -231,16 +231,46 @@
  * 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)				\
+do { \
+	SET_COMP_CHARP(query);	\
+	return completion_matches(text, complete_from_query);	\
+} while (0)
+
+/*
+ * COMPLETE_WITH_QUERY with additional keywords. Keywords are complete
+ * case-sensitively
+ */
+#define COMPLETE_WITH_QUERY_KW(query, addon)				\
 do { \
-	completion_charp = query;	\
+	SET_COMP_CHARP(query);	\
+	APPEND_COMP_CHARP(addon); \
 	return completion_matches(text, complete_from_query);	\
 } while (0)
 
-#define COMPLETE_WITH_SCHEMA_QUERY(query, addon) \
+#define COMPLETE_WITH_SCHEMA_QUERY(query) \
 do { \
 	completion_squery = &(query); \
-	completion_charp = addon; \
+	return completion_matches(text, complete_from_schema_query); \
+} while (0)
+
+/*
+ * COMPLETE_WITH_SCHEMA_QUERY with additional keywords. Keywords are complete
+ * case-sensitively
+ */
+#define COMPLETE_WITH_SCHEMA_QUERY_KW(query, addon)	\
+do { \
+	completion_squery = &(query); \
+	SET_COMP_CHARP(addon); \
 	return completion_matches(text, complete_from_schema_query); \
 } while (0)
 
@@ -260,12 +290,12 @@ do { \
 
 #define COMPLETE_WITH_CONST(string) \
 do { \
-	completion_charp = string;	\
+	SET_COMP_CHARP(string);	\
 	completion_case_sensitive = false; \
 	return completion_matches(text, complete_from_const);	\
 } while (0)
 
-#define COMPLETE_WITH_ATTR(relation, addon) \
+#define COMPLETE_WITH_ATTR_KW(relation, addon) \
 do { \
 	char   *_completion_schema; \
 	char   *_completion_table; \
@@ -278,18 +308,22 @@ 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; \
 	} \
 	return completion_matches(text, complete_from_query); \
 } while (0)
 
+#define COMPLETE_WITH_ATTR(query) COMPLETE_WITH_ATTR_KW((query), "")
+
 #define COMPLETE_WITH_ENUM_VALUE(type) \
 do { \
 	char   *_completion_schema; \
@@ -303,12 +337,12 @@ do { \
 							   false, false, pset.encoding);  \
 	if (_completion_type == NULL)\
 	{ \
-		completion_charp = Query_for_list_of_enum_values;	\
+		SET_COMP_CHARP(Query_for_list_of_enum_values);	\
 		completion_info_charp = type; \
 	} \
 	else \
 	{ \
-		completion_charp = Query_for_list_of_enum_values_with_schema;	\
+		SET_COMP_CHARP(Query_for_list_of_enum_values_with_schema);	\
 		completion_info_charp = _completion_type; \
 		completion_info_charp2 = _completion_schema; \
 	} \
@@ -328,12 +362,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; \
 	} \
@@ -425,6 +459,21 @@ do { \
 	COMPLETE_WITH_LIST_CS(list); \
 } while (0)
 
-
+#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 ADDLIST6(s1, s2, s3, s4, s5, s6)				\
+	additional_kw_query(text, 6, s1, s2, s3, s4, s5, s6)
+#define ADDLIST13(s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13) \
+	additional_kw_query(text, 13, s1, s2, s3, s4, s5, s6, s7,		\
+						s8, s9, s10, s11, s12, s13)
+#define ADDLIST15(s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15) \
+	additional_kw_query(text, 15, s1, s2, s3, s4, s5, s6, s7,		\
+						s8, s9, s10, s11, s12, s13, s14, s15)
+#define ADDLIST16(s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, s16) \
+	additional_kw_query(text, 16, s1, s2, s3, s4, s5, s6, s7,		\
+						s8, s9, s10, s11, s12, s13, s14, s15, s16)
 
 #endif   /* TAB_COMPLETE_MACROS_H */
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index 95587f7..8842dae 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -126,7 +126,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 */
@@ -500,12 +500,11 @@ static const SchemaQuery Query_for_list_of_matviews = {
 "  WHERE substring(pg_catalog.quote_ident(rolname),1,%d)='%s'"
 
 #define Query_for_list_of_grant_roles \
-" SELECT pg_catalog.quote_ident(rolname) "\
-"   FROM pg_catalog.pg_roles "\
-"  WHERE substring(pg_catalog.quote_ident(rolname),1,%d)='%s'"\
-" UNION ALL SELECT 'PUBLIC'"\
-" UNION ALL SELECT 'CURRENT_USER'"\
-" UNION ALL SELECT 'SESSION_USER'"
+	concatenate_strings( \
+		" SELECT pg_catalog.quote_ident(rolname) "	\
+		"   FROM pg_catalog.pg_roles "							\
+		"  WHERE substring(pg_catalog.quote_ident(rolname),1,%d)='%s'",	\
+		ADDLIST3("PUBLIC", "CURRENT_USER", "SESSION_USER"))
 
 /* the silly-looking length condition is just to eat up the current word */
 #define Query_for_table_owning_index \
@@ -796,6 +795,8 @@ static char **complete_from_variables(const char *text,
 static char *complete_from_files(const char *text, int state);
 
 static char *pg_strdup_keyword_case(const char *s, const char *ref);
+static char *concatenate_strings(const char *s1, const char *s2);
+static char *additional_kw_query( const char *ref, int n, ...);
 static char *escape_string(const char *text);
 static PGresult *exec_query(const char *query);
 
@@ -967,7 +968,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;
@@ -1076,8 +1078,8 @@ psql_completion_internal(const char *text, char **previous_words,
 
 	/* ALTER TABLE */
 	if (Matches2("ALTER", "TABLE"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
-								   "UNION SELECT 'ALL IN TABLESPACE'");
+		COMPLETE_WITH_SCHEMA_QUERY_KW(Query_for_list_of_tables,
+									  ADDLIST1("ALL IN TABLESPACE"));
 
 	/* ALTER something */
 	if (Matches1("ALTER"))
@@ -1193,8 +1195,8 @@ psql_completion_internal(const char *text, char **previous_words,
 
 	/* ALTER INDEX */
 	if (Matches2("ALTER", "INDEX"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes,
-								   "UNION SELECT 'ALL IN TABLESPACE'");
+		COMPLETE_WITH_SCHEMA_QUERY_KW(Query_for_list_of_indexes,
+									  ADDLIST1("ALL IN TABLESPACE"));
 	/* ALTER INDEX <name> */
 	if (Matches3("ALTER", "INDEX", MatchAny))
 		COMPLETE_WITH_LIST4("OWNER TO", "RENAME TO", "SET", "RESET");
@@ -1222,8 +1224,8 @@ psql_completion_internal(const char *text, char **previous_words,
 
 	/* ALTER MATERIALIZED VIEW */
 	if (Matches3("ALTER", "MATERIALIZED", "VIEW"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews,
-								   "UNION SELECT 'ALL IN TABLESPACE'");
+		COMPLETE_WITH_SCHEMA_QUERY_KW(Query_for_list_of_matviews,
+									  ADDLIST1("ALL IN TABLESPACE"));
 
 	/* ALTER USER,ROLE <name> */
 	if (Matches3("ALTER", "USER|ROLE", MatchAny) &&
@@ -1396,7 +1398,7 @@ psql_completion_internal(const char *text, char **previous_words,
 	 * If we have ALTER TRIGGER <sth> ON, then add the correct tablename
 	 */
 	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> */
 	if (Matches5("ALTER", "TRIGGER", MatchAny, "ON", MatchAny))
@@ -1442,10 +1444,10 @@ psql_completion_internal(const char *text, char **previous_words,
 	}
 	/* ALTER TABLE xxx INHERIT */
 	if (Matches4("ALTER", "TABLE", MatchAny, "INHERIT"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
 	/* ALTER TABLE xxx NO INHERIT */
 	if (Matches5("ALTER", "TABLE", MatchAny, "NO", "INHERIT"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
 	/* ALTER TABLE xxx DISABLE */
 	if (Matches4("ALTER", "TABLE", MatchAny, "DISABLE"))
 		COMPLETE_WITH_LIST3("ROW LEVEL SECURITY", "RULE", "TRIGGER");
@@ -1462,13 +1464,13 @@ psql_completion_internal(const char *text, char **previous_words,
 
 	/* ALTER TABLE xxx ALTER */
 	if (Matches4("ALTER", "TABLE", MatchAny, "ALTER"))
-		COMPLETE_WITH_ATTR(prev2_wd, " UNION SELECT 'COLUMN' UNION SELECT 'CONSTRAINT'");
+		COMPLETE_WITH_ATTR_KW(prev2_wd, ADDLIST2("COLUMN", "CONSTRAINT"));
 
 	/* ALTER TABLE xxx RENAME */
 	if (Matches4("ALTER", "TABLE", MatchAny, "RENAME"))
-		COMPLETE_WITH_ATTR(prev2_wd, " UNION SELECT 'COLUMN' UNION SELECT 'CONSTRAINT' UNION SELECT 'TO'");
+		COMPLETE_WITH_ATTR_KW(prev2_wd, ADDLIST3("COLUMN", "CONSTRAINT", "TO"));
 	if (Matches5("ALTER", "TABLE", MatchAny, "ALTER|RENAME", "COLUMN"))
-		COMPLETE_WITH_ATTR(prev3_wd, "");
+		COMPLETE_WITH_ATTR(prev3_wd);
 
 	/* ALTER TABLE xxx RENAME yyy */
 	if (Matches5("ALTER", "TABLE", MatchAny, "RENAME", MatchAnyExcept("CONSTRAINT|TO")))
@@ -1483,7 +1485,7 @@ psql_completion_internal(const char *text, char **previous_words,
 		COMPLETE_WITH_LIST2("COLUMN", "CONSTRAINT");
 	/* If we have ALTER TABLE <sth> DROP COLUMN, provide list of columns */
 	if (Matches5("ALTER", "TABLE", MatchAny, "DROP", "COLUMN"))
-		COMPLETE_WITH_ATTR(prev3_wd, "");
+		COMPLETE_WITH_ATTR(prev3_wd);
 
 	/*
 	 * If we have ALTER TABLE <sth> ALTER|DROP|RENAME|VALIDATE CONSTRAINT,
@@ -1634,7 +1636,7 @@ psql_completion_internal(const char *text, char **previous_words,
 	 * of attributes
 	 */
 	if (Matches5("ALTER", "TYPE", MatchAny, "ALTER|DROP|RENAME", "ATTRIBUTE"))
-		COMPLETE_WITH_ATTR(prev3_wd, "");
+		COMPLETE_WITH_ATTR(prev3_wd);
 	/* ALTER TYPE ALTER ATTRIBUTE <foo> */
 	if (Matches6("ALTER", "TYPE", MatchAny, "ALTER", "ATTRIBUTE", MatchAny))
 		COMPLETE_WITH_CONST("TYPE");
@@ -1671,9 +1673,10 @@ psql_completion_internal(const char *text, char **previous_words,
 		COMPLETE_WITH_LIST4("WORK", "TRANSACTION", "TO SAVEPOINT", "PREPARED");
 /* CLUSTER */
 	if (Matches1("CLUSTER"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, "UNION SELECT 'VERBOSE'");
+		COMPLETE_WITH_SCHEMA_QUERY_KW(Query_for_list_of_tm,
+									  ADDLIST1("VERBOSE"));
 	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" */
 	if (Matches2("CLUSTER", MatchAnyExcept("VERBOSE|ON")))
 		COMPLETE_WITH_CONST("USING");
@@ -1720,7 +1723,7 @@ psql_completion_internal(const char *text, char **previous_words,
 		COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_constraint);
 	}
 	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);
 	if (Matches4("COMMENT", "ON", "EVENT", "TRIGGER"))
 		COMPLETE_WITH_QUERY(Query_for_list_of_event_triggers);
 	if (Matches4("COMMENT", "ON", MatchAny, MatchAnyExcept("IS")) ||
@@ -1735,11 +1738,11 @@ psql_completion_internal(const char *text, char **previous_words,
 	 * backslash command).
 	 */
 	if (Matches1("COPY|\\copy"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
-								   " UNION ALL SELECT '('");
+		COMPLETE_WITH_SCHEMA_QUERY_KW(Query_for_list_of_tables,
+									  ADDLIST1("("));
 	/* If we have COPY BINARY, complete with list of tables */
 	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 */
 	if (Matches2("COPY|\\copy", "("))
 		COMPLETE_WITH_LIST7("SELECT", "TABLE", "VALUES", "INSERT", "UPDATE", "DELETE", "WITH");
@@ -1751,7 +1754,7 @@ psql_completion_internal(const char *text, char **previous_words,
 	if (Matches3("COPY|\\copy", MatchAny, "FROM|TO") ||
 			 Matches4("COPY", "BINARY", MatchAny, "FROM|TO"))
 	{
-		completion_charp = "";
+		SET_COMP_CHARP("");
 		return completion_matches(text, complete_from_files);
 	}
 
@@ -1820,21 +1823,20 @@ psql_completion_internal(const char *text, char **previous_words,
 	 * existing indexes
 	 */
 	if (TailMatches2("CREATE|UNIQUE", "INDEX"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes,
-								   " UNION SELECT 'ON'"
-								   " UNION SELECT 'CONCURRENTLY'");
+		COMPLETE_WITH_SCHEMA_QUERY_KW(Query_for_list_of_indexes,
+									  ADDLIST2("ON", "CONCURRENTLY"));
 	/* Complete ... INDEX|CONCURRENTLY [<name>] ON with a list of tables  */
 	if (TailMatches3("INDEX|CONCURRENTLY", MatchAny, "ON") ||
 			 TailMatches2("INDEX|CONCURRENTLY", "ON"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm);
 
 	/*
 	 * Complete CREATE|UNIQUE INDEX CONCURRENTLY with "ON" and existing
 	 * indexes
 	 */
 	if (TailMatches3("CREATE|UNIQUE", "INDEX", "CONCURRENTLY"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes,
-								   " UNION SELECT 'ON'");
+		COMPLETE_WITH_SCHEMA_QUERY_KW(Query_for_list_of_indexes,
+									  ADDLIST1("ON"));
 	/* Complete CREATE|UNIQUE INDEX [CONCURRENTLY] <sth> with "ON" */
 	if (TailMatches3("CREATE|UNIQUE", "INDEX", MatchAny) ||
 			 TailMatches4("CREATE|UNIQUE", "INDEX", "CONCURRENTLY", MatchAny))
@@ -1849,10 +1851,10 @@ psql_completion_internal(const char *text, char **previous_words,
 		COMPLETE_WITH_LIST2("(", "USING");
 	if (TailMatches5("INDEX", MatchAny, "ON", MatchAny, "(") ||
 		TailMatches4("INDEX|CONCURRENTLY", "ON", MatchAny, "("))
-		COMPLETE_WITH_ATTR(prev2_wd, "");
+		COMPLETE_WITH_ATTR(prev2_wd);
 	/* same if you put in USING */
 	if (TailMatches5("ON", MatchAny, "USING", MatchAny, "("))
-		COMPLETE_WITH_ATTR(prev4_wd, "");
+		COMPLETE_WITH_ATTR(prev4_wd);
 	/* Complete USING with an index method */
 	if (TailMatches6("INDEX", MatchAny, MatchAny, "ON", MatchAny, "USING") ||
 			 TailMatches5("INDEX", MatchAny, "ON", MatchAny, "USING") ||
@@ -1869,8 +1871,8 @@ psql_completion_internal(const char *text, char **previous_words,
 		COMPLETE_WITH_CONST("ON");
 	/* Complete "CREATE POLICY <name> ON <table>" */
 	if (Matches4("CREATE", "POLICY", MatchAny, "ON"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
-	/* Complete "CREATE POLICY <name> ON <table> AS|FOR|TO|USING|WITH CHECK" */
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
+	/* Complete "CREATE POLICY <name> ON <table> FOR|TO|USING|WITH CHECK" */
 	if (Matches5("CREATE", "POLICY", MatchAny, "ON", MatchAny))
 		COMPLETE_WITH_LIST5("AS", "FOR", "TO", "USING (", "WITH CHECK (");
 	/* CREATE POLICY <name> ON <table> AS PERMISSIVE|RESTRICTIVE */
@@ -1932,7 +1934,7 @@ psql_completion_internal(const char *text, char **previous_words,
 		COMPLETE_WITH_CONST("TO");
 	/* Complete "AS ON <sth> TO" with a table name */
 	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 --- is allowed inside CREATE SCHEMA, so use TailMatches */
 	if (TailMatches3("CREATE", "SEQUENCE", MatchAny) ||
@@ -1988,10 +1990,10 @@ psql_completion_internal(const char *text, char **previous_words,
 	 * tables
 	 */
 	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 */
 	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);
 	if (HeadMatches2("CREATE", "TRIGGER") && TailMatches2("ON", MatchAny))
 		COMPLETE_WITH_LIST7("NOT DEFERRABLE", "DEFERRABLE", "INITIALLY",
 							"REFERENCING", "FOR", "WHEN (", "EXECUTE PROCEDURE");
@@ -2028,7 +2030,7 @@ psql_completion_internal(const char *text, char **previous_words,
 	if (HeadMatches2("CREATE", "TRIGGER") && TailMatches1("EXECUTE"))
 		COMPLETE_WITH_CONST("PROCEDURE");
 	if (HeadMatches2("CREATE", "TRIGGER") && TailMatches2("EXECUTE", "PROCEDURE"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions);
 
 /* CREATE ROLE,USER,GROUP <name> */
 	if (Matches3("CREATE", "ROLE|GROUP|USER", MatchAny) &&
@@ -2111,7 +2113,7 @@ psql_completion_internal(const char *text, char **previous_words,
 		COMPLETE_WITH_CONST("FROM");
 	/* Complete DELETE FROM with a list of tables */
 	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> */
 	if (TailMatches3("DELETE", "FROM", MatchAny))
 		COMPLETE_WITH_LIST2("USING", "WHERE");
@@ -2149,10 +2151,10 @@ psql_completion_internal(const char *text, char **previous_words,
 
 	/* DROP INDEX */
 	if (Matches2("DROP", "INDEX"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes,
-								   " UNION SELECT 'CONCURRENTLY'");
+		COMPLETE_WITH_SCHEMA_QUERY_KW(Query_for_list_of_indexes,
+									  ADDLIST1("CONCURRENTLY"));
 	if (Matches3("DROP", "INDEX", "CONCURRENTLY"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes);
 	if (Matches3("DROP", "INDEX", MatchAny))
 		COMPLETE_WITH_LIST2("CASCADE", "RESTRICT");
 	if (Matches4("DROP", "INDEX", "CONCURRENTLY", MatchAny))
@@ -2162,7 +2164,7 @@ psql_completion_internal(const char *text, char **previous_words,
 	if (Matches2("DROP", "MATERIALIZED"))
 		COMPLETE_WITH_CONST("VIEW");
 	if (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 */
 	if (Matches2("DROP", "OWNED"))
@@ -2268,7 +2270,7 @@ psql_completion_internal(const char *text, char **previous_words,
 /* FOREIGN TABLE */
 	if (TailMatches2("FOREIGN", "TABLE") &&
 			 !TailMatches3("CREATE", MatchAny, MatchAny))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_foreign_tables, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_foreign_tables);
 
 /* FOREIGN SERVER */
 	if (TailMatches2("FOREIGN", "SERVER"))
@@ -2290,20 +2292,10 @@ psql_completion_internal(const char *text, char **previous_words,
 				"DELETE", "TRUNCATE", "REFERENCES", "TRIGGER",
 						"EXECUTE", "USAGE", "ALL");
 		else
-			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_KW(Query_for_list_of_roles,
+				   ADDLIST13("SELECT", "INSERT", "UPDATE", "DELETE", "TRUNCATE",
+							 "REFERENCES", "TRIGGER", "CREATE", "CONNECT",
+							 "TEMPORARY", "EXECUTE", "USAGE", "ALL"));
 	}
 	/*
 	 * Complete GRANT/REVOKE <privilege> with "ON", GRANT/REVOKE <role> with
@@ -2339,22 +2331,22 @@ psql_completion_internal(const char *text, char **previous_words,
 		if (HeadMatches3("ALTER","DEFAULT","PRIVILEGES"))
 			COMPLETE_WITH_LIST4("TABLES", "SEQUENCES", "FUNCTIONS", "TYPES");
 		else
-			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'");
+			COMPLETE_WITH_SCHEMA_QUERY_KW(Query_for_list_of_tsvmf,
+							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"));
 	}
 	if (TailMatches4("GRANT|REVOKE", MatchAny, "ON", "ALL"))
 		COMPLETE_WITH_LIST3("FUNCTIONS IN SCHEMA", "SEQUENCES IN SCHEMA",
@@ -2374,21 +2366,21 @@ psql_completion_internal(const char *text, char **previous_words,
 		if (TailMatches1("DATABASE"))
 			COMPLETE_WITH_QUERY(Query_for_list_of_databases);
 		if (TailMatches1("DOMAIN"))
-			COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains, NULL);
+			COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains);
 		if (TailMatches1("FUNCTION"))
-			COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
+			COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions);
 		if (TailMatches1("LANGUAGE"))
 			COMPLETE_WITH_QUERY(Query_for_list_of_languages);
 		if (TailMatches1("SCHEMA"))
 			COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
 		if (TailMatches1("SEQUENCE"))
-			COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences, NULL);
+			COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences);
 		if (TailMatches1("TABLE"))
-			COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf, NULL);
+			COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf);
 		if (TailMatches1("TABLESPACE"))
 			COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
 		if (TailMatches1("TYPE"))
-			COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes, NULL);
+			COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes);
 		if (TailMatches4("GRANT", MatchAny, MatchAny, MatchAny))
 			COMPLETE_WITH_CONST("TO");
 		else
@@ -2454,10 +2446,10 @@ psql_completion_internal(const char *text, char **previous_words,
 		COMPLETE_WITH_CONST("INTO");
 	/* Complete INSERT INTO with table names */
 	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 */
 	if (TailMatches4("INSERT", "INTO", MatchAny, "("))
-		COMPLETE_WITH_ATTR(prev2_wd, "");
+		COMPLETE_WITH_ATTR(prev2_wd);
 
 	/*
 	 * Complete INSERT INTO <table> with "(" or "VALUES" or "SELECT" or
@@ -2481,10 +2473,10 @@ psql_completion_internal(const char *text, char **previous_words,
 /* LOCK */
 	/* Complete LOCK [TABLE] with a list of tables */
 	if (Matches1("LOCK"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
-								   " UNION SELECT 'TABLE'");
+		COMPLETE_WITH_SCHEMA_QUERY_KW(Query_for_list_of_tables,
+									  ADDLIST1("TABLE"));
 	if (Matches2("LOCK", "TABLE"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
 
 	/* For the following, handle the case of a single table only for now */
 
@@ -2529,7 +2521,7 @@ psql_completion_internal(const char *text, char **previous_words,
 	if (TailMatches3("FROM", MatchAny, "ORDER"))
 		COMPLETE_WITH_CONST("BY");
 	if (TailMatches4("FROM", MatchAny, "ORDER", "BY"))
-		COMPLETE_WITH_ATTR(prev3_wd, "");
+		COMPLETE_WITH_ATTR(prev3_wd);
 
 /* PREPARE xx AS */
 	if (Matches3("PREPARE", MatchAny, "AS"))
@@ -2558,10 +2550,10 @@ psql_completion_internal(const char *text, char **previous_words,
 	if (Matches2("REFRESH", "MATERIALIZED"))
 		COMPLETE_WITH_CONST("VIEW");
 	if (Matches3("REFRESH", "MATERIALIZED", "VIEW"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews,
-								   " UNION SELECT 'CONCURRENTLY'");
+		COMPLETE_WITH_SCHEMA_QUERY_KW(Query_for_list_of_matviews,
+									  ADDLIST1("CONCURRENTLY"));
 	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);
 	if (Matches4("REFRESH", "MATERIALIZED", "VIEW", MatchAny))
 		COMPLETE_WITH_CONST("WITH");
 	if (Matches5("REFRESH", "MATERIALIZED", "VIEW", "CONCURRENTLY", MatchAny))
@@ -2579,9 +2571,9 @@ psql_completion_internal(const char *text, char **previous_words,
 	if (Matches1("REINDEX"))
 		COMPLETE_WITH_LIST5("TABLE", "INDEX", "SYSTEM", "SCHEMA", "DATABASE");
 	if (Matches2("REINDEX", "TABLE"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm);
 	if (Matches2("REINDEX", "INDEX"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes);
 	if (Matches2("REINDEX", "SCHEMA"))
 		COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
 	if (Matches2("REINDEX", "SYSTEM|DATABASE"))
@@ -2651,7 +2643,8 @@ psql_completion_internal(const char *text, char **previous_words,
 		COMPLETE_WITH_LIST2("ONLY", "WRITE");
 	/* SET CONSTRAINTS */
 	if (Matches2("SET", "CONSTRAINTS"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_constraints_with_schema, "UNION SELECT 'ALL'");
+		COMPLETE_WITH_SCHEMA_QUERY_KW(Query_for_list_of_constraints_with_schema,
+									  ADDLIST1("ALL"));
 	/* Complete SET CONSTRAINTS <foo> with DEFERRED|IMMEDIATE */
 	if (Matches3("SET", "CONSTRAINTS", MatchAny))
 		COMPLETE_WITH_LIST2("DEFERRED", "IMMEDIATE");
@@ -2663,7 +2656,8 @@ psql_completion_internal(const char *text, char **previous_words,
 		COMPLETE_WITH_LIST2("AUTHORIZATION", "CHARACTERISTICS AS TRANSACTION");
 	/* Complete SET SESSION AUTHORIZATION with username */
 	if (Matches3("SET", "SESSION", "AUTHORIZATION"))
-		COMPLETE_WITH_QUERY(Query_for_list_of_roles " UNION SELECT 'DEFAULT'");
+		COMPLETE_WITH_QUERY_KW(Query_for_list_of_roles,
+							   ADDLIST1("DEFAULT"));
 	/* Complete RESET SESSION with AUTHORIZATION */
 	if (Matches2("RESET", "SESSION"))
 		COMPLETE_WITH_CONST("AUTHORIZATION");
@@ -2689,10 +2683,10 @@ psql_completion_internal(const char *text, char **previous_words,
 			COMPLETE_WITH_LIST(my_list);
 		}
 		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_KW(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, guctype is malloc'ed */
@@ -2727,7 +2721,7 @@ psql_completion_internal(const char *text, char **previous_words,
 
 /* TABLE, but not TABLE embedded in other commands */
 	if (Matches1("TABLE"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_relations, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_relations);
 
 /* TABLESAMPLE */
 	if (TailMatches1("TABLESAMPLE"))
@@ -2737,7 +2731,7 @@ psql_completion_internal(const char *text, char **previous_words,
 
 /* TRUNCATE */
 	if (Matches1("TRUNCATE"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
 
 /* UNLISTEN */
 	if (Matches1("UNLISTEN"))
@@ -2746,13 +2740,13 @@ psql_completion_internal(const char *text, char **previous_words,
 /* UPDATE --- can be inside EXPLAIN, RULE, etc */
 	/* If prev. word is UPDATE suggest a list of tables */
 	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" */
 	if (TailMatches2("UPDATE", MatchAny))
 		COMPLETE_WITH_CONST("SET");
 	/* Complete UPDATE <table> SET with list of attributes */
 	if (TailMatches3("UPDATE", MatchAny, "SET"))
-		COMPLETE_WITH_ATTR(prev2_wd, "");
+		COMPLETE_WITH_ATTR(prev2_wd);
 	/* UPDATE <table> SET <attr> = */
 	if (TailMatches4("UPDATE", MatchAny, "SET", MatchAny))
 		COMPLETE_WITH_CONST("=");
@@ -2761,10 +2755,8 @@ psql_completion_internal(const char *text, char **previous_words,
 	if (Matches3("ALTER|CREATE|DROP", "USER", "MAPPING"))
 		COMPLETE_WITH_CONST("FOR");
 	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_KW(Query_for_list_of_roles,
+			ADDLIST3("CURRENT_USER", "PUBLIC", "USER"));
 	if (Matches4("ALTER|DROP", "USER", "MAPPING", "FOR"))
 		COMPLETE_WITH_QUERY(Query_for_list_of_user_mappings);
 	if (Matches5("CREATE|ALTER|DROP", "USER", "MAPPING", "FOR", MatchAny))
@@ -2777,29 +2769,26 @@ psql_completion_internal(const char *text, char **previous_words,
  * VACUUM [ FULL | FREEZE ] [ VERBOSE ] ANALYZE [ table [ (column [, ...] ) ] ]
  */
 	if (Matches1("VACUUM"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
-								   " UNION SELECT 'FULL'"
-								   " UNION SELECT 'FREEZE'"
-								   " UNION SELECT 'ANALYZE'"
-								   " UNION SELECT 'VERBOSE'");
+		COMPLETE_WITH_SCHEMA_QUERY_KW(Query_for_list_of_tm,
+									  ADDLIST4("FULL", "FREEZE",
+											   "ANALYZE", "VERBOSE"));
 	if (Matches2("VACUUM", "FULL|FREEZE"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
-								   " UNION SELECT 'ANALYZE'"
-								   " UNION SELECT 'VERBOSE'");
+		COMPLETE_WITH_SCHEMA_QUERY_KW(Query_for_list_of_tm,
+									  ADDLIST2("ANALYZE", "VERBOSE"));
 	if (Matches3("VACUUM", "FULL|FREEZE", "ANALYZE"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
-								   " UNION SELECT 'VERBOSE'");
+		COMPLETE_WITH_SCHEMA_QUERY_KW(Query_for_list_of_tm,
+									  ADDLIST1("VERBOSE"));
 	if (Matches3("VACUUM", "FULL|FREEZE", "VERBOSE"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
-								   " UNION SELECT 'ANALYZE'");
+		COMPLETE_WITH_SCHEMA_QUERY_KW(Query_for_list_of_tm,
+									  ADDLIST1("ANALYZE"));
 	if (Matches2("VACUUM", "VERBOSE"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
-								   " UNION SELECT 'ANALYZE'");
+		COMPLETE_WITH_SCHEMA_QUERY_KW(Query_for_list_of_tm,
+									  ADDLIST1("ANALYZE"));
 	if (Matches2("VACUUM", "ANALYZE"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm,
-								   " UNION SELECT 'VERBOSE'");
+		COMPLETE_WITH_SCHEMA_QUERY_KW(Query_for_list_of_tm,
+									  ADDLIST1("VERBOSE"));
 	if (HeadMatches1("VACUUM"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm);
 
 /* WITH [RECURSIVE] */
 
@@ -2813,21 +2802,21 @@ psql_completion_internal(const char *text, char **previous_words,
 /* ANALYZE */
 	/* Complete with list of tables */
 	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 */
 	if (TailMatches2(MatchAny, "WHERE"))
-		COMPLETE_WITH_ATTR(prev2_wd, "");
+		COMPLETE_WITH_ATTR(prev2_wd);
 
 /* ... FROM ... */
 /* TODO: also include SRF ? */
 	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 ... */
 	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 */
@@ -2844,13 +2833,13 @@ psql_completion_internal(const char *text, char **previous_words,
 			COMPLETE_WITH_QUERY(Query_for_list_of_roles);
 	}
 	if (TailMatchesCS1("\\da*"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_aggregates, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_aggregates);
 	if (TailMatchesCS1("\\dA*"))
 		COMPLETE_WITH_QUERY(Query_for_list_of_access_methods);
 	if (TailMatchesCS1("\\db*"))
 		COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
 	if (TailMatchesCS1("\\dD*"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains);
 	if (TailMatchesCS1("\\des*"))
 		COMPLETE_WITH_QUERY(Query_for_list_of_servers);
 	if (TailMatchesCS1("\\deu*"))
@@ -2858,7 +2847,7 @@ psql_completion_internal(const char *text, char **previous_words,
 	if (TailMatchesCS1("\\dew*"))
 		COMPLETE_WITH_QUERY(Query_for_list_of_fdws);
 	if (TailMatchesCS1("\\df*"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions);
 
 	if (TailMatchesCS1("\\dFd*"))
 		COMPLETE_WITH_QUERY(Query_for_list_of_ts_dictionaries);
@@ -2871,40 +2860,40 @@ psql_completion_internal(const char *text, char **previous_words,
 		COMPLETE_WITH_QUERY(Query_for_list_of_ts_configurations);
 
 	if (TailMatchesCS1("\\di*"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes);
 	if (TailMatchesCS1("\\dL*"))
 		COMPLETE_WITH_QUERY(Query_for_list_of_languages);
 	if (TailMatchesCS1("\\dn*"))
 		COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
 	if (TailMatchesCS1("\\dp") || TailMatchesCS1("\\z"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf);
 	if (TailMatchesCS1("\\ds*"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences);
 	if (TailMatchesCS1("\\dt*"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
 	if (TailMatchesCS1("\\dT*"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes);
 	if (TailMatchesCS1("\\du*") || TailMatchesCS1("\\dg*"))
 		COMPLETE_WITH_QUERY(Query_for_list_of_roles);
 	if (TailMatchesCS1("\\dv*"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views);
 	if (TailMatchesCS1("\\dx*"))
 		COMPLETE_WITH_QUERY(Query_for_list_of_extensions);
 	if (TailMatchesCS1("\\dm*"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews);
 	if (TailMatchesCS1("\\dE*"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_foreign_tables, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_foreign_tables);
 	if (TailMatchesCS1("\\dy*"))
 		COMPLETE_WITH_QUERY(Query_for_list_of_event_triggers);
 
 	/* must be at end of \d alternatives: */
 	if (TailMatchesCS1("\\d*"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_relations, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_relations);
 
 	if (TailMatchesCS1("\\ef"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions);
 	if (TailMatchesCS1("\\ev"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views);
 
 	if (TailMatchesCS1("\\encoding"))
 		COMPLETE_WITH_QUERY(Query_for_list_of_encodings);
@@ -2973,14 +2962,14 @@ psql_completion_internal(const char *text, char **previous_words,
 			COMPLETE_WITH_LIST_CS3("default", "verbose", "terse");
 	}
 	if (TailMatchesCS1("\\sf*"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions);
 	if (TailMatchesCS1("\\sv*"))
-		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL);
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views);
 	if (TailMatchesCS1("\\cd|\\e|\\edit|\\g|\\i|\\include|"
 							"\\ir|\\include_relative|\\o|\\out|"
 							"\\s|\\w|\\write|\\lo_import"))
 	{
-		completion_charp = "\\";
+		SET_COMP_CHARP("\\");
 		return completion_matches(text, complete_from_files);
 	}
 
@@ -3000,8 +2989,7 @@ psql_completion_internal(const char *text, char **previous_words,
 				if (words_after_create[i].query)
 					COMPLETE_WITH_QUERY(words_after_create[i].query);
 				if (words_after_create[i].squery)
-					COMPLETE_WITH_SCHEMA_QUERY(*words_after_create[i].squery,
-											   NULL);
+					COMPLETE_WITH_SCHEMA_QUERY(*words_after_create[i].squery);
 				break;
 			}
 		}
@@ -3248,13 +3236,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);
@@ -3369,18 +3357,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;
@@ -3481,7 +3468,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)
@@ -3502,7 +3489,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
@@ -3546,6 +3533,59 @@ pg_strdup_keyword_case(const char *s, const char *ref)
 	return ret;
 }
 
+/*
+ * Returns concatenated string.
+ * Note: the internal buffer is static so this cannot be called recursively.
+ */
+static char *
+concatenate_strings(const char *s1, const char *s2)
+{
+	static PQExpBuffer qbuf = NULL;
+
+	if (qbuf == NULL)
+		qbuf = createPQExpBuffer();
+	else
+		resetPQExpBuffer(qbuf);
+
+	appendPQExpBufferStr(qbuf, s1);
+	appendPQExpBufferStr(qbuf, s2);
+
+	return qbuf->data;
+}
+
+/* Construct codelet to append given keywords  */
+static char *
+additional_kw_query(const char *ref, int n, ...)
+{
+	va_list ap;
+	static PQExpBuffer qbuf = NULL;
+	int i;
+
+	if (qbuf == NULL)
+		qbuf = createPQExpBuffer();
+	else
+		resetPQExpBuffer(qbuf);
+
+	/* Construct an additional queriy to append keywords */
+	appendPQExpBufferStr(qbuf, " UNION ALL 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.
-- 
2.9.2


----Next_Part(Mon_Dec_26_17_40_58_2016_393)--
Content-Type: Text/X-Patch; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="0003-Introduce-word-shift-and-removal-feature-to-psql-com.patch"



view thread (8+ messages)  latest in thread

reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: [email protected]
  Cc: [email protected]
  Subject: Re: [PATCH 02/17] Make keywords' case follow to input
  In-Reply-To: <no-message-id-69812@localhost>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox