Skip to content

Commit 0315dfa

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 9b3f0c1 commit 0315dfa

File tree

1 file changed

+19
-11
lines changed

1 file changed

+19
-11
lines changed

src/bin/psql/tab-complete.c

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4126,9 +4126,8 @@ static char *
41264126
_complete_from_query(int is_schema_query, const char *text, int state)
41274127
{
41284128
static int list_index,
4129-
string_length;
4129+
byte_length;
41304130
static PGresult *result = NULL;
4131-
41324131
/*
41334132
* If this is the first time for this completion, we fetch a list of our
41344133
* "things" from the backend.
@@ -4139,9 +4138,18 @@ _complete_from_query(int is_schema_query, const char *text, int state)
41394138
char *e_text;
41404139
char *e_info_charp;
41414140
char *e_info_charp2;
4141+
const char *pstr = text;
4142+
int char_length = 0;
41424143

41434144
list_index = 0;
4144-
string_length = strlen(text);
4145+
byte_length = strlen(text);
4146+
4147+
/* Count length as number of characters (not bytes), for passing to substring */
4148+
while (*pstr)
4149+
{
4150+
char_length++;
4151+
pstr += PQmblen(pstr, pset.encoding);
4152+
}
41454153

41464154
/* Free any prior result */
41474155
PQclear(result);
@@ -4194,7 +4202,7 @@ _complete_from_query(int is_schema_query, const char *text, int state)
41944202
completion_squery->selcondition);
41954203
appendPQExpBuffer(&query_buffer, "substring(%s,1,%d)='%s'",
41964204
completion_squery->result,
4197-
string_length, e_text);
4205+
char_length, e_text);
41984206
appendPQExpBuffer(&query_buffer, " AND %s",
41994207
completion_squery->viscondition);
42004208

@@ -4221,13 +4229,13 @@ _complete_from_query(int is_schema_query, const char *text, int state)
42214229
"SELECT pg_catalog.quote_ident(n.nspname) || '.' "
42224230
"FROM pg_catalog.pg_namespace n "
42234231
"WHERE substring(pg_catalog.quote_ident(n.nspname) || '.',1,%d)='%s'",
4224-
string_length, e_text);
4232+
char_length, e_text);
42254233
appendPQExpBuffer(&query_buffer,
42264234
" AND (SELECT pg_catalog.count(*)"
42274235
" FROM pg_catalog.pg_namespace"
42284236
" WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d) ="
42294237
" substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(nspname))+1)) > 1",
4230-
string_length, e_text);
4238+
char_length, e_text);
42314239

42324240
/*
42334241
* Add in matching qualified names, but only if there is exactly
@@ -4245,7 +4253,7 @@ _complete_from_query(int is_schema_query, const char *text, int state)
42454253
completion_squery->selcondition);
42464254
appendPQExpBuffer(&query_buffer, "substring(pg_catalog.quote_ident(n.nspname) || '.' || %s,1,%d)='%s'",
42474255
qualresult,
4248-
string_length, e_text);
4256+
char_length, e_text);
42494257

42504258
/*
42514259
* This condition exploits the single-matching-schema rule to
@@ -4254,13 +4262,13 @@ _complete_from_query(int is_schema_query, const char *text, int state)
42544262
appendPQExpBuffer(&query_buffer,
42554263
" AND substring(pg_catalog.quote_ident(n.nspname) || '.',1,%d) ="
42564264
" substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(n.nspname))+1)",
4257-
string_length, e_text);
4265+
char_length, e_text);
42584266
appendPQExpBuffer(&query_buffer,
42594267
" AND (SELECT pg_catalog.count(*)"
42604268
" FROM pg_catalog.pg_namespace"
42614269
" WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d) ="
42624270
" substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(nspname))+1)) = 1",
4263-
string_length, e_text);
4271+
char_length, e_text);
42644272

42654273
/* If an addon query was provided, use it */
42664274
if (completion_charp)
@@ -4270,7 +4278,7 @@ _complete_from_query(int is_schema_query, const char *text, int state)
42704278
{
42714279
/* completion_charp is an sprintf-style format string */
42724280
appendPQExpBuffer(&query_buffer, completion_charp,
4273-
string_length, e_text,
4281+
char_length, e_text,
42744282
e_info_charp, e_info_charp,
42754283
e_info_charp2, e_info_charp2);
42764284
}
@@ -4296,7 +4304,7 @@ _complete_from_query(int is_schema_query, const char *text, int state)
42964304

42974305
while (list_index < PQntuples(result) &&
42984306
(item = PQgetvalue(result, list_index++, 0)))
4299-
if (pg_strncasecmp(text, item, string_length) == 0)
4307+
if (pg_strncasecmp(text, item, byte_length) == 0)
43004308
return pg_strdup(item);
43014309
}
43024310

0 commit comments

Comments
 (0)