Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b48b9cb

Browse files
committed
Teach psql to do tab completion for names of psql variables.
Completion is supported in the context of \set and when interpolating a variable value using :foo etc. In passing, fix some places in tab-complete.c that weren't following project style for comment formatting. Pavel Stehule, reviewed by Itagaki Takahiro
1 parent 2ec993a commit b48b9cb

File tree

1 file changed

+134
-63
lines changed

1 file changed

+134
-63
lines changed

src/bin/psql/tab-complete.c

Lines changed: 134 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -576,20 +576,24 @@ static char *complete_from_query(const char *text, int state);
576576
static char *complete_from_schema_query(const char *text, int state);
577577
static char *_complete_from_query(int is_schema_query,
578578
const char *text, int state);
579-
static char *complete_from_const(const char *text, int state);
580579
static char *complete_from_list(const char *text, int state);
580+
static char *complete_from_const(const char *text, int state);
581+
static char **complete_from_variables(char *text,
582+
const char *prefix, const char *suffix);
581583

582584
static PGresult *exec_query(const char *query);
583585

584586
static char *previous_word(int point, int skip);
585587

586-
#if 0
588+
#ifdef NOT_USED
587589
static char *quote_file_name(char *text, int match_type, char *quote_pointer);
588590
static char *dequote_file_name(char *text, char quote_char);
589591
#endif
590592

591593

592-
/* Initialize the readline library for our purposes. */
594+
/*
595+
* Initialize the readline library for our purposes.
596+
*/
593597
void
594598
initialize_readline(void)
595599
{
@@ -607,11 +611,14 @@ initialize_readline(void)
607611
}
608612

609613

610-
/* The completion function. Acc. to readline spec this gets passed the text
611-
entered to far and its start and end in the readline buffer. The return value
612-
is some partially obscure list format that can be generated by the readline
613-
libraries completion_matches() function, so we don't have to worry about it.
614-
*/
614+
/*
615+
* The completion function.
616+
*
617+
* According to readline spec this gets passed the text entered so far and its
618+
* start and end positions in the readline buffer. The return value is some
619+
* partially obscure list format that can be generated by readline's
620+
* completion_matches() function, so we don't have to worry about it.
621+
*/
615622
static char **
616623
psql_completion(char *text, int start, int end)
617624
{
@@ -1943,7 +1950,7 @@ psql_completion(char *text, int start, int end)
19431950
pg_strcasecmp(prev_wd, "WRAPPER") == 0)
19441951
COMPLETE_WITH_QUERY(Query_for_list_of_fdws);
19451952

1946-
/* GRANT && REVOKE*/
1953+
/* GRANT && REVOKE */
19471954
/* Complete GRANT/REVOKE with a list of privileges */
19481955
else if (pg_strcasecmp(prev_wd, "GRANT") == 0 ||
19491956
pg_strcasecmp(prev_wd, "REVOKE") == 0)
@@ -2512,7 +2519,6 @@ psql_completion(char *text, int start, int end)
25122519
pg_strcasecmp(prev3_wd, "\\copy") != 0)
25132520
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv, NULL);
25142521

2515-
25162522
/* Backslash commands */
25172523
/* TODO: \dc \dd \dl */
25182524
else if (strcmp(prev_wd, "\\connect") == 0 || strcmp(prev_wd, "\\c") == 0)
@@ -2582,6 +2588,10 @@ psql_completion(char *text, int start, int end)
25822588

25832589
COMPLETE_WITH_LIST(my_list);
25842590
}
2591+
else if (strcmp(prev_wd, "\\set") == 0)
2592+
{
2593+
matches = complete_from_variables(text, "", "");
2594+
}
25852595
else if (strcmp(prev_wd, "\\sf") == 0 || strcmp(prev_wd, "\\sf+") == 0)
25862596
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
25872597
else if (strcmp(prev_wd, "\\cd") == 0 ||
@@ -2594,6 +2604,16 @@ psql_completion(char *text, int start, int end)
25942604
)
25952605
matches = completion_matches(text, filename_completion_function);
25962606

2607+
/* Variable interpolation */
2608+
else if (text[0] == ':' && text[1] != ':')
2609+
{
2610+
if (text[1] == '\'')
2611+
matches = complete_from_variables(text, ":'", "'");
2612+
else if (text[1] == '"')
2613+
matches = complete_from_variables(text, ":\"", "\"");
2614+
else
2615+
matches = complete_from_variables(text, ":", "");
2616+
}
25972617

