@@ -982,10 +982,11 @@ typedef struct
982
982
983
983
#define THING_NO_CREATE (1 << 0) /* should not show up after CREATE */
984
984
#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)
986
987
987
988
static const pgsql_thing_t words_after_create [] = {
988
- {"ACCESS METHOD" , NULL , NULL },
989
+ {"ACCESS METHOD" , NULL , NULL , THING_NO_ALTER },
989
990
{"AGGREGATE" , NULL , & Query_for_list_of_aggregates },
990
991
{"CAST" , NULL , NULL }, /* Casts have complex structures for names, so
991
992
* skip it */
@@ -999,19 +1000,21 @@ static const pgsql_thing_t words_after_create[] = {
999
1000
{"CONVERSION" , "SELECT pg_catalog.quote_ident(conname) FROM pg_catalog.pg_conversion WHERE substring(pg_catalog.quote_ident(conname),1,%d)='%s'" },
1000
1001
{"DATABASE" , Query_for_list_of_databases },
1001
1002
{"DICTIONARY" , Query_for_list_of_ts_dictionaries , NULL , THING_NO_SHOW },
1003
+ {"DEFAULT PRIVILEGES" , NULL , NULL , THING_NO_CREATE | THING_NO_DROP },
1002
1004
{"DOMAIN" , NULL , & Query_for_list_of_domains },
1003
1005
{"EVENT TRIGGER" , NULL , NULL },
1004
1006
{"EXTENSION" , Query_for_list_of_extensions },
1005
1007
{"FOREIGN DATA WRAPPER" , NULL , NULL },
1006
1008
{"FOREIGN TABLE" , NULL , NULL },
1007
1009
{"FUNCTION" , NULL , & Query_for_list_of_functions },
1008
1010
{"GROUP" , Query_for_list_of_roles },
1009
- {"LANGUAGE" , Query_for_list_of_languages },
1010
1011
{"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 },
1011
1014
{"MATERIALIZED VIEW" , NULL , & Query_for_list_of_matviews },
1012
1015
{"OPERATOR" , NULL , NULL }, /* Querying for this is probably not such a
1013
1016
* 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 ... */
1015
1018
{"PARSER" , Query_for_list_of_ts_parsers , NULL , THING_NO_SHOW },
1016
1019
{"POLICY" , NULL , NULL },
1017
1020
{"PUBLICATION" , Query_for_list_of_publications },
@@ -1021,15 +1024,18 @@ static const pgsql_thing_t words_after_create[] = {
1021
1024
{"SEQUENCE" , NULL , & Query_for_list_of_sequences },
1022
1025
{"SERVER" , Query_for_list_of_servers },
1023
1026
{"SUBSCRIPTION" , Query_for_list_of_subscriptions },
1027
+ {"SYSTEM" , NULL , NULL , THING_NO_CREATE | THING_NO_DROP },
1024
1028
{"TABLE" , NULL , & Query_for_list_of_tables },
1025
1029
{"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 ... */
1027
1031
{"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 ... */
1028
1033
{"TEXT SEARCH" , NULL , NULL },
1034
+ {"TRANSFORM" , NULL , NULL },
1029
1035
{"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" },
1030
1036
{"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
1033
1039
* ... */
1034
1040
{"USER" , Query_for_list_of_roles },
1035
1041
{"USER MAPPING FOR" , NULL , NULL },
@@ -1042,6 +1048,7 @@ static const pgsql_thing_t words_after_create[] = {
1042
1048
static char * * psql_completion (const char * text , int start , int end );
1043
1049
static char * create_command_generator (const char * text , int state );
1044
1050
static char * drop_command_generator (const char * text , int state );
1051
+ static char * alter_command_generator (const char * text , int state );
1045
1052
static char * complete_from_query (const char * text , int state );
1046
1053
static char * complete_from_schema_query (const char * text , int state );
1047
1054
static char * _complete_from_query (int is_schema_query ,
@@ -1316,6 +1323,17 @@ psql_completion(const char *text, int start, int end)
1316
1323
(previous_words_count >= 2 && \
1317
1324
word_matches_cs(p1, prev_wd) && \
1318
1325
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))
1319
1337
1320
1338
/*
1321
1339
* 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)
1459
1477
1460
1478
/* ALTER something */
1461
1479
else 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 );
1473
1481
/* ALTER TABLE,INDEX,MATERIALIZED VIEW ALL IN TABLESPACE xxx */
1474
1482
else if (TailMatches4 ("ALL" , "IN" , "TABLESPACE" , MatchAny ))
1475
1483
COMPLETE_WITH_LIST2 ("SET TABLESPACE" , "OWNED BY" );
@@ -2622,6 +2630,7 @@ psql_completion(const char *text, int start, int end)
2622
2630
else if (Matches3 ("DROP" , "OWNED" , "BY" ))
2623
2631
COMPLETE_WITH_QUERY (Query_for_list_of_roles );
2624
2632
2633
+ /* DROP TEXT SEARCH */
2625
2634
else if (Matches3 ("DROP" , "TEXT" , "SEARCH" ))
2626
2635
COMPLETE_WITH_LIST4 ("CONFIGURATION" , "DICTIONARY" , "PARSER" , "TEMPLATE" );
2627
2636
@@ -3353,8 +3362,45 @@ psql_completion(const char *text, int start, int end)
3353
3362
3354
3363
else if (TailMatchesCS1 ("\\encoding" ))
3355
3364
COMPLETE_WITH_QUERY (Query_for_list_of_encodings );
3356
- else if (TailMatchesCS1 ("\\h" ) || TailMatchesCS1 ( " \\help" ))
3365
+ else if (TailMatchesCS1 ("\\h| \\help" ))
3357
3366
COMPLETE_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
+ }
3358
3404
else if (TailMatchesCS1 ("\\l*" ) && !TailMatchesCS1 ("\\lo*" ))
3359
3405
COMPLETE_WITH_QUERY (Query_for_list_of_databases );
3360
3406
else if (TailMatchesCS1 ("\\password" ))
@@ -3536,6 +3582,15 @@ drop_command_generator(const char *text, int state)
3536
3582
return create_or_drop_command_generator (text , state , THING_NO_DROP );
3537
3583
}
3538
3584
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
+
3539
3594
/* The following two functions are wrappers for _complete_from_query */
3540
3595
3541
3596
static char *
0 commit comments