Skip to content

Commit 90a847e

Browse files
committed
Fix psql's tab-completion of enum label values.
Since enum labels have to be single-quoted, this part of the tab completion machinery got side-swiped by commit cd69ec6. A side-effect of that commit is that (at least with some versions of Readline) the text string passed for completion will omit the leading quote mark of the enum label literal. Libedit still acts the same as before, though, so adapt COMPLETE_WITH_ENUM_VALUE so that it can cope with either convention. Also, when we fail to find any valid completion, set rl_completion_suppress_quote = 1. Otherwise readline will go ahead and append a closing quote, which is unwanted. Per report from Peter Eisentraut. Back-patch to v13 where cd69ec6 came in. Discussion: https://postgr.es/m/8ca82d89-ec3d-8b28-8291-500efaf23b25@enterprisedb.com
1 parent d681703 commit 90a847e

File tree

2 files changed

+57
-7
lines changed

2 files changed

+57
-7
lines changed

src/bin/psql/t/010_tab_completion.pl

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@
3939
$node->safe_psql('postgres',
4040
"CREATE TABLE tab1 (f1 int, f2 text);\n"
4141
. "CREATE TABLE mytab123 (f1 int, f2 text);\n"
42-
. "CREATE TABLE mytab246 (f1 int, f2 text);\n");
42+
. "CREATE TABLE mytab246 (f1 int, f2 text);\n"
43+
. "CREATE TYPE enum1 AS ENUM ('foo', 'bar', 'baz');\n");
4344

4445
# Developers would not appreciate this test adding a bunch of junk to
4546
# their ~/.psql_history, so be sure to redirect history into a temp file.
@@ -220,6 +221,16 @@ sub clear_line
220221

221222
clear_line();
222223

224+
# check enum label completion
225+
# some versions of readline/libedit require two tabs here, some only need one
226+
# also, some versions will offer quotes, some will not
227+
check_completion(
228+
"ALTER TYPE enum1 RENAME VALUE 'ba\t\t",
229+
qr|'?bar'? +'?baz'?|,
230+
"offer multiple enum choices");
231+
232+
clear_line();
233+
223234
# send psql an explicit \q to shut it down, else pty won't close properly
224235
$timer->start(5);
225236
$in .= "\\q\n";

src/bin/psql/tab-complete.c

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -280,25 +280,40 @@ do { \
280280
matches = rl_completion_matches(text, complete_from_query); \
281281
} while (0)
282282

