aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2022-01-16 14:59:20 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2022-01-16 14:59:20 -0500
commitfe75517443b7c38f5251d007d06321655ce6c0b6 (patch)
treea966139f0f12d3fd1d2bb8c4c0de4e450c7b9e36 /src
parented48e3582e8447cb9969c366e46c82a56b7608cd (diff)
downloadpostgresql-fe75517443b7c38f5251d007d06321655ce6c0b6.tar.gz
postgresql-fe75517443b7c38f5251d007d06321655ce6c0b6.zip
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 cd69ec66c. 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 cd69ec66c came in. Discussion: https://postgr.es/m/8ca82d89-ec3d-8b28-8291-500efaf23b25@enterprisedb.com
Diffstat (limited to 'src')
-rw-r--r--src/bin/psql/t/010_tab_completion.pl13
-rw-r--r--src/bin/psql/tab-complete.c51
2 files changed, 57 insertions, 7 deletions
diff --git a/src/bin/psql/t/010_tab_completion.pl b/src/bin/psql/t/010_tab_completion.pl
index ba98b8190b6..d3d1bd650e7 100644
--- a/src/bin/psql/t/010_tab_completion.pl
+++ b/src/bin/psql/t/010_tab_completion.pl
@@ -42,7 +42,8 @@ $node->start;
$node->safe_psql('postgres',
"CREATE TABLE tab1 (f1 int, f2 text);\n"
. "CREATE TABLE mytab123 (f1 int, f2 text);\n"
- . "CREATE TABLE mytab246 (f1 int, f2 text);\n");
+ . "CREATE TABLE mytab246 (f1 int, f2 text);\n"
+ . "CREATE TYPE enum1 AS ENUM ('foo', 'bar', 'baz');\n");
# Developers would not appreciate this test adding a bunch of junk to
# their ~/.psql_history, so be sure to redirect history into a temp file.
@@ -223,6 +224,16 @@ check_completion(
clear_line();
+# check enum label completion
+# some versions of readline/libedit require two tabs here, some only need one
+# also, some versions will offer quotes, some will not
+check_completion(
+ "ALTER TYPE enum1 RENAME VALUE 'ba\t\t",
+ qr|'?bar'? +'?baz'?|,
+ "offer multiple enum choices");
+
+clear_line();
+
# send psql an explicit \q to shut it down, else pty won't close properly
$timer->start(5);
$in .= "\\q\n";
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index 71f1a5c00d9..6bd33a06cb1 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -278,25 +278,40 @@ do { \
matches = rl_completion_matches(text, complete_from_query); \
} while (0)
+/*
+ * libedit will typically include the literal's leading single quote in
+ * "text", while readline will not. Adapt our offered strings to fit.
+ * But include a quote if there's not one just before "text", to get the
+ * user off to the right start.
+ */
#define COMPLETE_WITH_ENUM_VALUE(type) \
do { \
char *_completion_schema; \
char *_completion_type; \
+ bool use_quotes; \
\
_completion_schema = strtokx(type, " \t\n\r", ".", "\"", 0, \
false, false, pset.encoding); \
(void) strtokx(NULL, " \t\n\r", ".", "\"", 0, \
false, false, pset.encoding); \
_completion_type = strtokx(NULL, " \t\n\r", ".", "\"", 0, \
- false, false, pset.encoding); \
- if (_completion_type == NULL)\
+ false, false, pset.encoding); \
+ use_quotes = (text[0] == '\'' || \
+ start == 0 || rl_line_buffer[start - 1] != '\''); \
+ if (_completion_type == NULL) \
{ \
- completion_charp = Query_for_list_of_enum_values; \
+ if (use_quotes) \
+ completion_charp = Query_for_list_of_enum_values_quoted; \
+ else \
+ completion_charp = Query_for_list_of_enum_values_unquoted; \
completion_info_charp = type; \
} \
else \
{ \
- completion_charp = Query_for_list_of_enum_values_with_schema; \
+ if (use_quotes) \
+ completion_charp = Query_for_list_of_enum_values_with_schema_quoted; \
+ else \
+ completion_charp = Query_for_list_of_enum_values_with_schema_unquoted; \
completion_info_charp = _completion_type; \
completion_info_charp2 = _completion_schema; \
} \
@@ -678,7 +693,7 @@ static const SchemaQuery Query_for_list_of_collations = {
" AND (pg_catalog.quote_ident(nspname)='%s' "\
" OR '\"' || nspname || '\"' ='%s') "
-#define Query_for_list_of_enum_values \
+#define Query_for_list_of_enum_values_quoted \
"SELECT pg_catalog.quote_literal(enumlabel) "\
" FROM pg_catalog.pg_enum e, pg_catalog.pg_type t "\
" WHERE t.oid = e.enumtypid "\
@@ -687,7 +702,16 @@ static const SchemaQuery Query_for_list_of_collations = {
" OR '\"' || typname || '\"'='%s') "\
" AND pg_catalog.pg_type_is_visible(t.oid)"
-#define Query_for_list_of_enum_values_with_schema \
+#define Query_for_list_of_enum_values_unquoted \
+"SELECT enumlabel "\
+" FROM pg_catalog.pg_enum e, pg_catalog.pg_type t "\
+" WHERE t.oid = e.enumtypid "\
+" AND substring(enumlabel,1,%d)='%s' "\
+" AND (pg_catalog.quote_ident(typname)='%s' "\
+" OR '\"' || typname || '\"'='%s') "\
+" AND pg_catalog.pg_type_is_visible(t.oid)"
+
+#define Query_for_list_of_enum_values_with_schema_quoted \
"SELECT pg_catalog.quote_literal(enumlabel) "\
" FROM pg_catalog.pg_enum e, pg_catalog.pg_type t, pg_catalog.pg_namespace n "\
" WHERE t.oid = e.enumtypid "\
@@ -698,6 +722,17 @@ static const SchemaQuery Query_for_list_of_collations = {
" AND (pg_catalog.quote_ident(nspname)='%s' "\
" OR '\"' || nspname || '\"' ='%s') "
+#define Query_for_list_of_enum_values_with_schema_unquoted \
+"SELECT enumlabel "\
+" FROM pg_catalog.pg_enum e, pg_catalog.pg_type t, pg_catalog.pg_namespace n "\
+" WHERE t.oid = e.enumtypid "\
+" AND n.oid = t.typnamespace "\
+" AND substring(enumlabel,1,%d)='%s' "\
+" AND (pg_catalog.quote_ident(typname)='%s' "\
+" OR '\"' || typname || '\"'='%s') "\
+" AND (pg_catalog.quote_ident(nspname)='%s' "\
+" OR '\"' || nspname || '\"' ='%s') "
+
#define Query_for_list_of_template_databases \
"SELECT pg_catalog.quote_ident(d.datname) "\
" FROM pg_catalog.pg_database d "\
@@ -4417,9 +4452,13 @@ psql_completion(const char *text, int start, int end)
if (matches == NULL)
{
COMPLETE_WITH_CONST(true, "");
+ /* Also, prevent Readline from appending stuff to the non-match */
#ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
rl_completion_append_character = '\0';
#endif
+#ifdef HAVE_RL_COMPLETION_SUPPRESS_QUOTE
+ rl_completion_suppress_quote = 1;
+#endif
}
/* free storage */