On 03/01/2017 02:47 PM, Peter Eisentraut wrote:
Instead of creating another copy of list_ALTER, let's use the words_after_create list and write a version of create_command_generator/drop_command_generator.
Good idea. Here is a patch with that. Andreas
commit 7d691929f5814da87bb8a532e7dcfa2bd1dc9f15 Author: Andreas Karlsson <andr...@proxel.se> Date: Fri Feb 3 13:05:48 2017 +0100 Add compleition for \help DROP|ALTER diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index e8458e939e..3df7636c5b 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -982,10 +982,11 @@ typedef struct #define THING_NO_CREATE (1 << 0) /* should not show up after CREATE */ #define THING_NO_DROP (1 << 1) /* should not show up after DROP */ -#define THING_NO_SHOW (THING_NO_CREATE | THING_NO_DROP) +#define THING_NO_ALTER (1 << 2) /* should not show up after ALTER */ +#define THING_NO_SHOW (THING_NO_CREATE | THING_NO_DROP | THING_NO_ALTER) static const pgsql_thing_t words_after_create[] = { - {"ACCESS METHOD", NULL, NULL}, + {"ACCESS METHOD", NULL, NULL, THING_NO_ALTER}, {"AGGREGATE", NULL, &Query_for_list_of_aggregates}, {"CAST", NULL, NULL}, /* Casts have complex structures for names, so * skip it */ @@ -999,6 +1000,7 @@ static const pgsql_thing_t words_after_create[] = { {"CONVERSION", "SELECT pg_catalog.quote_ident(conname) FROM pg_catalog.pg_conversion WHERE substring(pg_catalog.quote_ident(conname),1,%d)='%s'"}, {"DATABASE", Query_for_list_of_databases}, {"DICTIONARY", Query_for_list_of_ts_dictionaries, NULL, THING_NO_SHOW}, + {"DEFAULT PRIVILEGES", NULL, NULL, THING_NO_CREATE | THING_NO_DROP}, {"DOMAIN", NULL, &Query_for_list_of_domains}, {"EVENT TRIGGER", NULL, NULL}, {"EXTENSION", Query_for_list_of_extensions}, @@ -1006,12 +1008,13 @@ static const pgsql_thing_t words_after_create[] = { {"FOREIGN TABLE", NULL, NULL}, {"FUNCTION", NULL, &Query_for_list_of_functions}, {"GROUP", Query_for_list_of_roles}, - {"LANGUAGE", Query_for_list_of_languages}, {"INDEX", NULL, &Query_for_list_of_indexes}, + {"LANGUAGE", Query_for_list_of_languages, NULL, THING_NO_ALTER}, + {"LARGE OBJECT", NULL, NULL, THING_NO_CREATE | THING_NO_DROP}, {"MATERIALIZED VIEW", NULL, &Query_for_list_of_matviews}, {"OPERATOR", NULL, NULL}, /* Querying for this is probably not such a * good idea. */ - {"OWNED", NULL, NULL, THING_NO_CREATE}, /* for DROP OWNED BY ... */ + {"OWNED", NULL, NULL, THING_NO_CREATE | THING_NO_ALTER}, /* for DROP OWNED BY ... */ {"PARSER", Query_for_list_of_ts_parsers, NULL, THING_NO_SHOW}, {"POLICY", NULL, NULL}, {"PUBLICATION", Query_for_list_of_publications}, @@ -1021,15 +1024,16 @@ static const pgsql_thing_t words_after_create[] = { {"SEQUENCE", NULL, &Query_for_list_of_sequences}, {"SERVER", Query_for_list_of_servers}, {"SUBSCRIPTION", Query_for_list_of_subscriptions}, + {"SYSTEM", NULL, NULL, THING_NO_CREATE | THING_NO_DROP}, {"TABLE", NULL, &Query_for_list_of_tables}, {"TABLESPACE", Query_for_list_of_tablespaces}, - {"TEMP", NULL, NULL, THING_NO_DROP}, /* for CREATE TEMP TABLE ... */ + {"TEMP", NULL, NULL, THING_NO_DROP | THING_NO_ALTER}, /* 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"}, {"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 + {"UNIQUE", NULL, NULL, THING_NO_DROP | THING_NO_ALTER}, /* for CREATE UNIQUE INDEX ... */ + {"UNLOGGED", NULL, NULL, THING_NO_DROP | THING_NO_ALTER}, /* for CREATE UNLOGGED TABLE * ... */ {"USER", Query_for_list_of_roles}, {"USER MAPPING FOR", NULL, NULL}, @@ -1042,6 +1046,7 @@ static const pgsql_thing_t words_after_create[] = { static char **psql_completion(const char *text, int start, int end); static char *create_command_generator(const char *text, int state); static char *drop_command_generator(const char *text, int state); +static char *alter_command_generator(const char *text, int state); static char *complete_from_query(const char *text, int state); static char *complete_from_schema_query(const char *text, int state); static char *_complete_from_query(int is_schema_query, @@ -1316,6 +1321,17 @@ psql_completion(const char *text, int start, int end) (previous_words_count >= 2 && \ word_matches_cs(p1, prev_wd) && \ word_matches_cs(p2, prev2_wd)) +#define TailMatchesCS3(p3, p2, p1) \ + (previous_words_count >= 3 && \ + word_matches_cs(p1, prev_wd) && \ + word_matches_cs(p2, prev2_wd) && \ + word_matches_cs(p3, prev3_wd)) +#define TailMatchesCS4(p4, p3, p2, p1) \ + (previous_words_count >= 4 && \ + word_matches_cs(p1, prev_wd) && \ + word_matches_cs(p2, prev2_wd) && \ + word_matches_cs(p3, prev3_wd) && \ + word_matches_cs(p4, prev4_wd)) /* * Macros for matching N words beginning at the start of the line, @@ -1459,17 +1475,7 @@ psql_completion(const char *text, int start, int end) /* ALTER something */ else if (Matches1("ALTER")) - { - static const char *const list_ALTER[] = - {"AGGREGATE", "COLLATION", "CONVERSION", "DATABASE", "DEFAULT PRIVILEGES", "DOMAIN", - "EVENT TRIGGER", "EXTENSION", "FOREIGN DATA WRAPPER", "FOREIGN TABLE", "FUNCTION", - "GROUP", "INDEX", "LANGUAGE", "LARGE OBJECT", "MATERIALIZED VIEW", "OPERATOR", - "POLICY", "PUBLICATION", "ROLE", "RULE", "SCHEMA", "SERVER", "SEQUENCE", - "SUBSCRIPTION", "SYSTEM", "TABLE", "TABLESPACE", "TEXT SEARCH", "TRIGGER", "TYPE", - "USER", "USER MAPPING FOR", "VIEW", NULL}; - - COMPLETE_WITH_LIST(list_ALTER); - } + matches = completion_matches(text, alter_command_generator); /* ALTER TABLE,INDEX,MATERIALIZED VIEW ALL IN TABLESPACE xxx */ else if (TailMatches4("ALL", "IN", "TABLESPACE", MatchAny)) COMPLETE_WITH_LIST2("SET TABLESPACE", "OWNED BY"); @@ -3353,8 +3359,41 @@ psql_completion(const char *text, int start, int end) else if (TailMatchesCS1("\\encoding")) COMPLETE_WITH_QUERY(Query_for_list_of_encodings); - else if (TailMatchesCS1("\\h") || TailMatchesCS1("\\help")) + else if (TailMatchesCS1("\\h|\\help")) COMPLETE_WITH_LIST(sql_commands); + else if (TailMatchesCS2("\\h|\\help", MatchAny)) + { + if (TailMatches1("DROP")) + matches = completion_matches(text, drop_command_generator); + else if (TailMatches1("ALTER")) + matches = completion_matches(text, alter_command_generator); + } + else if (TailMatchesCS3("\\h|\\help", MatchAny, MatchAny)) + { + if (TailMatches2("DROP", "ACCESS")) + COMPLETE_WITH_CONST("METHOD"); + else if (TailMatches2("ALTER", "DEFAULT")) + COMPLETE_WITH_CONST("PRIVILEGES"); + else if (TailMatches2("ALTER|DROP", "EVENT")) + COMPLETE_WITH_CONST("TRIGGER"); + else if (TailMatches2("ALTER|DROP", "FOREIGN")) + COMPLETE_WITH_LIST2("DATA WRAPPER", "TABLE"); + else if (TailMatches2("ALTER", "LARGE")) + COMPLETE_WITH_CONST("OBJECT"); + else if (TailMatches2("ALTER|DROP", "MATERIALIZED")) + COMPLETE_WITH_CONST("VIEW"); + else if (TailMatches2("ALTER|DROP", "TEXT")) + COMPLETE_WITH_CONST("SEARCH"); + else if (TailMatches2("ALTER|DROP", "USER")) + COMPLETE_WITH_CONST("MAPPING FOR"); + } + else if (TailMatchesCS4("\\h|\\help", MatchAny, MatchAny, MatchAny)) + { + if (TailMatches3("ALTER|DROP", "FOREIGN", "DATA")) + COMPLETE_WITH_CONST("WRAPPER"); + else if (TailMatches3("ALTER|DROP", "USER", "MAPPING")) + COMPLETE_WITH_CONST("FOR"); + } else if (TailMatchesCS1("\\l*") && !TailMatchesCS1("\\lo*")) COMPLETE_WITH_QUERY(Query_for_list_of_databases); else if (TailMatchesCS1("\\password")) @@ -3536,6 +3575,15 @@ drop_command_generator(const char *text, int state) return create_or_drop_command_generator(text, state, THING_NO_DROP); } +/* + * This function gives you a list of things you can put after an ALTER command. + */ +static char * +alter_command_generator(const char *text, int state) +{ + return create_or_drop_command_generator(text, state, THING_NO_ALTER); +} + /* The following two functions are wrappers for _complete_from_query */ static char *
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers