Skip to content

Commit 3ae1679

Browse files
committed
psql: Generic tab completion support for enum and bool GUCs.
Author: Pavel Stehule Reviewed-By: Andres Freund Discussion: 5594FE7A.5050205@iki.fi
1 parent 043113e commit 3ae1679

File tree

1 file changed

+97
-35
lines changed

1 file changed

+97
-35
lines changed

src/bin/psql/tab-complete.c

Lines changed: 97 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -759,6 +759,15 @@ static const SchemaQuery Query_for_list_of_matviews = {
759759
" (SELECT polrelid FROM pg_catalog.pg_policy "\
760760
" WHERE pg_catalog.quote_ident(polname)='%s')"
761761

762+
#define Query_for_enum \
763+
" SELECT name FROM ( "\
764+
" SELECT pg_catalog.quote_ident(pg_catalog.unnest(enumvals)) AS name "\
765+
" FROM pg_catalog.pg_settings "\
766+
" WHERE pg_catalog.lower(name)=pg_catalog.lower('%s') "\
767+
" UNION ALL " \
768+
" SELECT 'DEFAULT' ) ss "\
769+
" WHERE pg_catalog.substring(name,1,%%d)='%%s'"
770+
762771
/*
763772
* This is a list of all "things" in Pgsql, which can show up after CREATE or
764773
* DROP; and there is also a query to get a list of them.
@@ -845,10 +854,13 @@ static char **complete_from_variables(const char *text,
845854
static char *complete_from_files(const char *text, int state);
846855

847856
static char *pg_strdup_keyword_case(const char *s, const char *ref);
857+
static char *escape_string(const char *text);
848858
static PGresult *exec_query(const char *query);
849859

850860
static void get_previous_words(int point, char **previous_words, int nwords);
851861

862+
static char *get_guctype(const char *varname);
863+
852864
#ifdef NOT_USED
853865
static char *quote_file_name(char *text, int match_type, char *quote_pointer);
854866
static char *dequote_file_name(char *text, char quote_char);
@@ -3684,6 +3696,7 @@ psql_completion(const char *text, int start, int end)
36843696
else if (pg_strcasecmp(prev3_wd, "SET") == 0 &&
36853697
(pg_strcasecmp(prev_wd, "TO") == 0 || strcmp(prev_wd, "=") == 0))
36863698
{
3699+
/* special cased code for individual GUCs */
36873700
if (pg_strcasecmp(prev2_wd, "DateStyle") == 0)
36883701
{
36893702
static const char *const my_list[] =
@@ -3694,20 +3707,6 @@ psql_completion(const char *text, int start, int end)
36943707

36953708
COMPLETE_WITH_LIST(my_list);
36963709
}
3697-
else if (pg_strcasecmp(prev2_wd, "IntervalStyle") == 0)
3698-
{
3699-
static const char *const my_list[] =
3700-
{"postgres", "postgres_verbose", "sql_standard", "iso_8601", NULL};
3701-
3702-
COMPLETE_WITH_LIST(my_list);
3703-
}
3704-
else if (pg_strcasecmp(prev2_wd, "GEQO") == 0)
3705-
{
3706-
static const char *const my_list[] =
3707-
{"ON", "OFF", "DEFAULT", NULL};
3708-
3709-
COMPLETE_WITH_LIST(my_list);
3710-
}
37113710
else if (pg_strcasecmp(prev2_wd, "search_path") == 0)
37123711
{
37133712
COMPLETE_WITH_QUERY(Query_for_list_of_schemas
@@ -3717,10 +3716,34 @@ psql_completion(const char *text, int start, int end)
37173716
}
37183717
else
37193718
{
3720-
static const char *const my_list[] =
3721-
{"DEFAULT", NULL};
3719+
/* generic, type based, GUC support */
37223720

3723-
COMPLETE_WITH_LIST(my_list);
3721+
char *guctype = get_guctype(prev2_wd);
3722+
3723+
if (guctype && strcmp(guctype, "enum") == 0)
3724+
{
3725+
char querybuf[1024];
3726+
3727+
snprintf(querybuf, 1024, Query_for_enum, prev2_wd);
3728+
COMPLETE_WITH_QUERY(querybuf);
3729+
}
3730+
else if (guctype && strcmp(guctype, "bool") == 0)
3731+
{
3732+
static const char *const my_list[] =
3733+
{"on", "off", "true", "false", "yes", "no", "1", "0", "DEFAULT", NULL};
3734+
3735+
COMPLETE_WITH_LIST(my_list);
3736+
}
3737+
else
3738+
{
3739+
static const char *const my_list[] =
3740+
{"DEFAULT", NULL};
3741+
3742+
COMPLETE_WITH_LIST(my_list);
3743+
}
3744+
3745+
if (guctype)
3746+
free(guctype);
37243747
}
37253748
}
37263749

@@ -4263,30 +4286,15 @@ _complete_from_query(int is_schema_query, const char *text, int state)
42634286
result = NULL;
42644287

42654288
/* Set up suitably-escaped copies of textual inputs */
4266-
e_text = pg_malloc(string_length * 2 + 1);
4267-
PQescapeString(e_text, text, string_length);
4289+
e_text = escape_string(text);
42684290

42694291
if (completion_info_charp)
4270-
{
4271-
size_t charp_len;
4272-
4273-
charp_len = strlen(completion_info_charp);
4274-
e_info_charp = pg_malloc(charp_len * 2 + 1);
4275-
PQescapeString(e_info_charp, completion_info_charp,
4276-
charp_len);
4277-
}
4292+
e_info_charp = escape_string(completion_info_charp);
42784293
else
42794294
e_info_charp = NULL;
42804295

42814296
if (completion_info_charp2)
4282-
{
4283-
size_t charp_len;
4284-
4285-
charp_len = strlen(completion_info_charp2);
4286-
e_info_charp2 = pg_malloc(charp_len * 2 + 1);
4287-
PQescapeString(e_info_charp2, completion_info_charp2,
4288-
charp_len);
4289-
}
4297+
e_info_charp2 = escape_string(completion_info_charp2);
42904298
else
42914299
e_info_charp2 = NULL;
42924300

@@ -4677,6 +4685,26 @@ pg_strdup_keyword_case(const char *s, const char *ref)
46774685
}
46784686

