Skip to content

Commit 8de488d

Browse files
committed
Fix query-based tab completion for multibyte characters.
The existing code confuses the byte length of the string (which is relevant when passing it to pg_strncasecmp) with the character length of the string (which is relevant when it is used with the SQL substring function). Separate those two concepts. Report and patch by Kyotaro Horiguchi, reviewed by Thomas Munro and reviewed and further revised by me.
1 parent c732756 commit 8de488d

File tree

1 file changed

+19
-11
lines changed

1 file changed

+19
-11
lines changed

src/bin/psql/tab-complete.c

+19-11
Original file line numberDiff line numberDiff line change
@@ -3689,9 +3689,8 @@ static char *
36893689
_complete_from_query(int is_schema_query, const char *text, int state)
36903690
{
36913691
static int list_index,
3692-
string_length;
3692+
byte_length;
36933693
static PGresult *result = NULL;
3694-
36953694
/*
36963695
* If this is the first time for this completion, we fetch a list of our
36973696
* "things" from the backend.
@@ -3702,9 +3701,18 @@ _complete_from_query(int is_schema_query, const char *text, int state)
37023701
char *e_text;
37033702
char *e_info_charp;
37043703
char *e_info_charp2;
3704+
const char *pstr = text;
3705+
int char_length = 0;
37053706

37063707
list_index = 0;
3707-
string_length = strlen(text);
3708+
byte_length = strlen(text);
3709+
3710+
/* Count length as number of characters (not bytes), for passing to substring */
3711+
while (*pstr)
3712+
{
3713+
char_length++;
3714+
pstr += PQmblen(pstr, pset.encoding);
3715+
}
37083716

37093717
/* Free any prior result */
37103718
PQclear(result);
@@ -3757,7 +3765,7 @@ _complete_from_query(int is_schema_query, const char *text, int state)
37573765
completion_squery->selcondition);
37583766
appendPQExpBuffer(&query_buffer, "substring(%s,1,%d)='%s'",
37593767
completion_squery->result,
3760-
string_length, e_text);
3768+
char_length, e_text);
37613769
appendPQExpBuffer(&query_buffer, " AND %s",
37623770
completion_squery->viscondition);
37633771

@@ -3784,13 +3792,13 @@ _complete_from_query(int is_schema_query, const char *text, int state)
37843792
"SELECT pg_catalog.quote_ident(n.nspname) || '.' "
37853793
"FROM pg_catalog.pg_namespace n "
37863794
"WHERE substring(pg_catalog.quote_ident(n.nspname) || '.',1,%d)='%s'",
3787-
string_length, e_text);
3795+
char_length, e_text);
37883796
appendPQExpBuffer(&query_buffer,
37893797
" AND (SELECT pg_catalog.count(*)"
37903798
" FROM pg_catalog.pg_namespace"
37913799
" WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d) ="
37923800
" substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(nspname))+1)) > 1",
3793-
string_length, e_text);
3801+
char_length, e_text);
37943802

37953803
/*
37963804
* Add in matching qualified names, but only if there is exactly
@@ -3808,7 +3816,7 @@ _complete_from_query(int is_schema_query, const char *text, int state)
38083816
completion_squery->selcondition);
38093817
appendPQExpBuffer(&query_buffer, "substring(pg_catalog.quote_ident(n.nspname) || '.' || %s,1,%d)='%s'",
38103818
qualresult,
3811-
string_length, e_text);
3819+
char_length, e_text);
38123820

38133821
/*
38143822
* This condition exploits the single-matching-schema rule to
@@ -3817,13 +3825,13 @@ _complete_from_query(int is_schema_query, const char *text, int state)
38173825
appendPQExpBuffer(&query_buffer,
38183826
" AND substring(pg_catalog.quote_ident(n.nspname) || '.',1,%d) ="
38193827
" substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(n.nspname))+1)",
3820-
string_length, e_text);
3828+
char_length, e_text);
38213829
appendPQExpBuffer(&query_buffer,
38223830
" AND (SELECT pg_catalog.count(*)"
38233831
" FROM pg_catalog.pg_namespace"
38243832
" WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d) ="
38253833
" substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(nspname))+1)) = 1",
3826-
string_length, e_text);
3834+
char_length, e_text);
38273835

38283836
/* If an addon query was provided, use it */
38293837
if (completion_charp)
@@ -3833,7 +3841,7 @@ _complete_from_query(int is_schema_query, const char *text, int state)
38333841
{
38343842
/* completion_charp is an sprintf-style format string */
38353843
appendPQExpBuffer(&query_buffer, completion_charp,
3836-
string_length, e_text,
3844+
char_length, e_text,
38373845
e_info_charp, e_info_charp,
38383846
e_info_charp2, e_info_charp2);
38393847
}
@@ -3859,7 +3867,7 @@ _complete_from_query(int is_schema_query, const char *text, int state)
38593867

38603868
while (list_index < PQntuples(result) &&
38613869
(item = PQgetvalue(result, list_index++, 0)))
3862-
if (pg_strncasecmp(text, item, string_length) == 0)
3870+
if (pg_strncasecmp(text, item, byte_length) == 0)
38633871
return pg_strdup(item);
38643872
}
38653873

0 commit comments

Comments
 (0)