PostgreSQL Source Code git master
Loading...
Searching...
No Matches
pg_locale_icu.c
Go to the documentation of this file.
1/*-----------------------------------------------------------------------
2 *
3 * PostgreSQL locale utilities for ICU
4 *
5 * Portions Copyright (c) 2002-2026, PostgreSQL Global Development Group
6 *
7 * src/backend/utils/adt/pg_locale_icu.c
8 *
9 *-----------------------------------------------------------------------
10 */
11
12#include "postgres.h"
13
14#ifdef USE_ICU
15#include <unicode/ucasemap.h>
16#include <unicode/ucnv.h>
17#include <unicode/ucol.h>
18#include <unicode/ustring.h>
19
20/*
21 * We require ICU 55 to be able to use the "und" spelling of the root locale.
22 * (Prior versions do not recognize this locale, and moreover fall back to the
23 * environment for unrecognized locale names, which could cause confusion and
24 * corruption.)
25 */
26#if U_ICU_VERSION_MAJOR_NUM < 55
27#error ICU version 55 or later is required
28#endif
29#endif
30
31#include "access/htup_details.h"
32#include "catalog/pg_database.h"
34#include "mb/pg_wchar.h"
35#include "miscadmin.h"
36#include "utils/builtins.h"
37#include "utils/formatting.h"
38#include "utils/memutils.h"
39#include "utils/pg_locale.h"
40#include "utils/syscache.h"
41
42/*
43 * Size of stack buffer to use for string transformations, used to avoid heap
44 * allocations in typical cases. This should be large enough that most strings
45 * will fit, but small enough that we feel comfortable putting it on the
46 * stack.
47 */
48#define TEXTBUFLEN 1024
49
51
52#ifdef USE_ICU
53
54extern UCollator *pg_ucol_open(const char *loc_str);
55static UCaseMap *pg_ucasemap_open(const char *loc_str);
56
57static size_t strlower_icu(char *dest, size_t destsize, const char *src,
58 size_t srclen, pg_locale_t locale);
59static size_t strtitle_icu(char *dest, size_t destsize, const char *src,
60 size_t srclen, pg_locale_t locale);
61static size_t strupper_icu(char *dest, size_t destsize, const char *src,
62 size_t srclen, pg_locale_t locale);
63static size_t strfold_icu(char *dest, size_t destsize, const char *src,
64 size_t srclen, pg_locale_t locale);
65static size_t strlower_icu_utf8(char *dest, size_t destsize, const char *src,
66 size_t srclen, pg_locale_t locale);
67static size_t strtitle_icu_utf8(char *dest, size_t destsize, const char *src,
68 size_t srclen, pg_locale_t locale);
69static size_t strupper_icu_utf8(char *dest, size_t destsize, const char *src,
70 size_t srclen, pg_locale_t locale);
71static size_t strfold_icu_utf8(char *dest, size_t destsize, const char *src,
72 size_t srclen, pg_locale_t locale);
73static size_t downcase_ident_icu(char *dst, size_t dstsize, const char *src,
74 size_t srclen, pg_locale_t locale);
75static int strncoll_icu(const char *arg1, size_t len1,
76 const char *arg2, size_t len2,
77 pg_locale_t locale);
78static int strcoll_icu(const char *arg1, const char *arg2,
79 pg_locale_t locale);
80static size_t strnxfrm_icu(char *dest, size_t destsize,
81 const char *src, size_t srclen,
82 pg_locale_t locale);
83static size_t strxfrm_icu(char *dest, size_t destsize, const char *src,
84 pg_locale_t locale);
85extern char *get_collation_actual_version_icu(const char *collcollate);
86
88 const UChar *src, int32_t srcLength,
89 const char *locale,
91
92/*
93 * Converter object for converting between ICU's UChar strings and C strings
94 * in database encoding. Since the database encoding doesn't change, we only
95 * need one of these per session.
96 */
98
99static UCollator *make_icu_collator(const char *iculocstr,
100 const char *icurules);
101static size_t strnxfrm_prefix_icu(char *dest, size_t destsize,
102 const char *src, size_t srclen,
103 pg_locale_t locale);
104static size_t strxfrm_prefix_icu(char *dest, size_t destsize, const char *src,
105 pg_locale_t locale);
106static int strncoll_icu_utf8(const char *arg1, size_t len1,
107 const char *arg2, size_t len2,
108 pg_locale_t locale);
109static int strcoll_icu_utf8(const char *arg1,
110 const char *arg2,
111 pg_locale_t locale);
112static size_t strnxfrm_prefix_icu_utf8(char *dest, size_t destsize,
113 const char *src, size_t srclen,
114 pg_locale_t locale);
115static size_t strxfrm_prefix_icu_utf8(char *dest, size_t destsize, const char *src,
116 pg_locale_t locale);
117static void init_icu_converter(void);
119 const char *str, int32_t len);
121 UChar *dest, int32_t destlen,
122 const char *src, int32_t srclen);
123static int32_t icu_to_uchar(UChar **buff_uchar, const char *buff,
124 size_t nbytes);
125static size_t icu_from_uchar(char *dest, size_t destsize,
127static void icu_set_collation_attributes(UCollator *collator, const char *loc,
128 UErrorCode *status);
129static int32_t icu_convert_case(ICU_Convert_Func func, char *dest,
130 size_t destsize, const char *src,
131 size_t srclen, pg_locale_t locale);
133 const UChar *src, int32_t srcLength,
134 const char *locale,
137 const UChar *src, int32_t srcLength,
138 const char *locale,
140static int32_t foldcase_options(const char *locale);
141
142/*
143 * XXX: many of the functions below rely on casts directly from pg_wchar to
144 * UChar32, which is correct for UTF-8 and LATIN1, but not in general.
145 */
146
147static pg_wchar
149{
150 return u_toupper(wc);
151}
152
153static pg_wchar
155{
156 return u_tolower(wc);
157}
158
159static const struct collate_methods collate_methods_icu = {
161 .strcoll = strcoll_icu,
162 .strnxfrm = strnxfrm_icu,
163 .strxfrm = strxfrm_icu,
164 .strnxfrm_prefix = strnxfrm_prefix_icu,
165 .strxfrm_prefix = strxfrm_prefix_icu,
166 .strxfrm_is_safe = true,
167};
168
169static const struct collate_methods collate_methods_icu_utf8 = {
171 .strcoll = strcoll_icu_utf8,
172 .strnxfrm = strnxfrm_icu,
173 .strxfrm = strxfrm_icu,
174 .strnxfrm_prefix = strnxfrm_prefix_icu_utf8,
175 .strxfrm_prefix = strxfrm_prefix_icu_utf8,
176 .strxfrm_is_safe = true,
177};
178
179static bool
181{
182 return u_isdigit(wc);
183}
184
185static bool
187{
188 return u_isalpha(wc);
189}
190
191static bool
193{
194 return u_isalnum(wc);
195}
196
197static bool
199{
200 return u_isupper(wc);
201}
202
203static bool
205{
206 return u_islower(wc);
207}
208
209static bool
211{
212 return u_isgraph(wc);
213}
214
215static bool
217{
218 return u_isprint(wc);
219}
220
221static bool
223{
224 return u_ispunct(wc);
225}
226
227static bool
229{
230 return u_isspace(wc);
231}
232
233static bool
235{
236 return u_isxdigit(wc);
237}
238
239static bool
241{
243}
244
245static const struct ctype_methods ctype_methods_icu = {
247 .strtitle = strtitle_icu,
248 .strupper = strupper_icu,
249 .strfold = strfold_icu,
250 .downcase_ident = downcase_ident_icu,
251 .wc_isdigit = wc_isdigit_icu,
252 .wc_isalpha = wc_isalpha_icu,
253 .wc_isalnum = wc_isalnum_icu,
254 .wc_isupper = wc_isupper_icu,
255 .wc_islower = wc_islower_icu,
256 .wc_isgraph = wc_isgraph_icu,
257 .wc_isprint = wc_isprint_icu,
258 .wc_ispunct = wc_ispunct_icu,
259 .wc_isspace = wc_isspace_icu,
260 .wc_isxdigit = wc_isxdigit_icu,
261 .wc_iscased = wc_iscased_icu,
262 .wc_toupper = toupper_icu,
263 .wc_tolower = tolower_icu,
264};
265
266static const struct ctype_methods ctype_methods_icu_utf8 = {
268 .strtitle = strtitle_icu_utf8,
269 .strupper = strupper_icu_utf8,
270 .strfold = strfold_icu_utf8,
271 /* uses plain ASCII semantics for historical reasons */
272 .downcase_ident = NULL,
273 .wc_isdigit = wc_isdigit_icu,
274 .wc_isalpha = wc_isalpha_icu,
275 .wc_isalnum = wc_isalnum_icu,
276 .wc_isupper = wc_isupper_icu,
277 .wc_islower = wc_islower_icu,
278 .wc_isgraph = wc_isgraph_icu,
279 .wc_isprint = wc_isprint_icu,
280 .wc_ispunct = wc_ispunct_icu,
281 .wc_isspace = wc_isspace_icu,
282 .wc_isxdigit = wc_isxdigit_icu,
283 .wc_iscased = wc_iscased_icu,
284 .wc_toupper = toupper_icu,
285 .wc_tolower = tolower_icu,
286};
287
288/*
289 * ICU still depends on libc for compatibility with certain historical
290 * behavior for single-byte encodings. See downcase_ident_icu().
291 *
292 * XXX: consider fixing by decoding the single byte into a code point, and
293 * using u_tolower().
294 */
295static locale_t
296make_libc_ctype_locale(const char *ctype)
297{
298 locale_t loc;
299
300#ifndef WIN32
301 loc = newlocale(LC_CTYPE_MASK, ctype, NULL);
302#else
303 loc = _create_locale(LC_ALL, ctype);
304#endif
305 if (!loc)
307
308 return loc;
309}
310#endif /* USE_ICU */
311
314{
315#ifdef USE_ICU
316 bool deterministic;
317 const char *iculocstr;
318 const char *icurules = NULL;
320 locale_t loc = (locale_t) 0;
322
324 {
325 HeapTuple tp;
326 Datum datum;
327 bool isnull;
328
330 if (!HeapTupleIsValid(tp))
331 elog(ERROR, "cache lookup failed for database %u", MyDatabaseId);
332
333 /* default database collation is always deterministic */
334 deterministic = true;
338 datum = SysCacheGetAttr(DATABASEOID, tp,
340 if (!isnull)
342
343 /* libc only needed for default locale and single-byte encoding */
345 {
346 const char *ctype;
347
350 ctype = TextDatumGetCString(datum);
351
352 loc = make_libc_ctype_locale(ctype);
353 }
354
355 ReleaseSysCache(tp);
356 }
357 else
358 {
360 HeapTuple tp;
361 Datum datum;
362 bool isnull;
363
365 if (!HeapTupleIsValid(tp))
366 elog(ERROR, "cache lookup failed for collation %u", collid);
368 deterministic = collform->collisdeterministic;
372 datum = SysCacheGetAttr(COLLOID, tp,
374 if (!isnull)
376
377 ReleaseSysCache(tp);
378 }
379
381
382 result = MemoryContextAllocZero(context, sizeof(struct pg_locale_struct));
383 result->icu.locale = MemoryContextStrdup(context, iculocstr);
384 result->icu.ucol = collator;
385 result->icu.lt = loc;
386 result->deterministic = deterministic;
387 result->collate_is_c = false;
388 result->ctype_is_c = false;
390 {
391 result->icu.ucasemap = pg_ucasemap_open(iculocstr);
394 }
395 else
396 {
397 result->collate = &collate_methods_icu;
398 result->ctype = &ctype_methods_icu;
399 }
400
401 return result;
402#else /* not USE_ICU */
403 /* could get here if a collation was created by a build with ICU */
406 errmsg("ICU is not supported in this build")));
407
408 return NULL;
409#endif /* not USE_ICU */
410}
411
412#ifdef USE_ICU
413
414/*
415 * Check locale string and fix it if necessary. Returns a new palloc'd string.
416 */
417static char *
418fix_icu_locale_str(const char *loc_str)
419{
420 /*
421 * Must never open default collator, because it depends on the environment
422 * and may change at any time. Should not happen, but check here to catch
423 * bugs that might be hard to catch otherwise.
424 *
425 * NB: the default collator is not the same as the collator for the root
426 * locale. The root locale may be specified as the empty string, "und", or
427 * "root". The default collator is opened by passing NULL to ucol_open().
428 */
429 if (loc_str == NULL)
430 elog(ERROR, "opening default collator is not supported");
431
432 /*
433 * XXX There are currently no fixups required, but they could be added
434 * here.
435 */
436
437 return pstrdup(loc_str);
438}
439
440/*
441 * Wrapper around ucol_open() to handle API differences for older ICU
442 * versions.
443 *
444 * Ensure that no path leaks a UCollator.
445 */
446UCollator *
447pg_ucol_open(const char *loc_str)
448{
450 UErrorCode status;
451 char *fixed_str;
452
454
455 status = U_ZERO_ERROR;
456 collator = ucol_open(fixed_str, &status);
457 if (U_FAILURE(status))
459 /* use original string for error report */
461 errmsg("could not open collator for locale \"%s\": %s",
462 loc_str, u_errorName(status))));
463
465
466 return collator;
467}
468
469/*
470 * Wrapper around ucasemap_open() to handle API differences for older ICU
471 * versions.
472 *
473 * Additionally makes sure we get the right options for case folding.
474 */
475static UCaseMap *
476pg_ucasemap_open(const char *loc_str)
477{
478 UErrorCode status = U_ZERO_ERROR;
480 char *fixed_str;
481
483
485 if (U_FAILURE(status))
486 /* use original string for error report */
489 errmsg("could not open casemap for locale \"%s\": %s",
490 loc_str, u_errorName(status)));
491
493
494 return casemap;
495}
496
497/*
498 * Create a UCollator with the given locale string and rules.
499 *
500 * Ensure that no path leaks a UCollator.
501 */
502static UCollator *
503make_icu_collator(const char *iculocstr, const char *icurules)
504{
505 if (!icurules)
506 {
507 /* simple case without rules */
508 return pg_ucol_open(iculocstr);
509 }
510 else
511 {
514 const UChar *std_rules;
517 int32_t length;
518 int32_t total;
519 UErrorCode status;
520
521 /*
522 * If rules are specified, we extract the rules of the standard
523 * collation, add our own rules, and make a new collator with the
524 * combined rules.
525 */
527
529
531
532 total = u_strlen(std_rules) + u_strlen(my_rules) + 1;
533
534 /* avoid leaking collator on OOM */
536 if (!all_rules)
537 {
541 errmsg("out of memory")));
542 }
543
546
548
549 status = U_ZERO_ERROR;
552 NULL, &status);
553 if (U_FAILURE(status))
554 {
557 errmsg("could not open collator for locale \"%s\" with rules \"%s\": %s",
558 iculocstr, icurules, u_errorName(status))));
559 }
560
563 return collator_all_rules;
564 }
565}
566
567static size_t
568strlower_icu(char *dest, size_t destsize, const char *src, size_t srclen,
569 pg_locale_t locale)
570{
571 return icu_convert_case(u_strToLower, dest, destsize, src, srclen, locale);
572}
573
574static size_t
575strtitle_icu(char *dest, size_t destsize, const char *src, size_t srclen,
576 pg_locale_t locale)
577{
578 return icu_convert_case(u_strToTitle_default_BI, dest, destsize, src, srclen, locale);
579}
580
581static size_t
582strupper_icu(char *dest, size_t destsize, const char *src, size_t srclen,
583 pg_locale_t locale)
584{
585 return icu_convert_case(u_strToUpper, dest, destsize, src, srclen, locale);
586}
587
588static size_t
589strfold_icu(char *dest, size_t destsize, const char *src, size_t srclen,
590 pg_locale_t locale)
591{
592 return icu_convert_case(u_strFoldCase_default, dest, destsize, src, srclen, locale);
593}
594
595static size_t
596strlower_icu_utf8(char *dest, size_t destsize, const char *src, size_t srclen,
597 pg_locale_t locale)
598{
599 UErrorCode status = U_ZERO_ERROR;
601
602 needed = ucasemap_utf8ToLower(locale->icu.ucasemap, dest, destsize, src, srclen, &status);
603 if (U_FAILURE(status) && status != U_BUFFER_OVERFLOW_ERROR)
605 errmsg("case conversion failed: %s", u_errorName(status)));
606 return needed;
607}
608
609static size_t
610strtitle_icu_utf8(char *dest, size_t destsize, const char *src, size_t srclen,
611 pg_locale_t locale)
612{
613 UErrorCode status = U_ZERO_ERROR;
615
616 needed = ucasemap_utf8ToTitle(locale->icu.ucasemap, dest, destsize, src, srclen, &status);
617 if (U_FAILURE(status) && status != U_BUFFER_OVERFLOW_ERROR)
619 errmsg("case conversion failed: %s", u_errorName(status)));
620 return needed;
621}
622
623static size_t
624strupper_icu_utf8(char *dest, size_t destsize, const char *src, size_t srclen,
625 pg_locale_t locale)
626{
627 UErrorCode status = U_ZERO_ERROR;
629
630 needed = ucasemap_utf8ToUpper(locale->icu.ucasemap, dest, destsize, src, srclen, &status);
631 if (U_FAILURE(status) && status != U_BUFFER_OVERFLOW_ERROR)
633 errmsg("case conversion failed: %s", u_errorName(status)));
634 return needed;
635}
636
637static size_t
638strfold_icu_utf8(char *dest, size_t destsize, const char *src, size_t srclen,
639 pg_locale_t locale)
640{
641 UErrorCode status = U_ZERO_ERROR;
643
644 needed = ucasemap_utf8FoldCase(locale->icu.ucasemap, dest, destsize, src, srclen, &status);
645 if (U_FAILURE(status) && status != U_BUFFER_OVERFLOW_ERROR)
647 errmsg("case conversion failed: %s", u_errorName(status)));
648 return needed;
649}
650
651/*
652 * For historical compatibility, behavior is not multibyte-aware.
653 *
654 * NB: uses libc tolower() for single-byte encodings (also for historical
655 * compatibility), and therefore relies on the global LC_CTYPE setting.
656 */
657static size_t
658downcase_ident_icu(char *dst, size_t dstsize, const char *src,
659 size_t srclen, pg_locale_t locale)
660{
661 size_t i;
662 bool libc_lower;
663 locale_t lt = locale->icu.lt;
664
666
667 for (i = 0; i < srclen && i < dstsize; i++)
668 {
669 unsigned char ch = (unsigned char) src[i];
670
671 if (ch >= 'A' && ch <= 'Z')
673 else if (libc_lower && IS_HIGHBIT_SET(ch) && isupper_l(ch, lt))
674 ch = tolower_l(ch, lt);
675 dst[i] = (char) ch;
676 }
677
678 if (i < dstsize)
679 dst[i] = '\0';
680
681 return srclen;
682}
683
684/*
685 * strncoll_icu_utf8
686 *
687 * Call ucol_strcollUTF8() or ucol_strcoll() as appropriate for the given
688 * database encoding.
689 */
690int
691strncoll_icu_utf8(const char *arg1, size_t len1, const char *arg2, size_t len2,
692 pg_locale_t locale)
693{
694 int result;
695 UErrorCode status;
696
698
699 status = U_ZERO_ERROR;
700 result = ucol_strcollUTF8(locale->icu.ucol,
701 arg1, len1,
702 arg2, len2,
703 &status);
704 if (U_FAILURE(status))
706 (errmsg("collation failed: %s", u_errorName(status))));
707
708 return result;
709}
710
711int
712strcoll_icu_utf8(const char *arg1, const char *arg2, pg_locale_t locale)
713{
714 int result;
715 UErrorCode status;
716
718
719 status = U_ZERO_ERROR;
720 result = ucol_strcollUTF8(locale->icu.ucol,
721 arg1, -1,
722 arg2, -1,
723 &status);
724 if (U_FAILURE(status))
726 (errmsg("collation failed: %s", u_errorName(status))));
727
728 return result;
729}
730
731static size_t
732strnxfrm_icu_internal(char *dest, size_t destsize, const char *src, ssize_t srclen,
733 pg_locale_t locale)
734{
735 UChar sbuf[TEXTBUFLEN / sizeof(UChar)];
736 UChar *uchar = sbuf;
739
741
743
744 if (ulen >= lengthof(sbuf))
746
748
749 result_bsize = ucol_getSortKey(locale->icu.ucol,
750 uchar, ulen,
751 (uint8_t *) dest, destsize);
752
753 /*
754 * ucol_getSortKey() counts the nul-terminator in the result length, but
755 * this function should not.
756 */
757 Assert(result_bsize > 0);
758 result_bsize--;
759
760 if (uchar != sbuf)
761 pfree(uchar);
762
763 /* if dest is defined, it should be nul-terminated */
764 Assert(result_bsize >= destsize || dest[result_bsize] == '\0');
765
766 return result_bsize;
767}
768
769static size_t
770strnxfrm_icu(char *dest, size_t destsize, const char *src, size_t srclen,
771 pg_locale_t locale)
772{
773 return strnxfrm_icu_internal(dest, destsize, src, srclen, locale);
774}
775
776static size_t
777strxfrm_icu(char *dest, size_t destsize, const char *src,
778 pg_locale_t locale)
779{
780 return strnxfrm_icu_internal(dest, destsize, src, -1, locale);
781}
782
783static size_t
785 const char *src, ssize_t srclen,
786 pg_locale_t locale)
787{
788 size_t result;
789 UCharIterator iter;
790 uint32_t state[2];
791 UErrorCode status;
792
794
795 uiter_setUTF8(&iter, src, srclen);
796 state[0] = state[1] = 0; /* won't need that again */
797 status = U_ZERO_ERROR;
798 result = ucol_nextSortKeyPart(locale->icu.ucol,
799 &iter,
800 state,
801 (uint8_t *) dest,
802 destsize,
803 &status);
804 if (U_FAILURE(status))
806 (errmsg("sort key generation failed: %s",
807 u_errorName(status))));
808
809 return result;
810}
811
812static size_t
813strnxfrm_prefix_icu_utf8(char *dest, size_t destsize,
814 const char *src, size_t srclen,
815 pg_locale_t locale)
816{
817 return strnxfrm_prefix_icu_utf8_internal(dest, destsize, src, srclen, locale);
818}
819
820static size_t
821strxfrm_prefix_icu_utf8(char *dest, size_t destsize, const char *src,
822 pg_locale_t locale)
823{
824 return strnxfrm_prefix_icu_utf8_internal(dest, destsize, src, -1, locale);
825}
826
827char *
829{
833
835
838
840 return pstrdup(buf);
841}
842
843/*
844 * Convert a string in the database encoding into a string of UChars.
845 *
846 * The source string at buff is of length nbytes
847 * (it needn't be nul-terminated)
848 *
849 * *buff_uchar receives a pointer to the palloc'd result string, and
850 * the function's result is the number of UChars generated.
851 *
852 * The result string is nul-terminated, though most callers rely on the
853 * result length instead.
854 */
855static int32_t
856icu_to_uchar(UChar **buff_uchar, const char *buff, size_t nbytes)
857{
859
861
863
866 *buff_uchar, len_uchar + 1, buff, nbytes);
867
868 return len_uchar;
869}
870
871/*
872 * Convert a string of UChars into the database encoding.
873 *
874 * The source string at buff_uchar is of length len_uchar
875 * (it needn't be nul-terminated)
876 *
877 * *result receives a pointer to the palloc'd result string, and the
878 * function's result is the number of bytes generated (not counting nul).
879 *
880 * The result string is nul-terminated.
881 */
882static size_t
883icu_from_uchar(char *dest, size_t destsize, const UChar *buff_uchar, int32_t len_uchar)
884{
885 UErrorCode status;
887
889
890 status = U_ZERO_ERROR;
892 buff_uchar, len_uchar, &status);
893 if (U_FAILURE(status) && status != U_BUFFER_OVERFLOW_ERROR)
895 (errmsg("%s failed: %s", "ucnv_fromUChars",
896 u_errorName(status))));
897
898 if (len_result + 1 > destsize)
899 return len_result;
900
901 status = U_ZERO_ERROR;
903 buff_uchar, len_uchar, &status);
904 if (U_FAILURE(status) ||
907 (errmsg("%s failed: %s", "ucnv_fromUChars",
908 u_errorName(status))));
909
910 return len_result;
911}
912
913static int32_t
916{
917 UErrorCode status;
919
920 len_dest = len_source; /* try first with same length */
922 status = U_ZERO_ERROR;
924 mylocale->icu.locale, &status);
925 if (status == U_BUFFER_OVERFLOW_ERROR)
926 {
927 /* try again with adjusted length */
930 status = U_ZERO_ERROR;
932 mylocale->icu.locale, &status);
933 }
934 if (U_FAILURE(status))
936 (errmsg("case conversion failed: %s", u_errorName(status))));
937 return len_dest;
938}
939
940static int32_t
941icu_convert_case(ICU_Convert_Func func, char *dest, size_t destsize,
942 const char *src, size_t srclen, pg_locale_t locale)
943{
948 size_t result_len;
949
951 len_conv = convert_case_uchar(func, locale, &buff_conv,
956
957 return result_len;
958}
959
960static int32_t
962 const UChar *src, int32_t srcLength,
963 const char *locale,
965{
966 return u_strToTitle(dest, destCapacity, src, srcLength,
967 NULL, locale, pErrorCode);
968}
969
970static int32_t
972 const UChar *src, int32_t srcLength,
973 const char *locale,
975{
976 return u_strFoldCase(dest, destCapacity, src, srcLength,
978}
979
980/*
981 * Return the correct u_strFoldCase() options for the given locale.
982 *
983 * Unlike the ICU APIs for lowercasing, titlecasing, and uppercasing, case
984 * folding does not accept a locale. Instead it just supports a single option
985 * relevant to Turkic languages 'az' and 'tr'; check for those languages.
986 */
987static int32_t
988foldcase_options(const char *locale)
989{
991 char lang[ULOC_LANG_CAPACITY];
992 UErrorCode status = U_ZERO_ERROR;
993
994 uloc_getLanguage(locale, lang, ULOC_LANG_CAPACITY, &status);
995 if (U_SUCCESS(status) && status != U_STRING_NOT_TERMINATED_WARNING)
996 {
997 /*
998 * The option name is confusing, but it causes u_strFoldCase to use
999 * the 'T' mappings, which are ignored for U_FOLD_CASE_DEFAULT.
1000 */
1001 if (strcmp(lang, "tr") == 0 || strcmp(lang, "az") == 0)
1003 }
1004
1005 return options;
1006}
1007
1008/*
1009 * strncoll_icu
1010 *
1011 * Convert the arguments from the database encoding to UChar strings, then
1012 * call ucol_strcoll().
1013 *
1014 * When the database encoding is UTF-8, and ICU supports ucol_strcollUTF8(),
1015 * caller should call that instead.
1016 */
1017static int
1018strncoll_icu_internal(const char *arg1, ssize_t len1,
1019 const char *arg2, ssize_t len2,
1020 pg_locale_t locale)
1021{
1022 UChar sbuf[TEXTBUFLEN / sizeof(UChar)];
1023 UChar *buf = sbuf;
1024 int32_t ulen1;
1025 int32_t ulen2;
1026 size_t bufsize;
1027 UChar *uchar1,
1028 *uchar2;
1029 int result;
1030
1031 /* if encoding is UTF8, use more efficient strncoll_icu_utf8 */
1033
1035
1038
1039 /* ulen1+1 or ulen2+1 doesn't risk overflow, but summing them might */
1040 bufsize = add_size(ulen1 + 1, ulen2 + 1);
1041 if (bufsize > lengthof(sbuf))
1043
1044 uchar1 = buf;
1045 uchar2 = buf + ulen1 + 1;
1046
1049
1050 result = ucol_strcoll(locale->icu.ucol,
1051 uchar1, ulen1,
1052 uchar2, ulen2);
1053
1054 if (buf != sbuf)
1055 pfree(buf);
1056
1057 return result;
1058}
1059
1060static int
1061strncoll_icu(const char *arg1, size_t len1, const char *arg2, size_t len2,
1062 pg_locale_t locale)
1063{
1064 return strncoll_icu_internal(arg1, len1, arg2, len2, locale);
1065}
1066
1067static int
1068strcoll_icu(const char *arg1, const char *arg2, pg_locale_t locale)
1069{
1070 return strncoll_icu_internal(arg1, -1, arg2, -1, locale);
1071}
1072
1073static size_t
1074strnxfrm_prefix_icu_internal(char *dest, size_t destsize,
1075 const char *src, ssize_t srclen,
1076 pg_locale_t locale)
1077{
1078 UChar sbuf[TEXTBUFLEN / sizeof(UChar)];
1079 UChar *uchar = sbuf;
1080 UCharIterator iter;
1081 uint32_t state[2];
1082 UErrorCode status;
1083 int32_t ulen;
1085
1086 /* if encoding is UTF8, use more efficient strnxfrm_prefix_icu_utf8 */
1088
1090
1092
1093 if (ulen >= lengthof(sbuf))
1094 uchar = palloc_array(UChar, ulen + 1);
1095
1097
1098 uiter_setString(&iter, uchar, ulen);
1099 state[0] = state[1] = 0; /* won't need that again */
1100 status = U_ZERO_ERROR;
1101 result_bsize = ucol_nextSortKeyPart(locale->icu.ucol,
1102 &iter,
1103 state,
1104 (uint8_t *) dest,
1105 destsize,
1106 &status);
1107 if (U_FAILURE(status))
1108 ereport(ERROR,
1109 (errmsg("sort key generation failed: %s",
1110 u_errorName(status))));
1111
1112 if (uchar != sbuf)
1113 pfree(uchar);
1114
1115 return result_bsize;
1116}
1117
1118static size_t
1119strnxfrm_prefix_icu(char *dest, size_t destsize, const char *src, size_t srclen,
1120 pg_locale_t locale)
1121{
1122 return strnxfrm_prefix_icu_internal(dest, destsize, src, srclen, locale);
1123}
1124
1125static size_t
1126strxfrm_prefix_icu(char *dest, size_t destsize, const char *src,
1127 pg_locale_t locale)
1128{
1129 return strnxfrm_prefix_icu_internal(dest, destsize, src, -1, locale);
1130}
1131
1132static void
1134{
1135 const char *icu_encoding_name;
1136 UErrorCode status;
1138
1139 if (icu_converter)
1140 return; /* already done */
1141
1143 if (!icu_encoding_name)
1144 ereport(ERROR,
1146 errmsg("encoding \"%s\" not supported by ICU",
1148
1149 status = U_ZERO_ERROR;
1150 conv = ucnv_open(icu_encoding_name, &status);
1151 if (U_FAILURE(status))
1152 ereport(ERROR,
1153 (errmsg("could not open ICU converter for encoding \"%s\": %s",
1154 icu_encoding_name, u_errorName(status))));
1155
1157}
1158
1159/*
1160 * Find length, in UChars, of given string if converted to UChar string.
1161 *
1162 * A length of -1 indicates that the input string is NUL-terminated.
1163 *
1164 * Note: given the assumption that the input string fits in MaxAllocSize,
1165 * the result cannot overflow int32_t. But callers must be careful about
1166 * multiplying the result by sizeof(UChar).
1167 */
1168static int32_t
1170{
1171 UErrorCode status = U_ZERO_ERROR;
1172 int32_t ulen;
1173
1174 ulen = ucnv_toUChars(converter, NULL, 0, str, len, &status);
1175 if (U_FAILURE(status) && status != U_BUFFER_OVERFLOW_ERROR)
1176 ereport(ERROR,
1177 (errmsg("%s failed: %s", "ucnv_toUChars", u_errorName(status))));
1178 return ulen;
1179}
1180
1181/*
1182 * Convert the given source string into a UChar string, stored in dest, and
1183 * return the length (in UChars).
1184 *
1185 * A srclen of -1 indicates that the input string is NUL-terminated.
1186 */
1187static int32_t
1189 const char *src, int32_t srclen)
1190{
1191 UErrorCode status = U_ZERO_ERROR;
1192 int32_t ulen;
1193
1194 ulen = ucnv_toUChars(converter, dest, destlen, src, srclen, &status);
1195 if (U_FAILURE(status))
1196 ereport(ERROR,
1197 (errmsg("%s failed: %s", "ucnv_toUChars", u_errorName(status))));
1198 return ulen;
1199}
1200
1201/*
1202 * Parse collation attributes from the given locale string and apply them to
1203 * the open collator.
1204 *
1205 * First, the locale string is canonicalized to an ICU format locale ID such
1206 * as "und@colStrength=primary;colCaseLevel=yes". Then, it parses and applies
1207 * the key-value arguments.
1208 *
1209 * Starting with ICU version 54, the attributes are processed automatically by
1210 * ucol_open(), so this is only necessary for emulating this behavior on older
1211 * versions.
1212 */
1214static void
1216 UErrorCode *status)
1217{
1218 int32_t len;
1219 char *icu_locale_id;
1220 char *lower_str;
1221 char *str;
1222 char *token;
1223
1224 /*
1225 * The input locale may be a BCP 47 language tag, e.g.
1226 * "und-u-kc-ks-level1", which expresses the same attributes in a
1227 * different form. It will be converted to the equivalent ICU format
1228 * locale ID, e.g. "und@colcaselevel=yes;colstrength=primary", by
1229 * uloc_canonicalize().
1230 */
1231 *status = U_ZERO_ERROR;
1232 len = uloc_canonicalize(loc, NULL, 0, status);
1233 icu_locale_id = palloc(len + 1);
1234 *status = U_ZERO_ERROR;
1235 len = uloc_canonicalize(loc, icu_locale_id, len + 1, status);
1236 if (U_FAILURE(*status) || *status == U_STRING_NOT_TERMINATED_WARNING)
1237 return;
1238
1240
1242
1243 str = strchr(lower_str, '@');
1244 if (!str)
1245 return;
1246 str++;
1247
1248 while ((token = strsep(&str, ";")))
1249 {
1250 char *e = strchr(token, '=');
1251
1252 if (e)
1253 {
1254 char *name;
1255 char *value;
1258
1259 *status = U_ZERO_ERROR;
1260
1261 *e = '\0';
1262 name = token;
1263 value = e + 1;
1264
1265 /*
1266 * See attribute name and value lists in ICU i18n/coll.cpp
1267 */
1268 if (strcmp(name, "colstrength") == 0)
1270 else if (strcmp(name, "colbackwards") == 0)
1272 else if (strcmp(name, "colcaselevel") == 0)
1274 else if (strcmp(name, "colcasefirst") == 0)
1276 else if (strcmp(name, "colalternate") == 0)
1278 else if (strcmp(name, "colnormalization") == 0)
1280 else if (strcmp(name, "colnumeric") == 0)
1282 else
1283 /* ignore if unknown */
1284 continue;
1285
1286 if (strcmp(value, "primary") == 0)
1288 else if (strcmp(value, "secondary") == 0)
1290 else if (strcmp(value, "tertiary") == 0)
1292 else if (strcmp(value, "quaternary") == 0)
1294 else if (strcmp(value, "identical") == 0)
1296 else if (strcmp(value, "no") == 0)
1297 uvalue = UCOL_OFF;
1298 else if (strcmp(value, "yes") == 0)
1299 uvalue = UCOL_ON;
1300 else if (strcmp(value, "shifted") == 0)
1302 else if (strcmp(value, "non-ignorable") == 0)
1304 else if (strcmp(value, "lower") == 0)
1306 else if (strcmp(value, "upper") == 0)
1308 else
1309 {
1310 *status = U_ILLEGAL_ARGUMENT_ERROR;
1311 break;
1312 }
1313
1315 }
1316 }
1317
1319}
1320
1321#endif /* USE_ICU */
#define TextDatumGetCString(d)
Definition builtins.h:99
#define pg_attribute_unused()
Definition c.h:208
#define IS_HIGHBIT_SET(ch)
Definition c.h:1284
#define Assert(condition)
Definition c.h:1002
uint32_t uint32
Definition c.h:683
#define lengthof(array)
Definition c.h:932
size_t Size
Definition c.h:748
uint32 result
Oid collid
int errcode(int sqlerrcode)
Definition elog.c:875
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define ereport(elevel,...)
Definition elog.h:152
const char * get_encoding_name_for_icu(int encoding)
Definition encnames.c:467
#define palloc_array(type, count)
Definition fe_memutils.h:91
#define MCXT_ALLOC_NO_OOM
Definition fe_memutils.h:29
#define palloc_array_extended(type, count, flags)
Definition fe_memutils.h:93
char * asc_tolower(const char *buff, size_t nbytes)
Oid MyDatabaseId
Definition globals.c:96
const char * str
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
#define token
#define bufsize
static struct @175 value
int i
Definition isn.c:77
#define PG_UTF8
Definition mbprint.c:43
unsigned int pg_wchar
Definition mbprint.c:31
int GetDatabaseEncoding(void)
Definition mbutils.c:1389
int pg_database_encoding_max_length(void)
Definition mbutils.c:1673
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition mcxt.c:1897
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition mcxt.c:1269
Size add_size(Size s1, Size s2)
Definition mcxt.c:1733
char * pstrdup(const char *in)
Definition mcxt.c:1910
void pfree(void *pointer)
Definition mcxt.c:1619
void * palloc(Size size)
Definition mcxt.c:1390
static char * errmsg
END_CATALOG_STRUCT typedef FormData_pg_collation * Form_pg_collation
const void size_t len
pg_locale_t create_pg_locale_icu(Oid collid, MemoryContext context)
#define TEXTBUFLEN
void report_newlocale_failure(const char *localename)
static char buf[DEFAULT_XLOG_SEG_SIZE]
#define pg_encoding_to_char
Definition pg_wchar.h:483
char * strsep(char **stringp, const char *delim)
Definition strsep.c:50
static unsigned char pg_ascii_tolower(unsigned char ch)
Definition port.h:189
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
uint64_t Datum
Definition postgres.h:70
unsigned int Oid
e
static int fb(int x)
int(* strncoll)(const char *arg1, size_t len1, const char *arg2, size_t len2, pg_locale_t locale)
Definition pg_locale.h:66
size_t(* strlower)(char *dest, size_t destsize, const char *src, size_t srclen, pg_locale_t locale)
Definition pg_locale.h:101
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:265
Datum SysCacheGetAttrNotNull(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition syscache.c:626
HeapTuple SearchSysCache1(SysCacheIdentifier cacheId, Datum key1)
Definition syscache.c:221
Datum SysCacheGetAttr(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition syscache.c:596
static enum CaseMapResult casemap(char32_t u1, CaseKind casekind, bool full, const char *src, size_t srclen, size_t srcoff, char32_t *simple, const char32_t **special)
const char * name
#define locale_t
Definition win32_port.h:446
#define tolower_l
Definition win32_port.h:447
#define isupper_l
Definition win32_port.h:457