46794687

4688+
/*
4689+
* escape_string - Escape argument for use as string literal.
4690+
*
4691+
* The returned value has to be freed.
4692+
*/
4693+
static char *
4694+
escape_string(const char *text)
4695+
{
4696+
size_t text_length;
4697+
char *result;
4698+
4699+
text_length = strlen(text);
4700+
4701+
result = pg_malloc(text_length * 2 + 1);
4702+
PQescapeStringConn(pset.db, result, text, text_length, NULL);
4703+
4704+
return result;
4705+
}
4706+
4707+
46804708
/*
46814709
* Execute a query and report any errors. This should be the preferred way of
46824710
* talking to the database in this file.
@@ -4790,6 +4818,40 @@ get_previous_words(int point, char **previous_words, int nwords)
47904818
}
47914819
}
47924820

4821+
/*
4822+
* Look up the type for the GUC variable with the passed name.
4823+
*
4824+
* Returns NULL if the variable is unknown. Otherwise the returned string,
4825+
* containing the type, has to be freed.
4826+
*/
4827+
static char *
4828+
get_guctype(const char *varname)
4829+
{
4830+
PQExpBufferData query_buffer;
4831+
char *e_varname;
4832+
PGresult *result;
4833+
char *guctype = NULL;
4834+
4835+
e_varname = escape_string(varname);
4836+
4837+
initPQExpBuffer(&query_buffer);
4838+
appendPQExpBuffer(&query_buffer,
4839+
"SELECT vartype FROM pg_catalog.pg_settings "
4840+
"WHERE pg_catalog.lower(name) = pg_catalog.lower('%s')",
4841+
e_varname);
4842+
4843+
result = exec_query(query_buffer.data);
4844+
termPQExpBuffer(&query_buffer);
4845+
free(e_varname);
4846+
4847+
if (PQresultStatus(result) == PGRES_TUPLES_OK && PQntuples(result) > 0)
4848+
guctype = pg_strdup(PQgetvalue(result, 0, 0));
4849+
4850+
PQclear(result);
4851+
4852+
return guctype;
4853+
}
4854+
47934855
#ifdef NOT_USED
47944856

47954857
/*

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy