I wrote: > =?utf-8?Q?Dagfinn_Ilmari_Manns=C3=A5ker?= <ilm...@ilmari.org> writes: >> First, as noted in the test, it doesn't preserve the case of the input >> for keywords appended to the query result. This is easily fixed by >> using `pg_strdup_keyword_case()`, per the first attached patch.
> I thought about that, and intentionally didn't do it, because it > would also affect the menus produced by tab completion. > ... > We could do something hacky like matching case only when there's > no longer any matching object names, but that might be too magic. I experimented with that, and it actually doesn't seem as weird as I feared. See if you like this ... regards, tom lane
diff --git a/src/bin/psql/t/010_tab_completion.pl b/src/bin/psql/t/010_tab_completion.pl index c4f6552ac9..7a265e0676 100644 --- a/src/bin/psql/t/010_tab_completion.pl +++ b/src/bin/psql/t/010_tab_completion.pl @@ -40,7 +40,7 @@ $node->start; # set up a few database objects $node->safe_psql('postgres', - "CREATE TABLE tab1 (f1 int primary key, f2 text);\n" + "CREATE TABLE tab1 (c1 int primary key, c2 text);\n" . "CREATE TABLE mytab123 (f1 int, f2 text);\n" . "CREATE TABLE mytab246 (f1 int, f2 text);\n" . "CREATE TABLE \"mixedName\" (f1 int, f2 text);\n" @@ -317,14 +317,30 @@ check_completion( clear_line(); -# check completion of a keyword offered in addition to object names -# (that code path currently doesn't preserve case of what's typed) -check_completion( - "comment on constraint foo on dom\t", - qr|DOMAIN|, - "offer keyword in addition to query result"); - -clear_query(); +# check completion of a keyword offered in addition to object names; +# such a keyword should obey COMP_KEYWORD_CASE once only keyword +# completions are possible +foreach ( + [ 'lower', 'CO', 'column' ], + [ 'upper', 'co', 'COLUMN' ], + [ 'preserve-lower', 'co', 'column' ], + [ 'preserve-upper', 'CO', 'COLUMN' ],) +{ + my ($case, $in, $out) = @$_; + + check_completion( + "\\set COMP_KEYWORD_CASE $case\n", + qr/postgres=#/, + "set completion case to '$case'"); + check_completion("alter table tab1 rename c\t\t", + qr|COLUMN|, + "offer keyword COLUMN for input c<TAB>, COMP_KEYWORD_CASE = $case"); + clear_query(); + check_completion("alter table tab1 rename $in\t\t\t", + qr|$out|, + "offer keyword $out for input $in<TAB>, COMP_KEYWORD_CASE = $case"); + clear_query(); +} # send psql an explicit \q to shut it down, else pty won't close properly $timer->start(5); diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index b2ec50b4f2..bdc9760fba 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -4742,7 +4742,8 @@ _complete_from_query(const char *simple_query, { static int list_index, num_schema_only, - num_other; + num_other, + num_keywords; static PGresult *result = NULL; static bool non_empty_object; static bool schemaquoted; @@ -4766,6 +4767,7 @@ _complete_from_query(const char *simple_query, list_index = 0; num_schema_only = 0; num_other = 0; + num_keywords = 0; PQclear(result); result = NULL; @@ -4986,7 +4988,10 @@ _complete_from_query(const char *simple_query, /* In verbatim mode, we return all the items as-is */ if (verbatim) + { + num_other++; return pg_strdup(item); + } /* * In normal mode, a name requiring quoting will be returned only @@ -5031,8 +5036,12 @@ _complete_from_query(const char *simple_query, list_index++; if (pg_strncasecmp(text, item, strlen(text)) == 0) { - num_other++; - return pg_strdup(item); + num_keywords++; + /* Match keyword case if we are returning only keywords */ + if (num_schema_only == 0 && num_other == 0) + return pg_strdup_keyword_case(item, text); + else + return pg_strdup(item); } } } @@ -5049,8 +5058,12 @@ _complete_from_query(const char *simple_query, list_index++; if (pg_strncasecmp(text, item, strlen(text)) == 0) { - num_other++; - return pg_strdup(item); + num_keywords++; + /* Match keyword case if we are returning only keywords */ + if (num_schema_only == 0 && num_other == 0) + return pg_strdup_keyword_case(item, text); + else + return pg_strdup(item); } } } @@ -5062,7 +5075,7 @@ _complete_from_query(const char *simple_query, * completion subject text, which is not what we want. */ #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER - if (num_schema_only > 0 && num_other == 0) + if (num_schema_only > 0 && num_other == 0 && num_keywords == 0) rl_completion_append_character = '\0'; #endif