283+
/*
284+
* libedit will typically include the literal's leading single quote in
285+
* "text", while readline will not. Adapt our offered strings to fit.
286+
* But include a quote if there's not one just before "text", to get the
287+
* user off to the right start.
288+
*/
283289
#define COMPLETE_WITH_ENUM_VALUE(type) \
284290
do { \
285291
char *_completion_schema; \
286292
char *_completion_type; \
293+
bool use_quotes; \
287294
\
288295
_completion_schema = strtokx(type, " \t\n\r", ".", "\"", 0, \
289296
false, false, pset.encoding); \
290297
(void) strtokx(NULL, " \t\n\r", ".", "\"", 0, \
291298
false, false, pset.encoding); \
292299
_completion_type = strtokx(NULL, " \t\n\r", ".", "\"", 0, \
293-
false, false, pset.encoding); \
294-
if (_completion_type == NULL)\
300+
false, false, pset.encoding); \
301+
use_quotes = (text[0] == '\'' || \
302+
start == 0 || rl_line_buffer[start - 1] != '\''); \
303+
if (_completion_type == NULL) \
295304
{ \
296-
completion_charp = Query_for_list_of_enum_values; \
305+
if (use_quotes) \
306+
completion_charp = Query_for_list_of_enum_values_quoted; \
307+
else \
308+
completion_charp = Query_for_list_of_enum_values_unquoted; \
297309
completion_info_charp = type; \
298310
} \
299311
else \
300312
{ \
301-
completion_charp = Query_for_list_of_enum_values_with_schema; \
313+
if (use_quotes) \
314+
completion_charp = Query_for_list_of_enum_values_with_schema_quoted; \
315+
else \
316+
completion_charp = Query_for_list_of_enum_values_with_schema_unquoted; \
302317
completion_info_charp = _completion_type; \
303318
completion_info_charp2 = _completion_schema; \
304319
} \
@@ -654,7 +669,7 @@ static const SchemaQuery Query_for_list_of_statistics = {
654669
" AND (pg_catalog.quote_ident(nspname)='%s' "\
655670
" OR '\"' || nspname || '\"' ='%s') "
656671

657-
#define Query_for_list_of_enum_values \
672+
#define Query_for_list_of_enum_values_quoted \
658673
"SELECT pg_catalog.quote_literal(enumlabel) "\
659674
" FROM pg_catalog.pg_enum e, pg_catalog.pg_type t "\
660675
" WHERE t.oid = e.enumtypid "\
@@ -663,7 +678,16 @@ static const SchemaQuery Query_for_list_of_statistics = {
663678
" OR '\"' || typname || '\"'='%s') "\
664679
" AND pg_catalog.pg_type_is_visible(t.oid)"
665680

666-
#define Query_for_list_of_enum_values_with_schema \
681+
#define Query_for_list_of_enum_values_unquoted \
682+
"SELECT enumlabel "\
683+
" FROM pg_catalog.pg_enum e, pg_catalog.pg_type t "\
684+
" WHERE t.oid = e.enumtypid "\
685+
" AND substring(enumlabel,1,%d)='%s' "\
686+
" AND (pg_catalog.quote_ident(typname)='%s' "\
687+
" OR '\"' || typname || '\"'='%s') "\
688+
" AND pg_catalog.pg_type_is_visible(t.oid)"
689+
690+
#define Query_for_list_of_enum_values_with_schema_quoted \
667691
"SELECT pg_catalog.quote_literal(enumlabel) "\
668692
" FROM pg_catalog.pg_enum e, pg_catalog.pg_type t, pg_catalog.pg_namespace n "\
669693
" WHERE t.oid = e.enumtypid "\
@@ -674,6 +698,17 @@ static const SchemaQuery Query_for_list_of_statistics = {
674698
" AND (pg_catalog.quote_ident(nspname)='%s' "\
675699
" OR '\"' || nspname || '\"' ='%s') "
676700

701+
#define Query_for_list_of_enum_values_with_schema_unquoted \
702+
"SELECT enumlabel "\
703+
" FROM pg_catalog.pg_enum e, pg_catalog.pg_type t, pg_catalog.pg_namespace n "\
704+
" WHERE t.oid = e.enumtypid "\
705+
" AND n.oid = t.typnamespace "\
706+
" AND substring(enumlabel,1,%d)='%s' "\
707+
" AND (pg_catalog.quote_ident(typname)='%s' "\
708+
" OR '\"' || typname || '\"'='%s') "\
709+
" AND (pg_catalog.quote_ident(nspname)='%s' "\
710+
" OR '\"' || nspname || '\"' ='%s') "
711+
677712
#define Query_for_list_of_template_databases \
678713
"SELECT pg_catalog.quote_ident(d.datname) "\
679714
" FROM pg_catalog.pg_database d "\
@@ -3934,8 +3969,12 @@ psql_completion(const char *text, int start, int end)
39343969
if (matches == NULL)
39353970
{
39363971
COMPLETE_WITH_CONST(true, "");
3972+
/* Also, prevent Readline from appending stuff to the non-match */
39373973
#ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
39383974
rl_completion_append_character = '\0';
3975+
#endif
3976+
#ifdef HAVE_RL_COMPLETION_SUPPRESS_QUOTE
3977+
rl_completion_suppress_quote = 1;
39393978
#endif
39403979
}
39413980

0 commit comments

Comments
 (0)