mirror of
https://github.com/postgres/postgres.git
synced 2026-07-09 17:51:00 -04:00
pg_unicode_fast: fix final sigma logic.
If the string is preceded only by Case Ignorable characters, don't consider it to be a final sigma. In the process, refactor so that the preceding and following characters are found first, and then the rule is applied, to improve clarity. Discussion: https://postgr.es/m/c355354e6c3f4a7aafb047361b73db247260fca0.camel@j-davis.com Backpatch-through: 18
This commit is contained in:
parent
05da336dd7
commit
28d498e280
3 changed files with 52 additions and 53 deletions
|
|
@ -323,75 +323,67 @@ convert_case(char *dst, size_t dstsize, const char *src, size_t srclen,
|
|||
* 3-17. The character at the given offset must be directly preceded by a
|
||||
* Cased character, and must not be directly followed by a Cased character.
|
||||
*
|
||||
* Case_Ignorable characters are ignored. NB: some characters may be both
|
||||
* Case_Ignorable characters are ignored. Neither beginning of string nor end
|
||||
* of string are considered Cased characters. NB: some characters may be both
|
||||
* Cased and Case_Ignorable, in which case they are ignored.
|
||||
*/
|
||||
static bool
|
||||
check_final_sigma(const unsigned char *str, size_t len, size_t offset)
|
||||
{
|
||||
/* the start of the string is not preceded by a Cased character */
|
||||
if (offset == 0)
|
||||
return false;
|
||||
bool preceded_by_cased = false;
|
||||
bool followed_by_cased = false;
|
||||
char32_t curr;
|
||||
int ulen;
|
||||
|
||||
/* iterate backwards, looking for Cased character */
|
||||
for (int i = offset - 1; i >= 0; i--)
|
||||
/* iterate backwards looking for preceding character */
|
||||
for (int i = offset; i > 0;)
|
||||
{
|
||||
if ((str[i] & 0x80) == 0 || (str[i] & 0xC0) == 0xC0)
|
||||
{
|
||||
int u1len = utf8_mblen((const unsigned char *) str + i);
|
||||
char32_t curr;
|
||||
|
||||
/* invalid UTF8 */
|
||||
if (u1len < 0 || i + u1len > len)
|
||||
return false;
|
||||
|
||||
curr = utf8_to_unicode(str + i);
|
||||
|
||||
if (pg_u_prop_case_ignorable(curr))
|
||||
continue;
|
||||
else if (pg_u_prop_cased(curr))
|
||||
break;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else if ((str[i] & 0xC0) == 0x80)
|
||||
/* skip backwards through continuation bytes */
|
||||
i--;
|
||||
if ((str[i] & 0xC0) == 0x80)
|
||||
continue;
|
||||
else
|
||||
return false; /* invalid UTF8 */
|
||||
|
||||
/* now at leading byte of previous sequence */
|
||||
Assert((str[i] & 0x80) == 0 || (str[i] & 0xC0) == 0xC0);
|
||||
|
||||
ulen = utf8_mblen((const unsigned char *) str + i);
|
||||
|
||||
/* invalid UTF8 */
|
||||
if (ulen < 0 || i + ulen > len)
|
||||
return false;
|
||||
|
||||
curr = utf8_to_unicode((const unsigned char *) str + i);
|
||||
|
||||
if (!pg_u_prop_case_ignorable(curr))
|
||||
{
|
||||
preceded_by_cased = pg_u_prop_cased(curr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* end of string is not followed by a Cased character */
|
||||
if (offset == len)
|
||||
return true;
|
||||
ulen = utf8_mblen((const unsigned char *) str + offset);
|
||||
|
||||
/* iterate forwards, looking for Cased character */
|
||||
for (int i = offset + 1; i < len && str[i] != '\0'; i++)
|
||||
/* iterate forward looking for following character */
|
||||
for (int i = offset + ulen; i < len;)
|
||||
{
|
||||
if ((str[i] & 0x80) == 0 || (str[i] & 0xC0) == 0xC0)
|
||||
ulen = utf8_mblen((const unsigned char *) str + i);
|
||||
|
||||
/* invalid UTF8 */
|
||||
if (ulen < 0 || i + ulen > len)
|
||||
return false;
|
||||
|
||||
curr = utf8_to_unicode((const unsigned char *) str + i);
|
||||
|
||||
if (!pg_u_prop_case_ignorable(curr))
|
||||
{
|
||||
int u1len = utf8_mblen((const unsigned char *) str + i);
|
||||
char32_t curr;
|
||||
|
||||
/* invalid UTF8 */
|
||||
if (u1len < 0 || i + u1len > len)
|
||||
return false;
|
||||
|
||||
curr = utf8_to_unicode(str + i);
|
||||
|
||||
if (pg_u_prop_case_ignorable(curr))
|
||||
continue;
|
||||
else if (pg_u_prop_cased(curr))
|
||||
return false;
|
||||
else
|
||||
break;
|
||||
followed_by_cased = pg_u_prop_cased(curr);
|
||||
break;
|
||||
}
|
||||
else if ((str[i] & 0xC0) == 0x80)
|
||||
continue;
|
||||
else
|
||||
return false; /* invalid UTF8 */
|
||||
|
||||
i += ulen;
|
||||
}
|
||||
|
||||
return true;
|
||||
return (preceded_by_cased && !followed_by_cased);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -263,6 +263,12 @@ SELECT lower('ᾼΣͅΑ' COLLATE PG_UNICODE_FAST); -- 0391 0345 03A3 0345 0391
|
|||
ᾳσͅα
|
||||
(1 row)
|
||||
|
||||
SELECT lower(U&'\0300\03A3' COLLATE PG_UNICODE_FAST);
|
||||
lower
|
||||
-------
|
||||
̀σ
|
||||
(1 row)
|
||||
|
||||
-- properties
|
||||
SELECT 'xyz' ~ '[[:alnum:]]' COLLATE PG_UNICODE_FAST;
|
||||
?column?
|
||||
|
|
|
|||
|
|
@ -128,6 +128,7 @@ SELECT lower('0Σ' COLLATE PG_UNICODE_FAST); -- 0030 03A3
|
|||
SELECT lower('ΑΣΑ' COLLATE PG_UNICODE_FAST); -- 0391 03A3 0391
|
||||
SELECT lower('ἈΣ̓Α' COLLATE PG_UNICODE_FAST); -- 0391 0343 03A3 0343 0391
|
||||
SELECT lower('ᾼΣͅΑ' COLLATE PG_UNICODE_FAST); -- 0391 0345 03A3 0345 0391
|
||||
SELECT lower(U&'\0300\03A3' COLLATE PG_UNICODE_FAST);
|
||||
|
||||
-- properties
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue