@@ -982,10 +982,11 @@ typedef struct
982982
983983#define THING_NO_CREATE (1 << 0)/* should not show up after CREATE */
984984#define THING_NO_DROP (1 << 1)/* should not show up after DROP */
985- #define THING_NO_SHOW (THING_NO_CREATE | THING_NO_DROP)
985+ #define THING_NO_ALTER (1 << 2)/* should not show up after ALTER */
986+ #define THING_NO_SHOW (THING_NO_CREATE | THING_NO_DROP | THING_NO_ALTER)
986987
987988static const pgsql_thing_t words_after_create []= {
988- {"ACCESS METHOD" ,NULL ,NULL },
989+ {"ACCESS METHOD" ,NULL ,NULL , THING_NO_ALTER },
989990{"AGGREGATE" ,NULL ,& Query_for_list_of_aggregates },
990991{"CAST" ,NULL ,NULL },/* Casts have complex structures for names, so
991992 * skip it */
@@ -999,19 +1000,21 @@ static const pgsql_thing_t words_after_create[] = {
9991000{"CONVERSION" ,"SELECT pg_catalog.quote_ident(conname) FROM pg_catalog.pg_conversion WHERE substring(pg_catalog.quote_ident(conname),1,%d)='%s'" },
10001001{"DATABASE" ,Query_for_list_of_databases },
10011002{"DICTIONARY" ,Query_for_list_of_ts_dictionaries ,NULL ,THING_NO_SHOW },
1003+ {"DEFAULT PRIVILEGES" ,NULL ,NULL ,THING_NO_CREATE |THING_NO_DROP },
10021004{"DOMAIN" ,NULL ,& Query_for_list_of_domains },
10031005{"EVENT TRIGGER" ,NULL ,NULL },
10041006{"EXTENSION" ,Query_for_list_of_extensions },
10051007{"FOREIGN DATA WRAPPER" ,NULL ,NULL },
10061008{"FOREIGN TABLE" ,NULL ,NULL },
10071009{"FUNCTION" ,NULL ,& Query_for_list_of_functions },
10081010{"GROUP" ,Query_for_list_of_roles },
1009- {"LANGUAGE" ,Query_for_list_of_languages },
10101011{"INDEX" ,NULL ,& Query_for_list_of_indexes },
1012+ {"LANGUAGE" ,Query_for_list_of_languages },
1013+ {"LARGE OBJECT" ,NULL ,NULL ,THING_NO_CREATE |THING_NO_DROP },
10111014{"MATERIALIZED VIEW" ,NULL ,& Query_for_list_of_matviews },
10121015{"OPERATOR" ,NULL ,NULL },/* Querying for this is probably not such a
10131016 * good idea. */
1014- {"OWNED" ,NULL ,NULL ,THING_NO_CREATE },/* for DROP OWNED BY ... */
1017+ {"OWNED" ,NULL ,NULL ,THING_NO_CREATE | THING_NO_ALTER },/* for DROP OWNED BY ... */
10151018{"PARSER" ,Query_for_list_of_ts_parsers ,NULL ,THING_NO_SHOW },
10161019{"POLICY" ,NULL ,NULL },
10171020{"PUBLICATION" ,Query_for_list_of_publications },
@@ -1021,15 +1024,18 @@ static const pgsql_thing_t words_after_create[] = {
10211024{"SEQUENCE" ,NULL ,& Query_for_list_of_sequences },
10221025{"SERVER" ,Query_for_list_of_servers },
10231026{"SUBSCRIPTION" ,Query_for_list_of_subscriptions },
1027+ {"SYSTEM" ,NULL ,NULL ,THING_NO_CREATE |THING_NO_DROP },
10241028{"TABLE" ,NULL ,& Query_for_list_of_tables },
10251029{"TABLESPACE" ,Query_for_list_of_tablespaces },
1026- {"TEMP" ,NULL ,NULL ,THING_NO_DROP },/* for CREATE TEMP TABLE ... */
1030+ {"TEMP" ,NULL ,NULL ,THING_NO_DROP | THING_NO_ALTER },/* for CREATE TEMP TABLE ... */
10271031{"TEMPLATE" ,Query_for_list_of_ts_templates ,NULL ,THING_NO_SHOW },
1032+ {"TEMPORARY" ,NULL ,NULL ,THING_NO_DROP |THING_NO_ALTER },/* for CREATE TEMPORARY TABLE ... */
10281033{"TEXT SEARCH" ,NULL ,NULL },
1034+ {"TRANSFORM" ,NULL ,NULL },
10291035{"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" },
10301036{"TYPE" ,NULL ,& Query_for_list_of_datatypes },
1031- {"UNIQUE" ,NULL ,NULL ,THING_NO_DROP },/* for CREATE UNIQUE INDEX ... */
1032- {"UNLOGGED" ,NULL ,NULL ,THING_NO_DROP },/* for CREATE UNLOGGED TABLE
1037+ {"UNIQUE" ,NULL ,NULL ,THING_NO_DROP | THING_NO_ALTER },/* for CREATE UNIQUE INDEX ... */
1038+ {"UNLOGGED" ,NULL ,NULL ,THING_NO_DROP | THING_NO_ALTER },/* for CREATE UNLOGGED TABLE
10331039 * ... */
10341040{"USER" ,Query_for_list_of_roles },
10351041{"USER MAPPING FOR" ,NULL ,NULL },
@@ -1042,6 +1048,7 @@ static const pgsql_thing_t words_after_create[] = {
10421048static char * * psql_completion (const char * text ,int start ,int end );
10431049static char * create_command_generator (const char * text ,int state );
10441050static char * drop_command_generator (const char * text ,int state );
1051+ static char * alter_command_generator (const char * text ,int state );
10451052static char * complete_from_query (const char * text ,int state );
10461053static char * complete_from_schema_query (const char * text ,int state );
10471054static char * _complete_from_query (int is_schema_query ,
@@ -1316,6 +1323,17 @@ psql_completion(const char *text, int start, int end)
13161323(previous_words_count >= 2 && \
13171324 word_matches_cs(p1, prev_wd) && \
13181325 word_matches_cs(p2, prev2_wd))
1326+ #define TailMatchesCS3 (p3 ,p2 ,p1 ) \
1327+ (previous_words_count >= 3 && \
1328+ word_matches_cs(p1, prev_wd) && \
1329+ word_matches_cs(p2, prev2_wd) && \
1330+ word_matches_cs(p3, prev3_wd))
1331+ #define TailMatchesCS4 (p4 ,p3 ,p2 ,p1 ) \
1332+ (previous_words_count >= 4 && \
1333+ word_matches_cs(p1, prev_wd) && \
1334+ word_matches_cs(p2, prev2_wd) && \
1335+ word_matches_cs(p3, prev3_wd) && \
1336+ word_matches_cs(p4, prev4_wd))
13191337
13201338/*
13211339 * Macros for matching N words beginning at the start of the line,
@@ -1459,17 +1477,7 @@ psql_completion(const char *text, int start, int end)
14591477
14601478/* ALTER something */
14611479else if (Matches1 ("ALTER" ))
1462- {
1463- static const char * const list_ALTER []=
1464- {"AGGREGATE" ,"COLLATION" ,"CONVERSION" ,"DATABASE" ,"DEFAULT PRIVILEGES" ,"DOMAIN" ,
1465- "EVENT TRIGGER" ,"EXTENSION" ,"FOREIGN DATA WRAPPER" ,"FOREIGN TABLE" ,"FUNCTION" ,
1466- "GROUP" ,"INDEX" ,"LANGUAGE" ,"LARGE OBJECT" ,"MATERIALIZED VIEW" ,"OPERATOR" ,
1467- "POLICY" ,"PUBLICATION" ,"ROLE" ,"RULE" ,"SCHEMA" ,"SERVER" ,"SEQUENCE" ,
1468- "SUBSCRIPTION" ,"SYSTEM" ,"TABLE" ,"TABLESPACE" ,"TEXT SEARCH" ,"TRIGGER" ,"TYPE" ,
1469- "USER" ,"USER MAPPING FOR" ,"VIEW" ,NULL };
1470-
1471- COMPLETE_WITH_LIST (list_ALTER );
1472- }
1480+ matches = completion_matches (text ,alter_command_generator );
14731481/* ALTER TABLE,INDEX,MATERIALIZED VIEW ALL IN TABLESPACE xxx */
14741482else if (TailMatches4 ("ALL" ,"IN" ,"TABLESPACE" ,MatchAny ))
14751483COMPLETE_WITH_LIST2 ("SET TABLESPACE" ,"OWNED BY" );
@@ -2622,6 +2630,7 @@ psql_completion(const char *text, int start, int end)
26222630else if (Matches3 ("DROP" ,"OWNED" ,"BY" ))
26232631COMPLETE_WITH_QUERY (Query_for_list_of_roles );
26242632
2633+ /* DROP TEXT SEARCH */
26252634else if (Matches3 ("DROP" ,"TEXT" ,"SEARCH" ))
26262635COMPLETE_WITH_LIST4 ("CONFIGURATION" ,"DICTIONARY" ,"PARSER" ,"TEMPLATE" );
26272636
@@ -3353,8 +3362,45 @@ psql_completion(const char *text, int start, int end)
33533362
33543363else if (TailMatchesCS1 ("\\encoding" ))
33553364COMPLETE_WITH_QUERY (Query_for_list_of_encodings );
3356- else if (TailMatchesCS1 ("\\h" ) || TailMatchesCS1 ( " \\help" ))
3365+ else if (TailMatchesCS1 ("\\h| \\help" ))
33573366COMPLETE_WITH_LIST (sql_commands );
3367+ else if (TailMatchesCS2 ("\\h|\\help" ,MatchAny ))
3368+ {
3369+ if (TailMatches1 ("DROP" ))
3370+ matches = completion_matches (text ,drop_command_generator );
3371+ else if (TailMatches1 ("ALTER" ))
3372+ matches = completion_matches (text ,alter_command_generator );
3373+ /* CREATE is recognized by tail match elsewhere, so doesn't need to be
3374+ * repeated here */
3375+ }
3376+ else if (TailMatchesCS3 ("\\h|\\help" ,MatchAny ,MatchAny ))
3377+ {
3378+ if (TailMatches2 ("CREATE|DROP" ,"ACCESS" ))
3379+ COMPLETE_WITH_CONST ("METHOD" );
3380+ else if (TailMatches2 ("ALTER" ,"DEFAULT" ))
3381+ COMPLETE_WITH_CONST ("PRIVILEGES" );
3382+ else if (TailMatches2 ("CREATE|ALTER|DROP" ,"EVENT" ))
3383+ COMPLETE_WITH_CONST ("TRIGGER" );
3384+ else if (TailMatches2 ("CREATE|ALTER|DROP" ,"FOREIGN" ))
3385+ COMPLETE_WITH_LIST2 ("DATA WRAPPER" ,"TABLE" );
3386+ else if (TailMatches2 ("ALTER" ,"LARGE" ))
3387+ COMPLETE_WITH_CONST ("OBJECT" );
3388+ else if (TailMatches2 ("CREATE|ALTER|DROP" ,"MATERIALIZED" ))
3389+ COMPLETE_WITH_CONST ("VIEW" );
3390+ else if (TailMatches2 ("CREATE|ALTER|DROP" ,"TEXT" ))
3391+ COMPLETE_WITH_CONST ("SEARCH" );
3392+ else if (TailMatches2 ("CREATE|ALTER|DROP" ,"USER" ))
3393+ COMPLETE_WITH_CONST ("MAPPING FOR" );
3394+ }
3395+ else if (TailMatchesCS4 ("\\h|\\help" ,MatchAny ,MatchAny ,MatchAny ))
3396+ {
3397+ if (TailMatches3 ("CREATE|ALTER|DROP" ,"FOREIGN" ,"DATA" ))
3398+ COMPLETE_WITH_CONST ("WRAPPER" );
3399+ else if (TailMatches3 ("CREATE|ALTER|DROP" ,"TEXT" ,"SEARCH" ))
3400+ COMPLETE_WITH_LIST4 ("CONFIGURATION" ,"DICTIONARY" ,"PARSER" ,"TEMPLATE" );
3401+ else if (TailMatches3 ("CREATE|ALTER|DROP" ,"USER" ,"MAPPING" ))
3402+ COMPLETE_WITH_CONST ("FOR" );
3403+ }
33583404else if (TailMatchesCS1 ("\\l*" )&& !TailMatchesCS1 ("\\lo*" ))
33593405COMPLETE_WITH_QUERY (Query_for_list_of_databases );
33603406else if (TailMatchesCS1 ("\\password" ))
@@ -3536,6 +3582,15 @@ drop_command_generator(const char *text, int state)
35363582return create_or_drop_command_generator (text ,state ,THING_NO_DROP );
35373583}
35383584
3585+ /*
3586+ * This function gives you a list of things you can put after an ALTER command.
3587+ */
3588+ static char *
3589+ alter_command_generator (const char * text ,int state )
3590+ {
3591+ return create_or_drop_command_generator (text ,state ,THING_NO_ALTER );
3592+ }
3593+
35393594/* The following two functions are wrappers for _complete_from_query */
35403595
35413596static char *