v10-0001-Support-tab-completion-with-a-query-result-for-u.patch
application/octet-stream
Filename: v10-0001-Support-tab-completion-with-a-query-result-for-u.patch
Type: application/octet-stream
Part: 0
Patch
Format: format-patch
Series: patch v10-0001
Subject: Support tab completion with a query result for upper character inputs in psql
| File | + | − |
|---|---|---|
| src/bin/psql/t/010_tab_completion.pl | 64 | 1 |
| src/bin/psql/tab-complete.c | 67 | 2 |
From d049255b8b4806533276bcc9736e4342a8f8a5be Mon Sep 17 00:00:00 2001
From: Haiying Tang <tanghy.fnst@fujitsu.com>
Date: Fri, 10 Sep 2021 22:23:55 +0900
Subject: [PATCH v10] Support tab completion with a query result for upper
character inputs in psql
---
src/bin/psql/t/010_tab_completion.pl | 65 +++++++++++++++++++++++++-
src/bin/psql/tab-complete.c | 69 +++++++++++++++++++++++++++-
2 files changed, 131 insertions(+), 3 deletions(-)
diff --git a/src/bin/psql/t/010_tab_completion.pl b/src/bin/psql/t/010_tab_completion.pl
index 55b318517e..d6188287c8 100644
--- a/src/bin/psql/t/010_tab_completion.pl
+++ b/src/bin/psql/t/010_tab_completion.pl
@@ -41,8 +41,11 @@ $node->start;
# set up a few database objects
$node->safe_psql('postgres',
"CREATE TABLE tab1 (f1 int, f2 text);\n"
+ . "CREATE TABLE onetab1 (f1 int);\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 TABLE \"myTAB123\" (\"aF1\" int, f2 text);\n"
+ . "CREATE TYPE mytype1 as enum ('bLACK');\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.
@@ -149,6 +152,66 @@ check_completion("SEL\t", qr/SELECT /, "complete SEL<tab> to SELECT");
clear_query();
+# check set query command(upper case) completion for upper character inputs
+check_completion("set BYT\t", qq/set BYT\b\b\bbytea_output /, "complete set BYT<tab> to set bytea_output");
+
+clear_query();
+
+# check set query command(lower case) completion for upper character inputs
+check_completion("set bYT\t", qq/set bYT\b\bytea_output /, "complete set bYT<tab> to set bytea_output");
+
+clear_query();
+
+# check query command(upper case) completion for empty input
+check_completion("update onetab1 \t", qr/update onetab1 SET /, "complete SQL key words for onetab1 with empty input");
+
+clear_query();
+
+# check query command(lower case) completion for empty input
+check_completion("update onetab1 SET \t", qr/update onetab1 SET f1 /, "complete column name for onetab1 with empty input");
+
+clear_query();
+
+# check query command completion for upper character relation name
+check_completion("update TAB1 SET \t", qr/update TAB1 SET \af/, "complete column name for TAB1");
+
+clear_query();
+
+# check quoted identifiers in table
+check_completion("update \"my\t", qr/update \"myTAB123\" /, "complete quoted string1");
+
+clear_query();
+
+# check quoted identifiers in column
+check_completion("update \"myTAB123\" SET \"aF\t", qr/update \"myTAB123\" SET \"aF1\" /, "complete quoted string2");
+
+clear_query();
+
+# check schema query(lower case) which is case-insensitive
+check_completion("select oid from pg_Cla\t", qq/select oid from pg_Cla\b\b\bclass /, "complete schema query with lower case string");
+
+clear_query();
+
+# check schema query(upper case) which is case-insensitive
+check_completion("select oid from Pg_cla\t", qq/select oid from Pg_cla\b\b\b\b\b\bpg_class /, "complete schema query with uppper case string");
+
+clear_query();
+
+# check schema.table query which is case-insensitive
+check_completion("alter table PUBLIC.tab\t", qq/alter table PUBLIC.tab\b\b\b\b\b\b\b\b\b\bpublic.tab1 /, "complete schema.table without quoted identifiers");
+
+clear_query();
+
+# check schema.table query which is case-sensitive
+check_completion("alter table PUBLIC.\"my\t", qq/alter table PUBLIC.\"my\b\b\b\b\b\b\b\b\b\bpublic.\"myTAB123\" /, "complete schema.table with quoted identifiers");
+
+clear_query();
+
+# check enum values which are case-insensitive
+check_completion("ALTER TYPE mytype1 RENAME VALUE '\t\t", qr|'bLACK'|, "complete enum values");
+
+clear_line();
+
# check case variation is honored
check_completion("sel\t", qr/select /, "complete sel<tab> to select");
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index b81a04c93b..42a02d93dd 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -1027,7 +1027,7 @@ static const VersionedQuery Query_for_list_of_subscriptions[] = {
};
/*
- * This is a list of all "things" in Pgsql, which can show up after CREATE or
+ * This is a list of all "things" in pgsql, which can show up after CREATE or
* DROP; and there is also a query to get a list of them.
*/
@@ -1177,6 +1177,7 @@ static char *complete_from_files(const char *text, int state);
static char *pg_strdup_keyword_case(const char *s, const char *ref);
static char *escape_string(const char *text);
+static char *pg_string_tolower_if_ascii(const char *text);
static PGresult *exec_query(const char *query);
static char **get_previous_words(int point, char **buffer, int *nwords);
@@ -1429,6 +1430,20 @@ ends_with(const char *s, char c)
return (length > 0 && s[length - 1] == c);
}
+/*
+ * Check if the text is written by ASCII characters which only contain
+ * alphabet letters, dot, underscore, digits, backward slash and double quotes.
+ */
+static bool
+check_input_text(const char *text)
+{
+ if (strspn(text, "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"
+ "._0123456789\\\"") == strlen(text))
+ return true;
+
+ return false;
+}
+
/*
* The completion function.
*
@@ -4608,6 +4623,7 @@ _complete_from_query(const char *simple_query,
char *e_text;
char *e_info_charp;
char *e_info_charp2;
+ char *le_str;
const char *pstr = text;
int char_length = 0;
@@ -4631,13 +4647,27 @@ _complete_from_query(const char *simple_query,
/* Set up suitably-escaped copies of textual inputs */
e_text = escape_string(text);
+ /* Change the textual inputs to lower case if they're written by ascii*/
+ le_str = pg_string_tolower_if_ascii(e_text);
+ free(e_text);
+ e_text = le_str;
if (completion_info_charp)
+ {
e_info_charp = escape_string(completion_info_charp);
+ le_str = pg_string_tolower_if_ascii(e_info_charp);
+ free(e_info_charp);
+ e_info_charp = le_str;
+ }
else
e_info_charp = NULL;
if (completion_info_charp2)
+ {
e_info_charp2 = escape_string(completion_info_charp2);
+ le_str = pg_string_tolower_if_ascii(e_info_charp2);
+ free(e_info_charp2);
+ e_info_charp2 = le_str;
+ }
else
e_info_charp2 = NULL;
@@ -4672,7 +4702,7 @@ _complete_from_query(const char *simple_query,
*/
if (strcmp(schema_query->catname,
"pg_catalog.pg_class c") == 0 &&
- strncmp(text, "pg_", 3) != 0)
+ pg_strncasecmp(text, "pg_", 3) != 0)
{
appendPQExpBufferStr(&query_buffer,
" AND c.relnamespace <> (SELECT oid FROM"
@@ -5101,6 +5131,41 @@ escape_string(const char *text)
}
+/*
+ * pg_string_tolower - Fold a string to lower case if the string is not quoted
+ * and only contains ASCII characters.
+ * For German/Turkish etc text, no change will be made.
+ *
+ * The returned value has to be freed.
+ */
+static char *
+pg_string_tolower_if_ascii(const char *text)
+{
+ char *ret,
+ *p;
+ bool notquoted = true;
+ int count = 0;
+
+ ret = pg_strdup(text);
+
+ if(check_input_text(ret))
+ {
+ for (p = ret; *p; p++)
+ {
+ if (p[0] == '"')
+ {
+ count++;
+ notquoted = false;
+ }
+ if (notquoted && (count % 2 == 0))
+ *p = pg_tolower((unsigned char) *p);
+ }
+ }
+
+ return ret;
+}
+
+
/*
* Execute a query and report any errors. This should be the preferred way of
* talking to the database in this file.
--
2.33.0.windows.2