Skip to content

Commit f0cd909

Browse files
committed
Further tweaks for psql's new tab-completion logic.
The behavior I proposed, of matching case only when only keywords are available to complete, turns out to be too cute. It adds about as many problems as it removes. Simplify down to ilmari's original proposal of just always matching case when completing a keyword. Also, I noticed while testing this that we've pessimized the behavior for qualified GUC names: the code is insisting that they be double-quoted, which was not the case before. Fix that by treating GUC names as verbatim matches instead of possibly-schema-qualified names. (While it's tempting to try to split qualified GUC names so that we *could* treat them with the schema-qualified-name code path, that really isn't going to work in light of guc.c's willingness to allow more than two name components.) Dagfinn Ilmari Mannsåker and Tom Lane Discussion: https://postgr.es/m/445692.1644018081@sss.pgh.pa.us
1 parent c5f5b4d commit f0cd909

File tree

2 files changed

+56
-31
lines changed

2 files changed

+56
-31
lines changed

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

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -339,8 +339,7 @@ sub clear_line
339339
clear_line();
340340

341341
# check completion of a keyword offered in addition to object names;
342-
# such a keyword should obey COMP_KEYWORD_CASE once only keyword
343-
# completions are possible
342+
# such a keyword should obey COMP_KEYWORD_CASE
344343
foreach (
345344
[ 'lower', 'CO', 'column' ],
346345
[ 'upper', 'co', 'COLUMN' ],
@@ -353,10 +352,6 @@ sub clear_line
353352
"\\set COMP_KEYWORD_CASE $case\n",
354353
qr/postgres=#/,
355354
"set completion case to '$case'");
356-
check_completion("alter table tab1 rename c\t\t",
357-
qr|COLUMN|,
358-
"offer keyword COLUMN for input c<TAB>, COMP_KEYWORD_CASE = $case");
359-
clear_query();
360355
check_completion("alter table tab1 rename $in\t\t\t",
361356
qr|$out|,
362357
"offer keyword $out for input $in<TAB>, COMP_KEYWORD_CASE = $case");
@@ -410,6 +405,23 @@ sub clear_line
410405

411406
clear_query();
412407

408+
# same, for qualified GUC names
409+
check_completion(
410+
"DO \$\$begin end\$\$ LANGUAGE plpgsql;\n",
411+
qr/postgres=# /,
412+
"load plpgsql extension");
413+
414+
check_completion("set plpg\t", qr/plpg\a?sql\./,
415+
"complete prefix of a GUC name");
416+
check_completion(
417+
"var\t\t",
418+
qr/variable_conflict TO/,
419+
"complete a qualified GUC name");
420+
check_completion(" USE_C\t",
421+
qr/use_column/, "complete a qualified GUC enum value");
422+
423+
clear_query();
424+
413425
# check completions for psql variables
414426
check_completion("\\set VERB\t", qr/VERBOSITY /,
415427
"complete a psql variable name");

src/bin/psql/tab-complete.c

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -257,13 +257,22 @@ do { \
257257
} while (0)
258258

259259
#define COMPLETE_WITH_QUERY_VERBATIM(query) \
260+
COMPLETE_WITH_QUERY_VERBATIM_LIST(query, NULL)
261+
262+
#define COMPLETE_WITH_QUERY_VERBATIM_LIST(query, list) \
260263
do { \
261264
completion_charp = query; \
262-
completion_charpp = NULL; \
265+
completion_charpp = list; \
263266
completion_verbatim = true; \
264267
matches = rl_completion_matches(text, complete_from_query); \
265268
} while (0)
266269

270+
#define COMPLETE_WITH_QUERY_VERBATIM_PLUS(query, ...) \
271+
do { \
272+
static const char *const list[] = { __VA_ARGS__, NULL }; \
273+
COMPLETE_WITH_QUERY_VERBATIM_LIST(query, list); \
274+
} while (0)
275+
267276
#define COMPLETE_WITH_VERSIONED_QUERY(query) \
268277
COMPLETE_WITH_VERSIONED_QUERY_LIST(query, NULL)
269278

@@ -1273,6 +1282,7 @@ static char *_complete_from_query(const char *simple_query,
12731282
bool verbatim,
12741283
const char *text, int state);
12751284
static void set_completion_reference(const char *word);
1285+
static void set_completion_reference_verbatim(const char *word);
12761286
static char *complete_from_list(const char *text, int state);
12771287
static char *complete_from_const(const char *text, int state);
12781288
static void append_variable_names(char ***varnames, int *nvars,
@@ -2058,8 +2068,8 @@ psql_completion(const char *text, int start, int end)
20582068
else if (Matches("ALTER", "SYSTEM"))
20592069
COMPLETE_WITH("SET", "RESET");
20602070
else if (Matches("ALTER", "SYSTEM", "SET|RESET"))
2061-
COMPLETE_WITH_QUERY_PLUS(Query_for_list_of_alter_system_set_vars,
2062-
"ALL");
2071+
COMPLETE_WITH_QUERY_VERBATIM_PLUS(Query_for_list_of_alter_system_set_vars,
2072+
"ALL");
20632073
else if (Matches("ALTER", "SYSTEM", "SET", MatchAny))
20642074
COMPLETE_WITH("TO");
20652075
/* ALTER VIEW <name> */
@@ -4038,17 +4048,17 @@ psql_completion(const char *text, int start, int end)
40384048
/* SET, RESET, SHOW */
40394049
/* Complete with a variable name */
40404050
else if (TailMatches("SET|RESET") && !TailMatches("UPDATE", MatchAny, "SET"))
4041-
COMPLETE_WITH_QUERY_PLUS(Query_for_list_of_set_vars,
4042-
"CONSTRAINTS",
4043-
"TRANSACTION",
4044-
"SESSION",
4045-
"ROLE",
4046-
"TABLESPACE",
4047-
"ALL");
4051+
COMPLETE_WITH_QUERY_VERBATIM_PLUS(Query_for_list_of_set_vars,
4052+
"CONSTRAINTS",
4053+
"TRANSACTION",
4054+
"SESSION",
4055+
"ROLE",
4056+
"TABLESPACE",
4057+
"ALL");
40484058
else if (Matches("SHOW"))
4049-
COMPLETE_WITH_QUERY_PLUS(Query_for_list_of_show_vars,
4050-
"SESSION AUTHORIZATION",
4051-
"ALL");
4059+
COMPLETE_WITH_QUERY_VERBATIM_PLUS(Query_for_list_of_show_vars,
4060+
"SESSION AUTHORIZATION",
4061+
"ALL");
40524062
else if (Matches("SHOW", "SESSION"))
40534063
COMPLETE_WITH("AUTHORIZATION");
40544064
/* Complete "SET TRANSACTION" */
@@ -4150,7 +4160,7 @@ psql_completion(const char *text, int start, int end)
41504160
{
41514161
if (strcmp(guctype, "enum") == 0)
41524162
{
4153-
set_completion_reference(prev2_wd);
4163+
set_completion_reference_verbatim(prev2_wd);
41544164
COMPLETE_WITH_QUERY_PLUS(Query_for_values_of_enum_GUC,
41554165
"DEFAULT");
41564166
}
@@ -4707,7 +4717,7 @@ complete_from_versioned_schema_query(const char *text, int state)
47074717
* version of the string provided in completion_ref_object. If there is a
47084718
* third '%s', it will be replaced by a suitably-escaped version of the string
47094719
* provided in completion_ref_schema. Those strings should be set up
4710-
* by calling set_completion_reference().
4720+
* by calling set_completion_reference or set_completion_reference_verbatim.
47114721
* Simple queries should return a single column of matches. If "verbatim"
47124722
* is true, the matches are returned as-is; otherwise, they are taken to
47134723
* be SQL identifiers and quoted if necessary.
@@ -5037,11 +5047,7 @@ _complete_from_query(const char *simple_query,
50375047
if (pg_strncasecmp(text, item, strlen(text)) == 0)
50385048
{
50395049
num_keywords++;
5040-
/* Match keyword case if we are returning only keywords */
5041-
if (num_schema_only == 0 && num_query_other == 0)
5042-
return pg_strdup_keyword_case(item, text);
5043-
else
5044-
return pg_strdup(item);
5050+
return pg_strdup_keyword_case(item, text);
50455051
}
50465052
}
50475053
}
@@ -5059,11 +5065,7 @@ _complete_from_query(const char *simple_query,
50595065
if (pg_strncasecmp(text, item, strlen(text)) == 0)
50605066
{
50615067
num_keywords++;
5062-
/* Match keyword case if we are returning only keywords */
5063-
if (num_schema_only == 0 && num_query_other == 0)
5064-
return pg_strdup_keyword_case(item, text);
5065-
else
5066-
return pg_strdup(item);
5068+
return pg_strdup_keyword_case(item, text);
50675069
}
50685070
}
50695071
}
@@ -5100,6 +5102,17 @@ set_completion_reference(const char *word)
51005102
&schemaquoted, &objectquoted);
51015103
}
51025104

5105+
/*
5106+
* Set up completion_ref_object when it should just be
5107+
* the given word verbatim.
5108+
*/
5109+
static void
5110+
set_completion_reference_verbatim(const char *word)
5111+
{
5112+
completion_ref_schema = NULL;
5113+
completion_ref_object = pg_strdup(word);
5114+
}
5115+
51035116

51045117
/*
51055118
* This function returns in order one of a fixed, NULL pointer terminated list

0 commit comments

Comments
 (0)