mirror of
https://github.com/postgres/postgres.git
synced 2025-07-17 06:41:09 +03:00
psql: Generic tab completion support for enum and bool GUCs.
Author: Pavel Stehule Reviewed-By: Andres Freund Discussion: 5594FE7A.5050205@iki.fi
This commit is contained in:
@ -759,6 +759,15 @@ static const SchemaQuery Query_for_list_of_matviews = {
|
|||||||
" (SELECT polrelid FROM pg_catalog.pg_policy "\
|
" (SELECT polrelid FROM pg_catalog.pg_policy "\
|
||||||
" WHERE pg_catalog.quote_ident(polname)='%s')"
|
" WHERE pg_catalog.quote_ident(polname)='%s')"
|
||||||
|
|
||||||
|
#define Query_for_enum \
|
||||||
|
" SELECT name FROM ( "\
|
||||||
|
" SELECT pg_catalog.quote_ident(pg_catalog.unnest(enumvals)) AS name "\
|
||||||
|
" FROM pg_catalog.pg_settings "\
|
||||||
|
" WHERE pg_catalog.lower(name)=pg_catalog.lower('%s') "\
|
||||||
|
" UNION ALL " \
|
||||||
|
" SELECT 'DEFAULT' ) ss "\
|
||||||
|
" WHERE pg_catalog.substring(name,1,%%d)='%%s'"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is a list of all "things" in Pgsql, which can show up after CREATE or
|
* 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.
|
* 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,
|
|||||||
static char *complete_from_files(const char *text, int state);
|
static char *complete_from_files(const char *text, int state);
|
||||||
|
|
||||||
static char *pg_strdup_keyword_case(const char *s, const char *ref);
|
static char *pg_strdup_keyword_case(const char *s, const char *ref);
|
||||||
|
static char *escape_string(const char *text);
|
||||||
static PGresult *exec_query(const char *query);
|
static PGresult *exec_query(const char *query);
|
||||||
|
|
||||||
static void get_previous_words(int point, char **previous_words, int nwords);
|
static void get_previous_words(int point, char **previous_words, int nwords);
|
||||||
|
|
||||||
|
static char *get_guctype(const char *varname);
|
||||||
|
|
||||||
#ifdef NOT_USED
|
#ifdef NOT_USED
|
||||||
static char *quote_file_name(char *text, int match_type, char *quote_pointer);
|
static char *quote_file_name(char *text, int match_type, char *quote_pointer);
|
||||||
static char *dequote_file_name(char *text, char quote_char);
|
static char *dequote_file_name(char *text, char quote_char);
|
||||||
@ -3684,6 +3696,7 @@ psql_completion(const char *text, int start, int end)
|
|||||||
else if (pg_strcasecmp(prev3_wd, "SET") == 0 &&
|
else if (pg_strcasecmp(prev3_wd, "SET") == 0 &&
|
||||||
(pg_strcasecmp(prev_wd, "TO") == 0 || strcmp(prev_wd, "=") == 0))
|
(pg_strcasecmp(prev_wd, "TO") == 0 || strcmp(prev_wd, "=") == 0))
|
||||||
{
|
{
|
||||||
|
/* special cased code for individual GUCs */
|
||||||
if (pg_strcasecmp(prev2_wd, "DateStyle") == 0)
|
if (pg_strcasecmp(prev2_wd, "DateStyle") == 0)
|
||||||
{
|
{
|
||||||
static const char *const my_list[] =
|
static const char *const my_list[] =
|
||||||
@ -3694,20 +3707,6 @@ psql_completion(const char *text, int start, int end)
|
|||||||
|
|
||||||
COMPLETE_WITH_LIST(my_list);
|
COMPLETE_WITH_LIST(my_list);
|
||||||
}
|
}
|
||||||
else if (pg_strcasecmp(prev2_wd, "IntervalStyle") == 0)
|
|
||||||
{
|
|
||||||
static const char *const my_list[] =
|
|
||||||
{"postgres", "postgres_verbose", "sql_standard", "iso_8601", NULL};
|
|
||||||
|
|
||||||
COMPLETE_WITH_LIST(my_list);
|
|
||||||
}
|
|
||||||
else if (pg_strcasecmp(prev2_wd, "GEQO") == 0)
|
|
||||||
{
|
|
||||||
static const char *const my_list[] =
|
|
||||||
{"ON", "OFF", "DEFAULT", NULL};
|
|
||||||
|
|
||||||
COMPLETE_WITH_LIST(my_list);
|
|
||||||
}
|
|
||||||
else if (pg_strcasecmp(prev2_wd, "search_path") == 0)
|
else if (pg_strcasecmp(prev2_wd, "search_path") == 0)
|
||||||
{
|
{
|
||||||
COMPLETE_WITH_QUERY(Query_for_list_of_schemas
|
COMPLETE_WITH_QUERY(Query_for_list_of_schemas
|
||||||
@ -3716,12 +3715,36 @@ psql_completion(const char *text, int start, int end)
|
|||||||
" UNION SELECT 'DEFAULT' ");
|
" UNION SELECT 'DEFAULT' ");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
/* generic, type based, GUC support */
|
||||||
|
|
||||||
|
char *guctype = get_guctype(prev2_wd);
|
||||||
|
|
||||||
|
if (guctype && strcmp(guctype, "enum") == 0)
|
||||||
|
{
|
||||||
|
char querybuf[1024];
|
||||||
|
|
||||||
|
snprintf(querybuf, 1024, Query_for_enum, prev2_wd);
|
||||||
|
COMPLETE_WITH_QUERY(querybuf);
|
||||||
|
}
|
||||||
|
else if (guctype && strcmp(guctype, "bool") == 0)
|
||||||
|
{
|
||||||
|
static const char *const my_list[] =
|
||||||
|
{"on", "off", "true", "false", "yes", "no", "1", "0", "DEFAULT", NULL};
|
||||||
|
|
||||||
|
COMPLETE_WITH_LIST(my_list);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
static const char *const my_list[] =
|
static const char *const my_list[] =
|
||||||
{"DEFAULT", NULL};
|
{"DEFAULT", NULL};
|
||||||
|
|
||||||
COMPLETE_WITH_LIST(my_list);
|
COMPLETE_WITH_LIST(my_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (guctype)
|
||||||
|
free(guctype);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* START TRANSACTION */
|
/* START TRANSACTION */
|
||||||
@ -4263,30 +4286,15 @@ _complete_from_query(int is_schema_query, const char *text, int state)
|
|||||||
result = NULL;
|
result = NULL;
|
||||||
|
|
||||||
/* Set up suitably-escaped copies of textual inputs */
|
/* Set up suitably-escaped copies of textual inputs */
|
||||||
e_text = pg_malloc(string_length * 2 + 1);
|
e_text = escape_string(text);
|
||||||
PQescapeString(e_text, text, string_length);
|
|
||||||
|
|
||||||
if (completion_info_charp)
|
if (completion_info_charp)
|
||||||
{
|
e_info_charp = escape_string(completion_info_charp);
|
||||||
size_t charp_len;
|
|
||||||
|
|
||||||
charp_len = strlen(completion_info_charp);
|
|
||||||
e_info_charp = pg_malloc(charp_len * 2 + 1);
|
|
||||||
PQescapeString(e_info_charp, completion_info_charp,
|
|
||||||
charp_len);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
e_info_charp = NULL;
|
e_info_charp = NULL;
|
||||||
|
|
||||||
if (completion_info_charp2)
|
if (completion_info_charp2)
|
||||||
{
|
e_info_charp2 = escape_string(completion_info_charp2);
|
||||||
size_t charp_len;
|
|
||||||
|
|
||||||
charp_len = strlen(completion_info_charp2);
|
|
||||||
e_info_charp2 = pg_malloc(charp_len * 2 + 1);
|
|
||||||
PQescapeString(e_info_charp2, completion_info_charp2,
|
|
||||||
charp_len);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
e_info_charp2 = NULL;
|
e_info_charp2 = NULL;
|
||||||
|
|
||||||
@ -4677,6 +4685,26 @@ pg_strdup_keyword_case(const char *s, const char *ref)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* escape_string - Escape argument for use as string literal.
|
||||||
|
*
|
||||||
|
* The returned value has to be freed.
|
||||||
|
*/
|
||||||
|
static char *
|
||||||
|
escape_string(const char *text)
|
||||||
|
{
|
||||||
|
size_t text_length;
|
||||||
|
char *result;
|
||||||
|
|
||||||
|
text_length = strlen(text);
|
||||||
|
|
||||||
|
result = pg_malloc(text_length * 2 + 1);
|
||||||
|
PQescapeStringConn(pset.db, result, text, text_length, NULL);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Execute a query and report any errors. This should be the preferred way of
|
* Execute a query and report any errors. This should be the preferred way of
|
||||||
* talking to the database in this file.
|
* talking to the database in this file.
|
||||||
@ -4790,6 +4818,40 @@ get_previous_words(int point, char **previous_words, int nwords)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Look up the type for the GUC variable with the passed name.
|
||||||
|
*
|
||||||
|
* Returns NULL if the variable is unknown. Otherwise the returned string,
|
||||||
|
* containing the type, has to be freed.
|
||||||
|
*/
|
||||||
|
static char *
|
||||||
|
get_guctype(const char *varname)
|
||||||
|
{
|
||||||
|
PQExpBufferData query_buffer;
|
||||||
|
char *e_varname;
|
||||||
|
PGresult *result;
|
||||||
|
char *guctype = NULL;
|
||||||
|
|
||||||
|
e_varname = escape_string(varname);
|
||||||
|
|
||||||
|
initPQExpBuffer(&query_buffer);
|
||||||
|
appendPQExpBuffer(&query_buffer,
|
||||||
|
"SELECT vartype FROM pg_catalog.pg_settings "
|
||||||
|
"WHERE pg_catalog.lower(name) = pg_catalog.lower('%s')",
|
||||||
|
e_varname);
|
||||||
|
|
||||||
|
result = exec_query(query_buffer.data);
|
||||||
|
termPQExpBuffer(&query_buffer);
|
||||||
|
free(e_varname);
|
||||||
|
|
||||||
|
if (PQresultStatus(result) == PGRES_TUPLES_OK && PQntuples(result) > 0)
|
||||||
|
guctype = pg_strdup(PQgetvalue(result, 0, 0));
|
||||||
|
|
||||||
|
PQclear(result);
|
||||||
|
|
||||||
|
return guctype;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef NOT_USED
|
#ifdef NOT_USED
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Reference in New Issue
Block a user