Thread
Commits
-
Fix INITCAP() word boundaries for PG_UNICODE_FAST.
- 90260e2ec6bb 18.0 landed
-
Support PG_UNICODE_FAST locale in the builtin collation provider.
- d3d098316913 18.0 landed
-
Support Unicode full case mapping and conversion.
- 286a365b9c25 18.0 landed
-
Unicode full case mapping: PG_UNICODE_FAST, and standard-compliant UCS_BASIC
Jeff Davis <pgsql@j-davis.com> — 2024-12-11T23:52:44Z
Right now, the UCS_BASIC simply uses the "C" locale. The standard for LOWER() and UPPER() define the behavior in terms of Unicode. The specific requirement that "ß" shall uppercase to "SS" also seems to imply Full Case Mapping. Attached is a series of patches to implement full case mapping as the locale PG_UNICODE_FAST. The last patch in the series also changes UCS_BASIC to use that locale, bringing it into compliance with the standard. However, this will break existing users of the UCS_BASIC collation, so we may not want this at all. If we do want it, we should be clear that affected expression indexes using UCS_BASIC should be REINDEXed, or that users should change the collation to "C" to get the previous behavior. While Postgres uses the collation to define the behavior of LOWER() and UPPER(), the standard doesn't mention it, so the behavior of those functions is independent of the collation (according to the standard). It wouldn't make sense to force the standard behavior on all the collations, but it could make sense for the standard-defined UCS_BASIC collation. Regards, Jeff Davis
-
Re: Unicode full case mapping: PG_UNICODE_FAST, and standard-compliant UCS_BASIC
Jeff Davis <pgsql@j-davis.com> — 2024-12-16T20:49:14Z
On Wed, 2024-12-11 at 15:52 -0800, Jeff Davis wrote: > Attached is a series of patches to implement full case mapping as the > locale PG_UNICODE_FAST. Rebased and attached. I'm having a doubt about the correctness, though. There's a statement in SpecialCasing.txt: # IMPORTANT-when iota-subscript (0345) is uppercased or titlecased, # the result will be incorrect unless the iota-subscript is moved to the end # of any sequence of combining marks. Otherwise, the accents will go on the capital iota. # This process can be achieved by first transforming the text to NFC before casing. # E.g. <alpha><iota_subscript><acute> is uppercased to <ALPHA><acute><IOTA> That requirement doesn't appear to exist in the Unicode standard itself, nor is it implied from the mappings in the data files. And based on the description, it only matters if the input is not normalized in NFC (I believe NFD is also fine, because the combining class of U+0345 is 240, higher than any other class). Furthermore, it appears that the ICU root collation doesn't bother trying to implement that requirement for non-normalized input. There is a related requirement for caseless matching in the Unicode standard[1] that requires normalization iff the source includes U+0345 (or any character which has U+0345 in its decomposition). The ICU u_strFoldCase() function doesn't do that, either. I'm not sure how important these requirements are, but I'm bringing them up now because we can't change them after release, and they may be technically incorrect for non-normalized input. Regards, Jeff Davis [1] Unicode 16.0 section 3.13.5 rule D145 https://www.unicode.org/versions/Unicode16.0.0/UnicodeStandard-16.0.pdf#G34145
-
Re: Unicode full case mapping: PG_UNICODE_FAST, and standard-compliant UCS_BASIC
Jeff Davis <pgsql@j-davis.com> — 2025-01-11T00:36:09Z
On Mon, 2024-12-16 at 12:49 -0800, Jeff Davis wrote: > On Wed, 2024-12-11 at 15:52 -0800, Jeff Davis wrote: > > Attached is a series of patches to implement full case mapping as > > the > > locale PG_UNICODE_FAST. > > Rebased and attached. Rebased and attached v3. Regards, Jeff Davis
-
Re: Unicode full case mapping: PG_UNICODE_FAST, and standard-compliant UCS_BASIC
Jeff Davis <pgsql@j-davis.com> — 2025-01-15T21:21:34Z
On Fri, 2025-01-10 at 16:36 -0800, Jeff Davis wrote: > On Mon, 2024-12-16 at 12:49 -0800, Jeff Davis wrote: > > On Wed, 2024-12-11 at 15:52 -0800, Jeff Davis wrote: > > > Attached is a series of patches to implement full case mapping as > > > the > > > locale PG_UNICODE_FAST. > > > > Rebased and attached. > > Rebased and attached v3. I plan to commit 0001 and 0002 soon. There seems to be general agreement that we want full case mapping[1], and we can potentially use the infrastructure to extend the additional case variants into pattern matching[2]. 0003 requires more discussion. Regards, Jeff Davis [1]https://www.postgresql.org/message-id/27bb0e52-801d-4f73-a0a4-02cfdd4a9ada@eisentraut.org [2] https://www.postgresql.org/message-id/c10ed44c7e5dcbb7b4597889f02d029298f0c919.camel@j-davis.com
-
Re: Unicode full case mapping: PG_UNICODE_FAST, and standard-compliant UCS_BASIC
Jeff Davis <pgsql@j-davis.com> — 2025-01-18T00:06:20Z
On Wed, 2025-01-15 at 13:21 -0800, Jeff Davis wrote: > I plan to commit 0001 and 0002 soon. Committed 0001 and 0002. Upon reviewing the discussion threads, I removed the Unicode "adjust to Cased" behavior when titlecasing. As Peter pointed out[1], it doesn't match the documentation or expectations for INITCAP(). I also expanded the C tests a lot in 0001 so that it compares exhaustively against ICU for single-codepoint strings, and also added more multi-codepoint test strings. I don't plan to commit 0003 in v18, so I'm considering this series to be done for now. We can revisit whether UCS_BASIC should change behavior in 19. Regards, Jeff Davis
-
Re: Unicode full case mapping: PG_UNICODE_FAST, and standard-compliant UCS_BASIC
Jeff Davis <pgsql@j-davis.com> — 2025-01-18T00:40:07Z
On Fri, 2025-01-17 at 16:06 -0800, Jeff Davis wrote: > Upon reviewing the discussion threads, I removed the Unicode "adjust > to > Cased" behavior when titlecasing. As Peter pointed out[1], it doesn't > match the documentation or expectations for INITCAP(). Forgot to add a link to the discussion. Here are some relevant messages: https://www.postgresql.org/message-id/4c9eea58-08a1-4629-a004-439e2cf12de8%40eisentraut.org https://www.postgresql.org/message-id/610d7f1b-c68c-4eb8-a03d-1515da304c58%40manitou-mail.org Regards, Jeff Davis
-
Re: Unicode full case mapping: PG_UNICODE_FAST, and standard-compliant UCS_BASIC
Noah Misch <noah@leadboat.com> — 2025-04-17T13:58:41Z
On Fri, Jan 17, 2025 at 04:06:20PM -0800, Jeff Davis wrote: > Committed 0001 and 0002. > Upon reviewing the discussion threads, I removed the Unicode "adjust to > Cased" behavior when titlecasing. As Peter pointed out[1], it doesn't > match the documentation or expectations for INITCAP(). While commit d3d0983 changed most of the non-test pg_u_*() "bool posix" arguments, it left a pg_u_isalnum(u, true) in strtitle_builtin() subroutine initcap_wbnext(). The above paragraph may or may not be saying that's intentional. Example of the consequence at non-ASCII decimal digits: SELECT str, re, regexp_count(str COLLATE pg_c_utf8, re) AS count_c_utf8, regexp_count(str COLLATE pg_unicode_fast, re) AS count_unicode_fast, regexp_count(str COLLATE unicode, re) AS count_unicode, initcap(str COLLATE pg_c_utf8) AS initcap_c_utf8, initcap(str COLLATE pg_unicode_fast) AS initcap_unicode_fast, initcap(str COLLATE unicode) AS initcap_unicode FROM (VALUES (U&'foo\0661bar baz')) AS str_t(str), (VALUES ('[[:digit:]]')) AS re_t(re) ORDER BY 1, 2; str │ foo١bar baz re │ [[:digit:]] count_c_utf8 │ 0 count_unicode_fast │ 1 count_unicode │ 1 initcap_c_utf8 │ Foo١Bar Baz initcap_unicode_fast │ Foo١Bar Baz initcap_unicode │ Foo١bar Baz Should initcap_wbnext() pass in a locale-dependent "bool posix" argument like the others calls the commit changed? Related message from the development of pg_c_utf8, which you shared downthread: https://www.postgresql.org/message-id/610d7f1b-c68c-4eb8-a03d-1515da304c58%40manitou-mail.org Long-term, pg_u_isword() should have a "bool posix" argument. Currently, only tests call that function. If it got a non-test caller, https://www.unicode.org/reports/tr18/#word would have pg_u_isword() follow the choice of posix compatibility like pg_u_isalnum() does. -
Re: Unicode full case mapping: PG_UNICODE_FAST, and standard-compliant UCS_BASIC
Jeff Davis <pgsql@j-davis.com> — 2025-04-19T19:30:57Z
On Thu, 2025-04-17 at 06:58 -0700, Noah Misch wrote: > Should initcap_wbnext() pass in a locale-dependent "bool posix" > argument like > the others calls the commit changed? Yes, I believe you are correct. Patch and tests attached. > Long-term, pg_u_isword() should have a "bool posix" argument. > Currently, only > tests call that function. If it got a non-test caller, > https://www.unicode.org/reports/tr18/#word would have pg_u_isword() > follow the > choice of posix compatibility like pg_u_isalnum() does. I based those functions on: https://www.unicode.org/reports/tr18/#Compatibility_Properties and the "word" class does not have a POSIX variant. But Postgres has two documented definitions for "word" characters: * for regexes, alnum + "_" * for INITCAP(), just alnum and the above definition doesn't match up with either one, which is why we don't use it. ICU INITCAP() uses the ICU definition of word boundaries, so doesn't match our documentation. We could adjust our documentation to allow for provider-dependent definitions of word characters, which might be a good idea. But that still doesn't quite capture ICU's more complex definition of word boundaries. Or, we could remove those unused functions for now, and figure out if there's a reason to add them back later. They are probably adding more confusion than anything. Regards, Jeff Davis
-
Re: Unicode full case mapping: PG_UNICODE_FAST, and standard-compliant UCS_BASIC
Noah Misch <noah@leadboat.com> — 2025-04-20T12:53:22Z
On Sat, Apr 19, 2025 at 12:30:57PM -0700, Jeff Davis wrote: > On Thu, 2025-04-17 at 06:58 -0700, Noah Misch wrote: > > Should initcap_wbnext() pass in a locale-dependent "bool posix" > > argument like > > the others calls the commit changed? > > Yes, I believe you are correct. Patch and tests attached. That patch is ready for commit. > > Long-term, pg_u_isword() should have a "bool posix" argument. > > Currently, only > > tests call that function. If it got a non-test caller, > > https://www.unicode.org/reports/tr18/#word would have pg_u_isword() > > follow the > > choice of posix compatibility like pg_u_isalnum() does. > > I based those functions on: > > https://www.unicode.org/reports/tr18/#Compatibility_Properties > > and the "word" class does not have a POSIX variant. I missed that distinction. I withdraw this part.