|
58 | 58 | #include "catalog/pg_control.h"
|
59 | 59 | #include "mb/pg_wchar.h"
|
60 | 60 | #include "utils/builtins.h"
|
| 61 | +#include "utils/formatting.h" |
61 | 62 | #include "utils/hsearch.h"
|
62 | 63 | #include "utils/lsyscache.h"
|
63 | 64 | #include "utils/memutils.h"
|
@@ -132,6 +133,9 @@ static HTAB *collation_cache = NULL;
|
132 | 133 | static char *IsoLocaleName(const char *); /* MSVC specific */
|
133 | 134 | #endif
|
134 | 135 |
|
| 136 | +#ifdef USE_ICU |
| 137 | +static void icu_set_collation_attributes(UCollator *collator, const char *loc); |
| 138 | +#endif |
135 | 139 |
|
136 | 140 | /*
|
137 | 141 | * pg_perm_setlocale
|
@@ -1380,6 +1384,9 @@ pg_newlocale_from_collation(Oid collid)
|
1380 | 1384 | (errmsg("could not open collator for locale \"%s\": %s",
|
1381 | 1385 | collcollate, u_errorName(status))));
|
1382 | 1386 |
|
| 1387 | + if (U_ICU_VERSION_MAJOR_NUM < 54) |
| 1388 | + icu_set_collation_attributes(collator, collcollate); |
| 1389 | + |
1383 | 1390 | /* We will leak this string if we get an error below :-( */
|
1384 | 1391 | result.info.icu.locale = MemoryContextStrdup(TopMemoryContext,
|
1385 | 1392 | collcollate);
|
@@ -1588,6 +1595,103 @@ icu_from_uchar(char **result, const UChar *buff_uchar, int32_t len_uchar)
|
1588 | 1595 | return len_result;
|
1589 | 1596 | }
|
1590 | 1597 |
|
| 1598 | +/* |
| 1599 | + * Parse collation attributes and apply them to the open collator. This takes |
| 1600 | + * a string like "und@colStrength=primary;colCaseLevel=yes" and parses and |
| 1601 | + * applies the key-value arguments. |
| 1602 | + * |
| 1603 | + * Starting with ICU version 54, the attributes are processed automatically by |
| 1604 | + * ucol_open(), so this is only necessary for emulating this behavior on older |
| 1605 | + * versions. |
| 1606 | + */ |
| 1607 | +pg_attribute_unused() |
| 1608 | +static void |
| 1609 | +icu_set_collation_attributes(UCollator *collator, const char *loc) |
| 1610 | +{ |
| 1611 | + char *str = asc_tolower(loc, strlen(loc)); |
| 1612 | + |
| 1613 | + str = strchr(str, '@'); |
| 1614 | + if (!str) |
| 1615 | + return; |
| 1616 | + str++; |
| 1617 | + |
| 1618 | + for (char *token = strtok(str, ";"); token; token = strtok(NULL, ";")) |
| 1619 | + { |
| 1620 | + char *e = strchr(token, '='); |
| 1621 | + |
| 1622 | + if (e) |
| 1623 | + { |
| 1624 | + char *name; |
| 1625 | + char *value; |
| 1626 | + UColAttribute uattr = -1; |
| 1627 | + UColAttributeValue uvalue = -1; |
| 1628 | + UErrorCode status; |
| 1629 | + |
| 1630 | + status = U_ZERO_ERROR; |
| 1631 | + |
| 1632 | + *e = '\0'; |
| 1633 | + name = token; |
| 1634 | + value = e + 1; |
| 1635 | + |
| 1636 | + /* |
| 1637 | + * See attribute name and value lists in ICU i18n/coll.cpp |
| 1638 | + */ |
| 1639 | + if (strcmp(name, "colstrength") == 0) |
| 1640 | + uattr = UCOL_STRENGTH; |
| 1641 | + else if (strcmp(name, "colbackwards") == 0) |
| 1642 | + uattr = UCOL_FRENCH_COLLATION; |
| 1643 | + else if (strcmp(name, "colcaselevel") == 0) |
| 1644 | + uattr = UCOL_CASE_LEVEL; |
| 1645 | + else if (strcmp(name, "colcasefirst") == 0) |
| 1646 | + uattr = UCOL_CASE_FIRST; |
| 1647 | + else if (strcmp(name, "colalternate") == 0) |
| 1648 | + uattr = UCOL_ALTERNATE_HANDLING; |
| 1649 | + else if (strcmp(name, "colnormalization") == 0) |
| 1650 | + uattr = UCOL_NORMALIZATION_MODE; |
| 1651 | + else if (strcmp(name, "colnumeric") == 0) |
| 1652 | + uattr = UCOL_NUMERIC_COLLATION; |
| 1653 | + /* ignore if unknown */ |
| 1654 | + |
| 1655 | + if (strcmp(value, "primary") == 0) |
| 1656 | + uvalue = UCOL_PRIMARY; |
| 1657 | + else if (strcmp(value, "secondary") == 0) |
| 1658 | + uvalue = UCOL_SECONDARY; |
| 1659 | + else if (strcmp(value, "tertiary") == 0) |
| 1660 | + uvalue = UCOL_TERTIARY; |
| 1661 | + else if (strcmp(value, "quaternary") == 0) |
| 1662 | + uvalue = UCOL_QUATERNARY; |
| 1663 | + else if (strcmp(value, "identical") == 0) |
| 1664 | + uvalue = UCOL_IDENTICAL; |
| 1665 | + else if (strcmp(value, "no") == 0) |
| 1666 | + uvalue = UCOL_OFF; |
| 1667 | + else if (strcmp(value, "yes") == 0) |
| 1668 | + uvalue = UCOL_ON; |
| 1669 | + else if (strcmp(value, "shifted") == 0) |
| 1670 | + uvalue = UCOL_SHIFTED; |
| 1671 | + else if (strcmp(value, "non-ignorable") == 0) |
| 1672 | + uvalue = UCOL_NON_IGNORABLE; |
| 1673 | + else if (strcmp(value, "lower") == 0) |
| 1674 | + uvalue = UCOL_LOWER_FIRST; |
| 1675 | + else if (strcmp(value, "upper") == 0) |
| 1676 | + uvalue = UCOL_UPPER_FIRST; |
| 1677 | + else |
| 1678 | + status = U_ILLEGAL_ARGUMENT_ERROR; |
| 1679 | + |
| 1680 | + if (uattr != -1 && uvalue != -1) |
| 1681 | + ucol_setAttribute(collator, uattr, uvalue, &status); |
| 1682 | + |
| 1683 | + /* |
| 1684 | + * Pretend the error came from ucol_open(), for consistent error |
| 1685 | + * message across ICU versions. |
| 1686 | + */ |
| 1687 | + if (U_FAILURE(status)) |
| 1688 | + ereport(ERROR, |
| 1689 | + (errmsg("could not open collator for locale \"%s\": %s", |
| 1690 | + loc, u_errorName(status)))); |
| 1691 | + } |
| 1692 | + } |
| 1693 | +} |
| 1694 | + |
1591 | 1695 | #endif /* USE_ICU */
|
1592 | 1696 |
|
1593 | 1697 | /*
|
|
0 commit comments