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
 

Reply via email to