25982618
/*
25992619
* Finally, we look through the list of "things", such as TABLE, INDEX and
@@ -2643,23 +2663,24 @@ psql_completion(char *text, int start, int end)
26432663
}
26442664

26452665

2666+
/*
2667+
* GENERATOR FUNCTIONS
2668+
*
2669+
* These functions do all the actual work of completing the input. They get
2670+
* passed the text so far and the count how many times they have been called
2671+
* so far with the same text.
2672+
* If you read the above carefully, you'll see that these don't get called
2673+
* directly but through the readline interface.
2674+
* The return value is expected to be the full completion of the text, going
2675+
* through a list each time, or NULL if there are no more matches. The string
2676+
* will be free()'d by readline, so you must run it through strdup() or
2677+
* something of that sort.
2678+
*/
26462679

2647-
/* GENERATOR FUNCTIONS
2648-
2649-
These functions do all the actual work of completing the input. They get
2650-
passed the text so far and the count how many times they have been called so
2651-
far with the same text.
2652-
If you read the above carefully, you'll see that these don't get called
2653-
directly but through the readline interface.
2654-
The return value is expected to be the full completion of the text, going
2655-
through a list each time, or NULL if there are no more matches. The string
2656-
will be free()'d by readline, so you must run it through strdup() or
2657-
something of that sort.
2658-
*/
2659-
2660-
/* This one gives you one from a list of things you can put after CREATE
2661-
as defined above.
2662-
*/
2680+
/*
2681+
* This one gives you one from a list of things you can put after CREATE
2682+
* as defined above.
2683+
*/
26632684
static char *
26642685
create_command_generator(const char *text, int state)
26652686
{
@@ -2677,7 +2698,8 @@ create_command_generator(const char *text, int state)
26772698
/* find something that matches */
26782699
while ((name = words_after_create[list_index++].name))
26792700
{
2680-
if ((pg_strncasecmp(name, text, string_length) == 0) && !words_after_create[list_index - 1].noshow)
2701+
if ((pg_strncasecmp(name, text, string_length) == 0) &&
2702+
!words_after_create[list_index - 1].noshow)
26812703
return pg_strdup(name);
26822704
}
26832705
/* if nothing matches, return NULL */
@@ -2745,26 +2767,27 @@ complete_from_schema_query(const char *text, int state)
27452767
}
27462768

27472769

2748-
/* This creates a list of matching things, according to a query pointed to
2749-
by completion_charp.
2750-
The query can be one of two kinds:
2751-
- A simple query which must contain a %d and a %s, which will be replaced
2752-
by the string length of the text and the text itself. The query may also
2753-
have up to four more %s in it; the first two such will be replaced by the
2754-
value of completion_info_charp, the next two by the value of
2755-
completion_info_charp2.
2756-
or:
2757-
- A schema query used for completion of both schema and relation names;
2758-
these are more complex and must contain in the following order:
2759-
%d %s %d %s %d %s %s %d %s
2760-
where %d is the string length of the text and %s the text itself.
2761-
2762-
It is assumed that strings should be escaped to become SQL literals
2763-
(that is, what is in the query is actually ... '%s' ...)
2764-
2765-
See top of file for examples of both kinds of query.
2766-
*/
2767-
2770+
/*
2771+
* This creates a list of matching things, according to a query pointed to
2772+
* by completion_charp.
2773+
* The query can be one of two kinds:
2774+
*
2775+
* 1. A simple query which must contain a %d and a %s, which will be replaced
2776+
* by the string length of the text and the text itself. The query may also
2777+
* have up to four more %s in it; the first two such will be replaced by the
2778+
* value of completion_info_charp, the next two by the value of
2779+
* completion_info_charp2.
2780+
*
2781+
* 2. A schema query used for completion of both schema and relation names.
2782+
* These are more complex and must contain in the following order:
2783+
* %d %s %d %s %d %s %s %d %s
2784+
* where %d is the string length of the text and %s the text itself.
2785+
*
2786+
* It is assumed that strings should be escaped to become SQL literals
2787+
* (that is, what is in the query is actually ... '%s' ...)
2788+
*
2789+
* See top of file for examples of both kinds of query.
2790+
*/
27682791
static char *
27692792
_complete_from_query(int is_schema_query, const char *text, int state)
27702793
{
@@ -2950,10 +2973,11 @@ _complete_from_query(int is_schema_query, const char *text, int state)
29502973
}
29512974

29522975

2953-
/* This function returns in order one of a fixed, NULL pointer terminated list
2954-
of strings (if matching). This can be used if there are only a fixed number
2955-
SQL words that can appear at certain spot.
2956-
*/
2976+
/*
2977+
* This function returns in order one of a fixed, NULL pointer terminated list
2978+
* of strings (if matching). This can be used if there are only a fixed number
2979+
* SQL words that can appear at certain spot.
2980+
*/
29572981
static char *
29582982
complete_from_list(const char *text, int state)
29592983
{
@@ -3006,12 +3030,13 @@ complete_from_list(const char *text, int state)
30063030
}
30073031

30083032

3009-
/* This function returns one fixed string the first time even if it doesn't
3010-
match what's there, and nothing the second time. This should be used if there
3011-
is only one possibility that can appear at a certain spot, so misspellings
3012-
will be overwritten.
3013-
The string to be passed must be in completion_charp.
3014-
*/
3033+
/*
3034+
* This function returns one fixed string the first time even if it doesn't
3035+
* match what's there, and nothing the second time. This should be used if
3036+
* there is only one possibility that can appear at a certain spot, so
3037+
* misspellings will be overwritten. The string to be passed must be in
3038+
* completion_charp.
3039+
*/
30153040
static char *
30163041
complete_from_const(const char *text, int state)
30173042
{
@@ -3026,6 +3051,55 @@ complete_from_const(const char *text, int state)
30263051
}
30273052

30283053

3054+
/*
3055+
* This function supports completion with the name of a psql variable.
3056+
* The variable names can be prefixed and suffixed with additional text
3057+
* to support quoting usages.
3058+
*/
3059+
static char **
3060+
complete_from_variables(char *text, const char *prefix, const char *suffix)
3061+
{
3062+
char **matches;
3063+
int overhead = strlen(prefix) + strlen(suffix) + 1;
3064+
const char **varnames;
3065+
int nvars = 0;
3066+
int maxvars = 100;
3067+
int i;
3068+
struct _variable *ptr;
3069+
3070+
varnames = (const char **) pg_malloc((maxvars + 1) * sizeof(char *));
3071+
3072+
for (ptr = pset.vars->next; ptr; ptr = ptr->next)
3073+
{
3074+
char *buffer;
3075+
3076+
if (nvars >= maxvars)
3077+
{
3078+
maxvars *= 2;
3079+
varnames = (const char **) realloc(varnames,
3080+
(maxvars + 1) * sizeof(char *));
3081+
if (!varnames)
3082+
{
3083+
psql_error("out of memory\n");
3084+
exit(EXIT_FAILURE);
3085+
}
3086+
}
3087+
3088+
buffer = (char *) pg_malloc(strlen(ptr->name) + overhead);
3089+
sprintf(buffer, "%s%s%s", prefix, ptr->name, suffix);
3090+
varnames[nvars++] = buffer;
3091+
}
3092+
3093+
varnames[nvars] = NULL;
3094+
COMPLETE_WITH_LIST(varnames);
3095+
3096+
for (i = 0; i < nvars; i++)
3097+
free((void *) varnames[i]);
3098+
free(varnames);
3099+
3100+
return matches;
3101+
}
3102+
30293103

30303104
/* HELPER FUNCTIONS */
30313105

@@ -3046,7 +3120,7 @@ exec_query(const char *query)
30463120

30473121
if (PQresultStatus(result) != PGRES_TUPLES_OK)
30483122
{
3049-
#if 0
3123+
#ifdef NOT_USED
30503124
psql_error("tab completion query failed: %s\nQuery was:\n%s\n",
30513125
PQerrorMessage(pset.db), query);
30523126
#endif
@@ -3058,7 +3132,6 @@ exec_query(const char *query)
30583132
}
30593133

30603134

3061-
30623135
/*
30633136
* Return the word (space delimited) before point. Set skip > 0 to
30643137
* skip that many words; e.g. skip=1 finds the word before the
@@ -3133,7 +3206,7 @@ previous_word(int point, int skip)
31333206
return s;
31343207
}
31353208

3136-
#if 0
3209+
#ifdef NOT_USED
31373210

31383211
/*
31393212
* Surround a string with single quotes. This works for both SQL and
@@ -3158,8 +3231,6 @@ quote_file_name(char *text, int match_type, char *quote_pointer)
31583231
return s;
31593232
}
31603233

3161-
3162-
31633234
static char *
31643235
dequote_file_name(char *text, char quote_char)
31653236
{
@@ -3175,6 +3246,6 @@ dequote_file_name(char *text, char quote_char)
31753246

31763247
return s;
31773248
}
3178-
#endif /* 0 */
3249+
#endif /* NOT_USED */
31793250

31803251
#endif /* USE_READLINE */

0 commit comments

Comments
 (0)