@ -70,15 +70,43 @@ extern char *filename_completion_function();
*/
PQExpBuffer tab_completion_query_buf = NULL ;
/*
* In some situations , the query to find out what names are available to
* complete with must vary depending on server version . We handle this by
* storing a list of queries , each tagged with the minimum server version
* it will work for . Each list must be stored in descending server version
* order , so that the first satisfactory query is the one to use .
*
* When the query string is otherwise constant , an array of VersionedQuery
* suffices . Terminate the array with an entry having min_server_version = 0.
* That entry ' s query string can be a query that works in all supported older
* server versions , or NULL to give up and do no completion .
*/
typedef struct VersionedQuery
{
int min_server_version ;
const char * query ;
} VersionedQuery ;
/*
* This struct is used to define " schema queries " , which are custom - built
* to obtain possibly - schema - qualified names of database objects . There is
* enough similarity in the structure that we don ' t want to repeat it each
* time . So we put the components of each query into this struct and
* assemble them with the common boilerplate in _complete_from_query ( ) .
*
* As with VersionedQuery , we can use an array of these if the query details
* must vary across versions .
*/
typedef struct SchemaQuery
{
/*
* If not zero , minimum server version this struct applies to . If not
* zero , there should be a following struct with a smaller minimum server
* version ; use catname = = NULL in the last entry if we should do nothing .
*/
int min_server_version ;
/*
* Name of catalog or catalogs to be queried , with alias , eg .
* " pg_catalog.pg_class c " . Note that " pg_namespace n " will be added .
@ -133,6 +161,7 @@ static const char *completion_charp; /* 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 */
static const VersionedQuery * completion_vquery ; /* to pass a VersionedQuery */
static const SchemaQuery * completion_squery ; /* to pass a SchemaQuery */
static bool completion_case_sensitive ; /* completion is case sensitive */
@ -140,7 +169,9 @@ static bool completion_case_sensitive; /* completion is case sensitive */
* A few macros to ease typing . You can use these to complete the given
* string with
* 1 ) The results from a query you pass it . ( Perhaps one of those below ? )
* We support both simple and versioned queries .
* 2 ) The results from a schema query you pass it .
* We support both simple and versioned schema queries .
* 3 ) The items from a null - pointer - terminated list ( with or without
* case - sensitive comparison ; see also COMPLETE_WITH_LISTn , below ) .
* 4 ) A string constant .
@ -153,6 +184,12 @@ do { \
matches = completion_matches ( text , complete_from_query ) ; \
} while ( 0 )
# define COMPLETE_WITH_VERSIONED_QUERY(query) \
do { \
completion_vquery = query ; \
matches = completion_matches ( text , complete_from_versioned_query ) ; \
} while ( 0 )
# define COMPLETE_WITH_SCHEMA_QUERY(query, addon) \
do { \
completion_squery = & ( query ) ; \
@ -160,6 +197,13 @@ do { \
matches = completion_matches ( text , complete_from_schema_query ) ; \
} while ( 0 )
# define COMPLETE_WITH_VERSIONED_SCHEMA_QUERY(query, addon) \
do { \
completion_squery = query ; \
completion_vquery = addon ; \
matches = completion_matches ( text , complete_from_versioned_schema_query ) ; \
} while ( 0 )
# define COMPLETE_WITH_LIST_CS(list) \
do { \
completion_charpp = list ; \
@ -345,22 +389,44 @@ do { \
* Assembly instructions for schema queries
*/
static const SchemaQuery Query_for_list_of_aggregates = {
/* catname */
" pg_catalog.pg_proc p " ,
/* selcondition */
" p.prokind = 'a' " ,
/* viscondition */
" pg_catalog.pg_function_is_visible(p.oid) " ,
/* namespace */
" p.pronamespace " ,
/* result */
" pg_catalog.quote_ident(p.proname) " ,
/* qualresult */
NULL
static const SchemaQuery Query_for_list_of_aggregates [ ] = {
{
/* min_server_version */
110000 ,
/* catname */
" pg_catalog.pg_proc p " ,
/* selcondition */
" p.prokind = 'a' " ,
/* viscondition */
" pg_catalog.pg_function_is_visible(p.oid) " ,
/* namespace */
" p.pronamespace " ,
/* result */
" pg_catalog.quote_ident(p.proname) " ,
/* qualresult */
NULL
} ,
{
/* min_server_version */
0 ,
/* catname */
" pg_catalog.pg_proc p " ,
/* selcondition */
" p.proisagg " ,
/* viscondition */
" pg_catalog.pg_function_is_visible(p.oid) " ,
/* namespace */
" p.pronamespace " ,
/* result */
" pg_catalog.quote_ident(p.proname) " ,
/* qualresult */
NULL
}
} ;
static const SchemaQuery Query_for_list_of_datatypes = {
/* min_server_version */
0 ,
/* catname */
" pg_catalog.pg_type t " ,
/* selcondition --- ignore table rowtypes and array types */
@ -379,6 +445,8 @@ static const SchemaQuery Query_for_list_of_datatypes = {
} ;
static const SchemaQuery Query_for_list_of_domains = {
/* min_server_version */
0 ,
/* catname */
" pg_catalog.pg_type t " ,
/* selcondition */
@ -393,22 +461,44 @@ static const SchemaQuery Query_for_list_of_domains = {
NULL
} ;
static const SchemaQuery Query_for_list_of_functions = {
/* catname */
" pg_catalog.pg_proc p " ,
/* selcondition */
" p.prokind IN ('f', 'w') " ,
/* viscondition */
" pg_catalog.pg_function_is_visible(p.oid) " ,
/* namespace */
" p.pronamespace " ,
/* result */
" pg_catalog.quote_ident(p.proname) " ,
/* qualresult */
NULL
static const SchemaQuery Query_for_list_of_functions [ ] = {
{
/* min_server_version */
110000 ,
/* catname */
" pg_catalog.pg_proc p " ,
/* selcondition */
" p.prokind IN ('f', 'w') " ,
/* viscondition */
" pg_catalog.pg_function_is_visible(p.oid) " ,
/* namespace */
" p.pronamespace " ,
/* result */
" pg_catalog.quote_ident(p.proname) " ,
/* qualresult */
NULL
} ,
{
/* min_server_version */
0 ,
/* catname */
" pg_catalog.pg_proc p " ,
/* selcondition */
NULL ,
/* viscondition */
" pg_catalog.pg_function_is_visible(p.oid) " ,
/* namespace */
" p.pronamespace " ,
/* result */
" pg_catalog.quote_ident(p.proname) " ,
/* qualresult */
NULL
}
} ;
static const SchemaQuery Query_for_list_of_indexes = {
/* min_server_version */
0 ,
/* catname */
" pg_catalog.pg_class c " ,
/* selcondition */
@ -424,22 +514,29 @@ static const SchemaQuery Query_for_list_of_indexes = {
NULL
} ;
static const SchemaQuery Query_for_list_of_procedures = {
/* catname */
" pg_catalog.pg_proc p " ,
/* selcondition */
" p.prokind = 'p' " ,
/* viscondition */
" pg_catalog.pg_function_is_visible(p.oid) " ,
/* namespace */
" p.pronamespace " ,
/* result */
" pg_catalog.quote_ident(p.proname) " ,
/* qualresult */
NULL
static const SchemaQuery Query_for_list_of_procedures [ ] = {
{
/* min_server_version */
110000 ,
/* catname */
" pg_catalog.pg_proc p " ,
/* selcondition */
" p.prokind = 'p' " ,
/* viscondition */
" pg_catalog.pg_function_is_visible(p.oid) " ,
/* namespace */
" p.pronamespace " ,
/* result */
" pg_catalog.quote_ident(p.proname) " ,
/* qualresult */
NULL
} ,
{ 0 , NULL }
} ;
static const SchemaQuery Query_for_list_of_routines = {
/* min_server_version */
0 ,
/* catname */
" pg_catalog.pg_proc p " ,
/* selcondition */
@ -455,6 +552,8 @@ static const SchemaQuery Query_for_list_of_routines = {
} ;
static const SchemaQuery Query_for_list_of_sequences = {
/* min_server_version */
0 ,
/* catname */
" pg_catalog.pg_class c " ,
/* selcondition */
@ -470,6 +569,8 @@ static const SchemaQuery Query_for_list_of_sequences = {
} ;
static const SchemaQuery Query_for_list_of_foreign_tables = {
/* min_server_version */
0 ,
/* catname */
" pg_catalog.pg_class c " ,
/* selcondition */
@ -485,6 +586,8 @@ static const SchemaQuery Query_for_list_of_foreign_tables = {
} ;
static const SchemaQuery Query_for_list_of_tables = {
/* min_server_version */
0 ,
/* catname */
" pg_catalog.pg_class c " ,
/* selcondition */
@ -501,6 +604,8 @@ static const SchemaQuery Query_for_list_of_tables = {
} ;
static const SchemaQuery Query_for_list_of_partitioned_tables = {
/* min_server_version */
0 ,
/* catname */
" pg_catalog.pg_class c " ,
/* selcondition */
@ -516,6 +621,8 @@ static const SchemaQuery Query_for_list_of_partitioned_tables = {
} ;
static const SchemaQuery Query_for_list_of_constraints_with_schema = {
/* min_server_version */
0 ,
/* catname */
" pg_catalog.pg_constraint c " ,
/* selcondition */
@ -532,6 +639,8 @@ static const SchemaQuery Query_for_list_of_constraints_with_schema = {
/* Relations supporting INSERT, UPDATE or DELETE */
static const SchemaQuery Query_for_list_of_updatables = {
/* min_server_version */
0 ,
/* catname */
" pg_catalog.pg_class c " ,
/* selcondition */
@ -550,6 +659,8 @@ static const SchemaQuery Query_for_list_of_updatables = {
} ;
static const SchemaQuery Query_for_list_of_relations = {
/* min_server_version */
0 ,
/* catname */
" pg_catalog.pg_class c " ,
/* selcondition */
@ -565,6 +676,8 @@ static const SchemaQuery Query_for_list_of_relations = {
} ;
static const SchemaQuery Query_for_list_of_tsvmf = {
/* min_server_version */
0 ,
/* catname */
" pg_catalog.pg_class c " ,
/* selcondition */
@ -585,6 +698,8 @@ static const SchemaQuery Query_for_list_of_tsvmf = {
} ;
static const SchemaQuery Query_for_list_of_tmf = {
/* min_server_version */
0 ,
/* catname */
" pg_catalog.pg_class c " ,
/* selcondition */
@ -602,6 +717,8 @@ static const SchemaQuery Query_for_list_of_tmf = {
} ;
static const SchemaQuery Query_for_list_of_tpm = {
/* min_server_version */
0 ,
/* catname */
" pg_catalog.pg_class c " ,
/* selcondition */
@ -619,6 +736,8 @@ static const SchemaQuery Query_for_list_of_tpm = {
} ;
static const SchemaQuery Query_for_list_of_tm = {
/* min_server_version */
0 ,
/* catname */
" pg_catalog.pg_class c " ,
/* selcondition */
@ -635,6 +754,8 @@ static const SchemaQuery Query_for_list_of_tm = {
} ;
static const SchemaQuery Query_for_list_of_views = {
/* min_server_version */
0 ,
/* catname */
" pg_catalog.pg_class c " ,
/* selcondition */
@ -650,6 +771,8 @@ static const SchemaQuery Query_for_list_of_views = {
} ;
static const SchemaQuery Query_for_list_of_matviews = {
/* min_server_version */
0 ,
/* catname */
" pg_catalog.pg_class c " ,
/* selcondition */
@ -665,6 +788,8 @@ static const SchemaQuery Query_for_list_of_matviews = {
} ;
static const SchemaQuery Query_for_list_of_statistics = {
/* min_server_version */
0 ,
/* catname */
" pg_catalog.pg_statistic_ext s " ,
/* selcondition */
@ -925,18 +1050,6 @@ static const SchemaQuery Query_for_list_of_statistics = {
" FROM pg_catalog.pg_am " \
" WHERE substring(pg_catalog.quote_ident(amname),1,%d)='%s' "
# define Query_for_list_of_publications \
" SELECT pg_catalog.quote_ident(pubname) " \
" FROM pg_catalog.pg_publication " \
" WHERE substring(pg_catalog.quote_ident(pubname),1,%d)='%s' "
# define Query_for_list_of_subscriptions \
" SELECT pg_catalog.quote_ident(s.subname) " \
" FROM pg_catalog.pg_subscription s, pg_catalog.pg_database d " \
" WHERE substring(pg_catalog.quote_ident(s.subname),1,%d)='%s' " \
" AND d.datname = pg_catalog.current_database() " \
" AND s.subdbid = d.oid "
/* the silly-looking length condition is just to eat up the current word */
# define Query_for_list_of_arguments \
" SELECT pg_catalog.oidvectortypes(proargtypes)||')' " \
@ -1030,6 +1143,32 @@ static const SchemaQuery Query_for_list_of_statistics = {
" and pg_catalog.pg_table_is_visible(c2.oid) " \
" and c2.relispartition = 'true' "
/*
* These object types were introduced later than our support cutoff of
* server version 7.4 . We use the VersionedQuery infrastructure so that
* we don ' t send certain - to - fail queries to older servers .
*/
static const VersionedQuery Query_for_list_of_publications [ ] = {
{ 100000 ,
" SELECT pg_catalog.quote_ident(pubname) "
" FROM pg_catalog.pg_publication "
" WHERE substring(pg_catalog.quote_ident(pubname),1,%d)='%s' "
} ,
{ 0 , NULL }
} ;
static const VersionedQuery Query_for_list_of_subscriptions [ ] = {
{ 100000 ,
" SELECT pg_catalog.quote_ident(s.subname) "
" FROM pg_catalog.pg_subscription s, pg_catalog.pg_database d "
" WHERE substring(pg_catalog.quote_ident(s.subname),1,%d)='%s' "
" AND d.datname = pg_catalog.current_database() "
" AND s.subdbid = d.oid "
} ,
{ 0 , NULL }
} ;
/*
* This is a list of all " things " in Pgsql , which can show up after CREATE or
* DROP ; and there is also a query to get a list of them .
@ -1039,6 +1178,7 @@ typedef struct
{
const char * name ;
const char * query ; /* simple query, or NULL */
const VersionedQuery * vquery ; /* versioned query, or NULL */
const SchemaQuery * squery ; /* schema query, or NULL */
const bits32 flags ; /* visibility flags, see below */
} pgsql_thing_t ;
@ -1049,9 +1189,9 @@ typedef struct
# 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 , THING_NO_ALTER } ,
{ " AGGREGATE " , NULL , & Query_for_list_of_aggregates } ,
{ " CAST " , NULL , NULL } , /* Casts have complex structures for names, so
{ " ACCESS METHOD " , NULL , NULL , NULL , THING_NO_ALTER } ,
{ " AGGREGATE " , NULL , NULL , Query_for_list_of_aggregates } ,
{ " CAST " , NULL , NULL , NULL } , /* Casts have complex structures for names, so
* skip it */
{ " COLLATION " , " SELECT pg_catalog.quote_ident(collname) FROM pg_catalog.pg_collation WHERE collencoding IN (-1, pg_catalog.pg_char_to_encoding(pg_catalog.getdatabaseencoding())) AND substring(pg_catalog.quote_ident(collname),1,%d)='%s' " } ,
@ -1059,56 +1199,56 @@ static const pgsql_thing_t words_after_create[] = {
* CREATE CONSTRAINT TRIGGER is not supported here because it is designed
* to be used only by pg_dump .
*/
{ " CONFIGURATION " , Query_for_list_of_ts_configurations , NULL , THING_NO_SHOW } ,
{ " CONFIGURATION " , Query_for_list_of_ts_configurations , NULL , NULL , THING_NO_SHOW } ,
{ " 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 } ,
{ " DEFAULT PRIVILEGES " , NULL , NULL , THING_NO_CREATE | THING_NO_DROP } ,
{ " DICTIONARY " , Query_for_list_of_ts_dictionaries , NULL , THING_NO_SHOW } ,
{ " DOMAIN " , NULL , & Query_for_list_of_domains } ,
{ " EVENT TRIGGER " , NULL , NULL } ,
{ " DEFAULT PRIVILEGES " , NULL , NULL , NULL , THING_NO_CREATE | THING_NO_DROP } ,
{ " DICTIONARY " , Query_for_list_of_ts_dictionaries , NULL , NULL , THING_NO_SHOW } ,
{ " DOMAIN " , NULL , NULL , & Query_for_list_of_domains } ,
{ " EVENT TRIGGER " , NULL , NULL , NULL } ,
{ " EXTENSION " , Query_for_list_of_extensions } ,
{ " FOREIGN DATA WRAPPER " , NULL , NULL } ,
{ " FOREIGN TABLE " , NULL , NULL } ,
{ " FUNCTION " , NULL , & Query_for_list_of_functions } ,
{ " FOREIGN DATA WRAPPER " , NULL , NULL , NULL } ,
{ " FOREIGN TABLE " , NULL , NULL , NULL } ,
{ " FUNCTION " , NULL , NULL , Query_for_list_of_functions } ,
{ " GROUP " , Query_for_list_of_roles } ,
{ " INDEX " , NULL , & Query_for_list_of_indexes } ,
{ " INDEX " , NULL , NULL , & Query_for_list_of_indexes } ,
{ " LANGUAGE " , Query_for_list_of_languages } ,
{ " 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 | THING_NO_ALTER } , /* for DROP OWNED BY ... */
{ " PARSER " , Query_for_list_of_ts_parsers , NULL , THING_NO_SHOW } ,
{ " POLICY " , NULL , NULL } ,
{ " PROCEDURE " , NULL , & Query_for_list_of_procedures } ,
{ " PUBLICATION " , Query_for_list_of_publications } ,
{ " LARGE OBJECT " , NULL , NULL , NULL , THING_NO_CREATE | THING_NO_DROP } ,
{ " MATERIALIZED VIEW " , NULL , NULL , & Query_for_list_of_matviews } ,
{ " OPERATOR " , NULL , NULL , NULL } , /* Querying for this is probably not such
* a good idea . */
{ " OWNED " , NULL , NULL , NULL , THING_NO_CREATE | THING_NO_ALTER } , /* for DROP OWNED BY ... */
{ " PARSER " , Query_for_list_of_ts_parsers , NULL , NULL , THING_NO_SHOW } ,
{ " POLICY " , NULL , NULL , NULL } ,
{ " PROCEDURE " , NULL , NULL , Query_for_list_of_procedures } ,
{ " PUBLICATION " , NULL , Query_for_list_of_publications } ,
{ " ROLE " , Query_for_list_of_roles } ,
{ " ROUTINE " , NULL , & Query_for_list_of_routines , THING_NO_CREATE } ,
{ " ROUTINE " , NULL , NULL , & Query_for_list_of_routines , THING_NO_CREATE } ,
{ " RULE " , " SELECT pg_catalog.quote_ident(rulename) FROM pg_catalog.pg_rules WHERE substring(pg_catalog.quote_ident(rulename),1,%d)='%s' " } ,
{ " SCHEMA " , Query_for_list_of_schemas } ,
{ " SEQUENCE " , NULL , & Query_for_list_of_sequences } ,
{ " SEQUENCE " , NULL , NULL , & Query_for_list_of_sequences } ,
{ " SERVER " , Query_for_list_of_servers } ,
{ " STATISTICS " , NULL , & Query_for_list_of_statistics } ,
{ " SUBSCRIPTION " , Query_for_list_of_subscriptions } ,
{ " SYSTEM " , NULL , NULL , THING_NO_CREATE | THING_NO_DROP } ,
{ " TABLE " , NULL , & Query_for_list_of_tables } ,
{ " STATISTICS " , NULL , NULL , & Query_for_list_of_statistics } ,
{ " SUBSCRIPTION " , NULL , Query_for_list_of_subscriptions } ,
{ " SYSTEM " , NULL , NULL , NULL , THING_NO_CREATE | THING_NO_DROP } ,
{ " TABLE " , NULL , NULL , & Query_for_list_of_tables } ,
{ " TABLESPACE " , Query_for_list_of_tablespaces } ,
{ " TEMP " , NULL , NULL , THING_NO_DROP | THING_NO_ALTER } , /* for CREATE TEMP TABLE
* . . . */
{ " TEMPLATE " , Query_for_list_of_ts_templates , NULL , THING_NO_SHOW } ,
{ " TEMPORARY " , NULL , NULL , THING_NO_DROP | THING_NO_ALTER } , /* for CREATE TEMPORARY
* TABLE . . . */
{ " TEXT SEARCH " , NULL , NULL } ,
{ " TRANSFORM " , NULL , NULL } ,
{ " TEMP " , NULL , NULL , NULL , THING_NO_DROP | THING_NO_ALTER } , /* for CREATE TEMP TABLE
* . . . */
{ " TEMPLATE " , Query_for_list_of_ts_templates , NULL , NULL , THING_NO_SHOW } ,
{ " TEMPORARY " , NULL , NULL , NULL , THING_NO_DROP | THING_NO_ALTER } , /* for CREATE TEMPORARY
* TABLE . . . */
{ " TEXT SEARCH " , NULL , NULL , NULL } ,
{ " TRANSFORM " , NULL , 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 | THING_NO_ALTER } , /* for CREATE UNIQUE
* INDEX . . . */
{ " UNLOGGED " , NULL , NULL , THING_NO_DROP | THING_NO_ALTER } , /* for CREATE UNLOGGED
* TABLE . . . */
{ " TYPE " , NULL , NULL , & Query_for_list_of_datatypes } ,
{ " UNIQUE " , NULL , NULL , NULL , THING_NO_DROP | THING_NO_ALTER } , /* for CREATE UNIQUE
* INDEX . . . */
{ " UNLOGGED " , NULL , NULL , NULL , THING_NO_DROP | THING_NO_ALTER } , /* for CREATE UNLOGGED
* TABLE . . . */
{ " USER " , Query_for_list_of_roles " UNION SELECT 'MAPPING FOR' " } ,
{ " USER MAPPING FOR " , NULL , NULL } ,
{ " VIEW " , NULL , & Query_for_list_of_views } ,
{ " USER MAPPING FOR " , NULL , NULL , NULL } ,
{ " VIEW " , NULL , NULL , & Query_for_list_of_views } ,
{ NULL } /* end of list */
} ;
@ -1119,8 +1259,11 @@ 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_versioned_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 ,
static char * complete_from_versioned_schema_query ( const char * text , int state ) ;
static char * _complete_from_query ( const char * simple_query ,
const SchemaQuery * schema_query ,
const char * text , int state ) ;
static char * complete_from_list ( const char * text , int state ) ;
static char * complete_from_const ( const char * text , int state ) ;
@ -2208,7 +2351,7 @@ psql_completion(const char *text, int start, int end)
COMPLETE_WITH_LIST4 ( " WORK " , " TRANSACTION " , " TO SAVEPOINT " , " PREPARED " ) ;
/* CALL */
else if ( Matches1 ( " CALL " ) )
COMPLETE_WITH_SCHEMA_QUERY ( Query_for_list_of_procedures , NULL ) ;
COMPLETE_WITH_VERSIONED_ SCHEMA_QUERY ( Query_for_list_of_procedures , NULL ) ;
else if ( Matches2 ( " CALL " , MatchAny ) )
COMPLETE_WITH_CONST ( " ( " ) ;
/* CLUSTER */
@ -2654,7 +2797,7 @@ psql_completion(const char *text, int start, int end)
else if ( HeadMatches2 ( " CREATE " , " TRIGGER " ) & & TailMatches1 ( " EXECUTE " ) )
COMPLETE_WITH_CONST ( " PROCEDURE " ) ;
else if ( HeadMatches2 ( " CREATE " , " TRIGGER " ) & & TailMatches2 ( " EXECUTE " , " PROCEDURE " ) )
COMPLETE_WITH_SCHEMA_QUERY ( Query_for_list_of_functions , NULL ) ;
COMPLETE_WITH_VERSIONED_ SCHEMA_QUERY ( Query_for_list_of_functions , NULL ) ;
/* CREATE ROLE,USER,GROUP <name> */
else if ( Matches3 ( " CREATE " , " ROLE|GROUP|USER " , MatchAny ) & &
@ -3008,11 +3151,11 @@ psql_completion(const char *text, int start, int end)
else if ( TailMatches1 ( " DOMAIN " ) )
COMPLETE_WITH_SCHEMA_QUERY ( Query_for_list_of_domains , NULL ) ;
else if ( TailMatches1 ( " FUNCTION " ) )
COMPLETE_WITH_SCHEMA_QUERY ( Query_for_list_of_functions , NULL ) ;
COMPLETE_WITH_VERSIONED_ SCHEMA_QUERY ( Query_for_list_of_functions , NULL ) ;
else if ( TailMatches1 ( " LANGUAGE " ) )
COMPLETE_WITH_QUERY ( Query_for_list_of_languages ) ;
else if ( TailMatches1 ( " PROCEDURE " ) )
COMPLETE_WITH_SCHEMA_QUERY ( Query_for_list_of_procedures , NULL ) ;
COMPLETE_WITH_VERSIONED_ SCHEMA_QUERY ( Query_for_list_of_procedures , NULL ) ;
else if ( TailMatches1 ( " ROUTINE " ) )
COMPLETE_WITH_SCHEMA_QUERY ( Query_for_list_of_routines , NULL ) ;
else if ( TailMatches1 ( " SCHEMA " ) )
@ -3483,7 +3626,7 @@ psql_completion(const char *text, int start, int end)
COMPLETE_WITH_QUERY ( Query_for_list_of_roles ) ;
}
else if ( TailMatchesCS1 ( " \\ da* " ) )
COMPLETE_WITH_SCHEMA_QUERY ( Query_for_list_of_aggregates , NULL ) ;
COMPLETE_WITH_VERSIONED_ SCHEMA_QUERY ( Query_for_list_of_aggregates , NULL ) ;
else if ( TailMatchesCS1 ( " \\ dA* " ) )
COMPLETE_WITH_QUERY ( Query_for_list_of_access_methods ) ;
else if ( TailMatchesCS1 ( " \\ db* " ) )
@ -3497,7 +3640,7 @@ psql_completion(const char *text, int start, int end)
else if ( TailMatchesCS1 ( " \\ dew* " ) )
COMPLETE_WITH_QUERY ( Query_for_list_of_fdws ) ;
else if ( TailMatchesCS1 ( " \\ df* " ) )
COMPLETE_WITH_SCHEMA_QUERY ( Query_for_list_of_functions , NULL ) ;
COMPLETE_WITH_VERSIONED_ SCHEMA_QUERY ( Query_for_list_of_functions , NULL ) ;
else if ( TailMatchesCS1 ( " \\ dFd* " ) )
COMPLETE_WITH_QUERY ( Query_for_list_of_ts_dictionaries ) ;
@ -3541,7 +3684,7 @@ psql_completion(const char *text, int start, int end)
COMPLETE_WITH_SCHEMA_QUERY ( Query_for_list_of_relations , NULL ) ;
else if ( TailMatchesCS1 ( " \\ ef " ) )
COMPLETE_WITH_SCHEMA_QUERY ( Query_for_list_of_functions , NULL ) ;
COMPLETE_WITH_VERSIONED_ SCHEMA_QUERY ( Query_for_list_of_functions , NULL ) ;
else if ( TailMatchesCS1 ( " \\ ev " ) )
COMPLETE_WITH_SCHEMA_QUERY ( Query_for_list_of_views , NULL ) ;
@ -3650,7 +3793,7 @@ psql_completion(const char *text, int start, int end)
COMPLETE_WITH_LIST_CS3 ( " default " , " verbose " , " terse " ) ;
}
else if ( TailMatchesCS1 ( " \\ sf* " ) )
COMPLETE_WITH_SCHEMA_QUERY ( Query_for_list_of_functions , NULL ) ;
COMPLETE_WITH_VERSIONED_ SCHEMA_QUERY ( Query_for_list_of_functions , NULL ) ;
else if ( TailMatchesCS1 ( " \\ sv* " ) )
COMPLETE_WITH_SCHEMA_QUERY ( Query_for_list_of_views , NULL ) ;
else if ( TailMatchesCS1 ( " \\ cd| \\ e| \\ edit| \\ g| \\ i| \\ include| "
@ -3676,9 +3819,11 @@ psql_completion(const char *text, int start, int end)
{
if ( words_after_create [ i ] . query )
COMPLETE_WITH_QUERY ( words_after_create [ i ] . query ) ;
else if ( words_after_create [ i ] . vquery )
COMPLETE_WITH_VERSIONED_QUERY ( words_after_create [ i ] . vquery ) ;
else if ( words_after_create [ i ] . squery )
COMPLETE_WITH_SCHEMA_QUERY ( * words_after_create [ i ] . squery ,
NULL ) ;
COMPLETE_WITH_VERSIONED_ SCHEMA_QUERY ( words_after_create [ i ] . squery ,
NULL ) ;
break ;
}
}
@ -3777,24 +3922,73 @@ 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 */
/*
* These functions generate lists using server queries .
* They are all wrappers for _complete_from_query .
*/
static char *
complete_from_query ( const char * text , int state )
{
return _complete_from_query ( 0 , text , state ) ;
/* query is assumed to work for any server version */
return _complete_from_query ( completion_charp , NULL , text , state ) ;
}
static char *
complete_from_versioned_query ( const char * text , int state )
{
const VersionedQuery * vquery = completion_vquery ;
/* Find appropriate array element */
while ( pset . sversion < vquery - > min_server_version )
vquery + + ;
/* Fail completion if server is too old */
if ( vquery - > query = = NULL )
return NULL ;
return _complete_from_query ( vquery - > query , NULL , text , state ) ;
}
static char *
complete_from_schema_query ( const char * text , int state )
{
return _complete_from_query ( 1 , text , state ) ;
/* query is assumed to work for any server version */
return _complete_from_query ( completion_charp , completion_squery ,
text , state ) ;
}
static char *
complete_from_versioned_schema_query ( const char * text , int state )
{
const SchemaQuery * squery = completion_squery ;
const VersionedQuery * vquery = completion_vquery ;
/* Find appropriate array element */
while ( pset . sversion < squery - > min_server_version )
squery + + ;
/* Fail completion if server is too old */
if ( squery - > catname = = NULL )
return NULL ;
/* Likewise for the add-on text, if any */
if ( vquery )
{
while ( pset . sversion < vquery - > min_server_version )
vquery + + ;
if ( vquery - > query = = NULL )
return NULL ;
}
return _complete_from_query ( vquery ? vquery - > query : NULL ,
squery , text , state ) ;
}
/*
* This creates a list of matching things , according to a query pointed to
* by completion_charp .
* This creates a list of matching things , according to a query described by
* the initial arguments . The caller has already done any work needed to
* select the appropriate query for the server ' s version .
*
* The query can be one of two kinds :
*
* 1. A simple query which must contain a % d and a % s , which will be replaced
@ -3808,13 +4002,20 @@ complete_from_schema_query(const char *text, int state)
* % d % s % d % s % d % s % s % d % s
* where % d is the string length of the text and % s the text itself .
*
* If both simple_query and schema_query are non - NULL , then we construct
* a schema query and append the ( uninterpreted ) string simple_query to it .
*
* It is assumed that strings should be escaped to become SQL literals
* ( that is , what is in the query is actually . . . ' % s ' . . . )
*
* See top of file for examples of both kinds of query .
*
* " text " and " state " are supplied by readline .
*/
static char *
_complete_from_query ( int is_schema_query , const char * text , int state )
_complete_from_query ( const char * simple_query ,
const SchemaQuery * schema_query ,
const char * text , int state )
{
static int list_index ,
byte_length ;
@ -3865,26 +4066,26 @@ _complete_from_query(int is_schema_query, const char *text, int state)
initPQExpBuffer ( & query_buffer ) ;
if ( is_ schema_query)
if ( schema_query )
{
/* completion_s query gives us the pieces to assemble */
const char * qualresult = completion_s query- > qualresult ;
/* schema_ query gives us the pieces to assemble */
const char * qualresult = schema_ query- > qualresult ;
if ( qualresult = = NULL )
qualresult = completion_s query- > result ;
qualresult = schema_ query- > result ;
/* Get unqualified names matching the input-so-far */
appendPQExpBuffer ( & query_buffer , " SELECT %s FROM %s WHERE " ,
completion_s query- > result ,
completion_s query- > catname ) ;
if ( completion_s query- > selcondition )
schema_ query- > result ,
schema_ query- > catname ) ;
if ( schema_ query- > selcondition )
appendPQExpBuffer ( & query_buffer , " %s AND " ,
completion_s query- > selcondition ) ;
schema_ query- > selcondition ) ;
appendPQExpBuffer ( & query_buffer , " substring(%s,1,%d)='%s' " ,
completion_s query- > result ,
schema_ query- > result ,
char_length , e_text ) ;
appendPQExpBuffer ( & query_buffer , " AND %s " ,
completion_s query- > viscondition ) ;
schema_ query- > viscondition ) ;
/*
* When fetching relation names , suppress system catalogs unless
@ -3892,7 +4093,7 @@ _complete_from_query(int is_schema_query, const char *text, int state)
* between not offering system catalogs for completion at all , and
* having them swamp the result when the input is just " p " .
*/
if ( strcmp ( completion_s query- > catname ,
if ( strcmp ( schema_ query- > catname ,
" pg_catalog.pg_class c " ) = = 0 & &
strncmp ( text , " pg_ " , 3 ) ! = 0 )
{
@ -3926,11 +4127,11 @@ _complete_from_query(int is_schema_query, const char *text, int state)
" FROM %s, pg_catalog.pg_namespace n "
" WHERE %s = n.oid AND " ,
qualresult ,
completion_s query- > catname ,
completion_s query- > namespace ) ;
if ( completion_s query- > selcondition )
schema_ query- > catname ,
schema_ query- > namespace ) ;
if ( schema_ query- > selcondition )
appendPQExpBuffer ( & query_buffer , " %s AND " ,
completion_s query- > selcondition ) ;
schema_ query- > selcondition ) ;
appendPQExpBuffer ( & query_buffer , " substring(pg_catalog.quote_ident(n.nspname) || '.' || %s,1,%d)='%s' " ,
qualresult ,
char_length , e_text ) ;
@ -3951,13 +4152,14 @@ _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 ( simple_query )
appendPQExpBuffer ( & query_buffer , " \n %s " , simple_query ) ;
}
else
{
/* completion_charp is an sprintf-style format string */
appendPQExpBuffer ( & query_buffer , completion_charp ,
Assert ( simple_query ) ;
/* simple_query is an sprintf-style format string */
appendPQExpBuffer ( & query_buffer , simple_query ,
char_length , e_text ,
e_info_charp , e_info_charp ,
e_info_charp2 , e_info_charp2 ) ;