@@ -598,10 +598,13 @@ typedef struct
598598const char * name ;
599599const char * query ;/* simple query, or NULL */
600600const SchemaQuery * squery ;/* schema query, or NULL */
601- const bool noshow ;/* NULL or true if this word should not show
602- * up after CREATE or DROP */
601+ const bits32 flags ;/* visibility flags, see below */
603602}pgsql_thing_t ;
604603
604+ #define THING_NO_CREATE (1 << 0)/* should not show up after CREATE */
605+ #define THING_NO_DROP (1 << 1)/* should not show up after DROP */
606+ #define THING_NO_SHOW (THING_NO_CREATE | THING_NO_DROP)
607+
605608static const pgsql_thing_t words_after_create []= {
606609{"AGGREGATE" ,NULL ,& Query_for_list_of_aggregates },
607610{"CAST" ,NULL ,NULL },/* Casts have complex structures for names, so
@@ -612,10 +615,10 @@ static const pgsql_thing_t words_after_create[] = {
612615 * CREATE CONSTRAINT TRIGGER is not supported here because it is designed
613616 * to be used only by pg_dump.
614617 */
615- {"CONFIGURATION" ,Query_for_list_of_ts_configurations ,NULL ,true },
618+ {"CONFIGURATION" ,Query_for_list_of_ts_configurations ,NULL ,THING_NO_SHOW },
616619{"CONVERSION" ,"SELECT pg_catalog.quote_ident(conname) FROM pg_catalog.pg_conversion WHERE substring(pg_catalog.quote_ident(conname),1,%d)='%s'" },
617620{"DATABASE" ,Query_for_list_of_databases },
618- {"DICTIONARY" ,Query_for_list_of_ts_dictionaries ,NULL ,true },
621+ {"DICTIONARY" ,Query_for_list_of_ts_dictionaries ,NULL ,THING_NO_SHOW },
619622{"DOMAIN" ,NULL ,& Query_for_list_of_domains },
620623{"EXTENSION" ,Query_for_list_of_extensions },
621624{"FOREIGN DATA WRAPPER" ,NULL ,NULL },
@@ -626,24 +629,26 @@ static const pgsql_thing_t words_after_create[] = {
626629{"INDEX" ,NULL ,& Query_for_list_of_indexes },
627630{"OPERATOR" ,NULL ,NULL },/* Querying for this is probably not such a
628631 * good idea. */
629- {"PARSER" ,Query_for_list_of_ts_parsers ,NULL , true},
632+ {"OWNED" ,NULL ,NULL ,THING_NO_CREATE },/* for DROP OWNED BY ... */
633+ {"PARSER" ,Query_for_list_of_ts_parsers ,NULL ,THING_NO_SHOW },
630634{"ROLE" ,Query_for_list_of_roles },
631635{"RULE" ,"SELECT pg_catalog.quote_ident(rulename) FROM pg_catalog.pg_rules WHERE substring(pg_catalog.quote_ident(rulename),1,%d)='%s'" },
632636{"SCHEMA" ,Query_for_list_of_schemas },
633637{"SEQUENCE" ,NULL ,& Query_for_list_of_sequences },
634638{"SERVER" ,Query_for_list_of_servers },
635639{"TABLE" ,NULL ,& Query_for_list_of_tables },
636640{"TABLESPACE" ,Query_for_list_of_tablespaces },
637- {"TEMP" ,NULL ,NULL }, /* for CREATE TEMP TABLE ... */
638- {"TEMPLATE" ,Query_for_list_of_ts_templates ,NULL ,true },
641+ {"TEMP" ,NULL ,NULL , THING_NO_DROP }, /* for CREATE TEMP TABLE ... */
642+ {"TEMPLATE" ,Query_for_list_of_ts_templates ,NULL ,THING_NO_SHOW },
639643{"TEXT SEARCH" ,NULL ,NULL },
640644{"TRIGGER" ,"SELECT pg_catalog.quote_ident(tgname) FROM pg_catalog.pg_trigger WHERE substring(pg_catalog.quote_ident(tgname),1,%d)='%s'" },
641645{"TYPE" ,NULL ,& Query_for_list_of_datatypes },
642- {"UNIQUE" ,NULL ,NULL },/* for CREATE UNIQUE INDEX ... */
646+ {"UNIQUE" ,NULL ,NULL ,THING_NO_DROP },/* for CREATE UNIQUE INDEX ... */
647+ {"UNLOGGED" ,NULL ,NULL ,THING_NO_DROP },/* for CREATE UNLOGGED TABLE ... */
643648{"USER" ,Query_for_list_of_roles },
644649{"USER MAPPING FOR" ,NULL ,NULL },
645650{"VIEW" ,NULL ,& Query_for_list_of_views },
646- {NULL , NULL , NULL , false }/* end of list */
651+ {NULL }/* end of list */
647652};
648653
649654
@@ -1771,6 +1776,12 @@ psql_completion(char *text, int start, int end)
17711776
17721777COMPLETE_WITH_LIST (list_TEMP );
17731778}
1779+ /* Complete "CREATE UNLOGGED" with TABLE */
1780+ else if (pg_strcasecmp (prev2_wd ,"CREATE" )== 0 &&
1781+ pg_strcasecmp (prev_wd ,"UNLOGGED" )== 0 )
1782+ {
1783+ COMPLETE_WITH_CONST ("TABLE" );
1784+ }
17741785
17751786/* CREATE TABLESPACE */
17761787else if (pg_strcasecmp (prev3_wd ,"CREATE" )== 0 &&
@@ -2858,11 +2869,11 @@ psql_completion(char *text, int start, int end)
28582869 */
28592870
28602871/*
2861- *This one gives you one from a list of things you can put after CREATE
2862- *as defined above .
2872+ *Common routine for create_command_generator and drop_command_generator.
2873+ *Entries that have 'excluded' flags are not returned .
28632874 */
28642875static char *
2865- create_command_generator (const char * text ,int state )
2876+ create_or_drop_command_generator (const char * text ,int state , bits32 excluded )
28662877{
28672878static int list_index ,
28682879string_length ;
@@ -2879,57 +2890,30 @@ create_command_generator(const char *text, int state)
28792890while ((name = words_after_create [list_index ++ ].name ))
28802891{
28812892if ((pg_strncasecmp (name ,text ,string_length )== 0 )&&
2882- !words_after_create [list_index - 1 ].noshow )
2893+ !( words_after_create [list_index - 1 ].flags & excluded ) )
28832894return pg_strdup (name );
28842895}
28852896/* if nothing matches, return NULL */
28862897return NULL ;
28872898}
28882899
2900+ /*
2901+ * This one gives you one from a list of things you can put after CREATE
2902+ * as defined above.
2903+ */
2904+ static char *
2905+ create_command_generator (const char * text ,int state )
2906+ {
2907+ return create_or_drop_command_generator (text ,state ,THING_NO_CREATE );
2908+ }
2909+
28892910/*
28902911 * This function gives you a list of things you can put after a DROP command.
2891- * Very similar to create_command_generator, but has an additional entry for
2892- * OWNED BY. (We do it this way in order not to duplicate the
2893- * words_after_create list.)
28942912 */
28952913static char *
28962914drop_command_generator (const char * text ,int state )
28972915{
2898- static int list_index ,
2899- string_length ;
2900- const char * name ;
2901-
2902- if (state == 0 )
2903- {
2904- /* If this is the first time for this completion, init some values */
2905- list_index = 0 ;
2906- string_length = strlen (text );
2907-
2908- /*
2909- * DROP can be followed by "OWNED BY", which is not found in the list
2910- * for CREATE matches, so make it the first state. (We do not make it
2911- * the last state because it would be more difficult to detect when we
2912- * have to return NULL instead.)
2913- *
2914- * Make sure we advance to the next state.
2915- */
2916- list_index ++ ;
2917- if (pg_strncasecmp ("OWNED" ,text ,string_length )== 0 )
2918- return pg_strdup ("OWNED" );
2919- }
2920-
2921- /*
2922- * In subsequent attempts, try to complete with the same items we use for
2923- * CREATE
2924- */
2925- while ((name = words_after_create [list_index ++ - 1 ].name ))
2926- {
2927- if ((pg_strncasecmp (name ,text ,string_length )== 0 )&& (!words_after_create [list_index - 2 ].noshow ))
2928- return pg_strdup (name );
2929- }
2930-
2931- /* if nothing matches, return NULL */
2932- return NULL ;
2916+ return create_or_drop_command_generator (text ,state ,THING_NO_DROP );
29332917}
29342918
29352919/* The following two functions are wrappers for _complete_from_query */