|
92 | 92 | #include "utils/numeric.h"
|
93 | 93 | #include "utils/pg_locale.h"
|
94 | 94 |
|
| 95 | +#ifdef USE_ICU |
| 96 | +#include <unicode/utypes.h> /* Basic ICU data types */ |
| 97 | +#include <unicode/ucnv.h> /* C Converter API */ |
| 98 | +#include <unicode/ustring.h> |
| 99 | +#endif /* USE_ICU */ |
| 100 | + |
95 | 101 | /* ----------
|
96 | 102 | * Routines type
|
97 | 103 | * ----------
|
@@ -940,6 +946,12 @@ typedef struct NUMProc
|
940 | 946 | } NUMProc;
|
941 | 947 |
|
942 | 948 |
|
| 949 | +#ifdef USE_ICU |
| 950 | +static UConverter *conv = NULL; |
| 951 | +#define STACKBUFLEN 1024 / sizeof(UChar) |
| 952 | +#endif /* USE_ICU */ |
| 953 | + |
| 954 | + |
943 | 955 | /* ----------
|
944 | 956 | * Functions
|
945 | 957 | * ----------
|
@@ -1491,6 +1503,82 @@ str_tolower(const char *buff, size_t nbytes, Oid collid)
|
1491 | 1503 | {
|
1492 | 1504 | result = asc_tolower(buff, nbytes);
|
1493 | 1505 | }
|
| 1506 | +#ifdef USE_ICU |
| 1507 | + /* use ICU only when max encoding length > one */ |
| 1508 | + if (pg_database_encoding_max_length() > 1) |
| 1509 | + { |
| 1510 | + UChar sourcebuf[STACKBUFLEN], destbuf[STACKBUFLEN]; |
| 1511 | + UChar *source, *dest; |
| 1512 | + int buflen; |
| 1513 | + size_t result_size, usize; |
| 1514 | + UErrorCode status = U_ZERO_ERROR; |
| 1515 | + |
| 1516 | + if (conv == NULL) |
| 1517 | + { |
| 1518 | + conv = ucnv_open(NULL, &status); |
| 1519 | + if (U_FAILURE(status)) |
| 1520 | + { |
| 1521 | + ereport(ERROR, |
| 1522 | + (errcode(status), |
| 1523 | + errmsg("ICU error: oracle_compat.c, could not get converter for \"%s\"", ucnv_getDefaultName()))); |
| 1524 | + } |
| 1525 | + } |
| 1526 | + |
| 1527 | + if (nbytes >= STACKBUFLEN / sizeof(UChar)) |
| 1528 | + { |
| 1529 | + buflen = (nbytes + 1) * sizeof(UChar); |
| 1530 | + source = palloc(buflen); |
| 1531 | + dest = palloc(buflen); |
| 1532 | + } |
| 1533 | + else |
| 1534 | + { |
| 1535 | + buflen = STACKBUFLEN; |
| 1536 | + source = sourcebuf; |
| 1537 | + dest = destbuf; |
| 1538 | + } |
| 1539 | + // convert to UTF-16 |
| 1540 | + ucnv_toUChars(conv, source, buflen, buff, nbytes, &status); |
| 1541 | + if (U_FAILURE(status)) |
| 1542 | + { |
| 1543 | + ereport(ERROR, |
| 1544 | + (errcode(status), |
| 1545 | + errmsg("ICU error: Could not convert string"))); |
| 1546 | + } |
| 1547 | + |
| 1548 | + // run desired function |
| 1549 | + buflen = u_strToLower(dest, buflen, source, -1, NULL, &status); |
| 1550 | + if (U_FAILURE(status)) |
| 1551 | + { |
| 1552 | + ereport(ERROR, |
| 1553 | + (errcode(status), |
| 1554 | + errmsg("ICU error: Could not modify case"))); |
| 1555 | + } |
| 1556 | + |
| 1557 | + // and convert modified utf-16 string back to text |
| 1558 | + result_size = UCNV_GET_MAX_BYTES_FOR_STRING(buflen, ucnv_getMaxCharSize(conv)); |
| 1559 | + result = palloc(result_size); |
| 1560 | + |
| 1561 | + usize = ucnv_fromUChars(conv, result, result_size, |
| 1562 | + dest, buflen, &status); |
| 1563 | + |
| 1564 | + if (U_FAILURE(status)) |
| 1565 | + { |
| 1566 | + /* Invalid multibyte character encountered ... shouldn't happen */ |
| 1567 | + ereport(ERROR, |
| 1568 | + (errcode(ERRCODE_CHARACTER_NOT_IN_REPERTOIRE), |
| 1569 | + errmsg("ICU: invalid multibyte character for locale"))); |
| 1570 | + } |
| 1571 | + |
| 1572 | + Assert(usize <= (size_t) (buflen * sizeof(UChar))); |
| 1573 | + |
| 1574 | + if (nbytes >= STACKBUFLEN / sizeof(UChar)) |
| 1575 | + { |
| 1576 | + pfree(source); |
| 1577 | + pfree(dest); |
| 1578 | + } |
| 1579 | + return result; |
| 1580 | + } |
| 1581 | +#else |
1494 | 1582 | #ifdef USE_WIDE_UPPER_LOWER
|
1495 | 1583 | else if (pg_database_encoding_max_length() > 1)
|
1496 | 1584 | {
|
@@ -1544,6 +1632,7 @@ str_tolower(const char *buff, size_t nbytes, Oid collid)
|
1544 | 1632 | pfree(workspace);
|
1545 | 1633 | }
|
1546 | 1634 | #endif /* USE_WIDE_UPPER_LOWER */
|
| 1635 | +#endif /* USE_ICU */ |
1547 | 1636 | else
|
1548 | 1637 | {
|
1549 | 1638 | #ifdef HAVE_LOCALE_T
|
@@ -1611,6 +1700,82 @@ str_toupper(const char *buff, size_t nbytes, Oid collid)
|
1611 | 1700 | {
|
1612 | 1701 | result = asc_toupper(buff, nbytes);
|
1613 | 1702 | }
|
| 1703 | +#ifdef USE_ICU |
| 1704 | + /* use ICU only when max encoding length > one */ |
| 1705 | + if (pg_database_encoding_max_length() > 1) |
| 1706 | + { |
| 1707 | + UChar sourcebuf[STACKBUFLEN], destbuf[STACKBUFLEN]; |
| 1708 | + UChar *source, *dest; |
| 1709 | + int buflen; |
| 1710 | + size_t result_size, usize; |
| 1711 | + UErrorCode status = U_ZERO_ERROR; |
| 1712 | + |
| 1713 | + if (conv == NULL) |
| 1714 | + { |
| 1715 | + conv = ucnv_open(NULL, &status); |
| 1716 | + if (U_FAILURE(status)) |
| 1717 | + { |
| 1718 | + ereport(ERROR, |
| 1719 | + (errcode(status), |
| 1720 | + errmsg("ICU error: oracle_compat.c, could not get converter for \"%s\"", ucnv_getDefaultName()))); |
| 1721 | + } |
| 1722 | + } |
| 1723 | + |
| 1724 | + if (nbytes >= STACKBUFLEN / sizeof(UChar)) |
| 1725 | + { |
| 1726 | + buflen = (nbytes + 1) * sizeof(UChar); |
| 1727 | + source = palloc(buflen); |
| 1728 | + dest = palloc(buflen); |
| 1729 | + } |
| 1730 | + else |
| 1731 | + { |
| 1732 | + buflen = STACKBUFLEN; |
| 1733 | + source = sourcebuf; |
| 1734 | + dest = destbuf; |
| 1735 | + } |
| 1736 | + // convert to UTF-16 |
| 1737 | + ucnv_toUChars(conv, source, buflen, buff, nbytes, &status); |
| 1738 | + if (U_FAILURE(status)) |
| 1739 | + { |
| 1740 | + ereport(ERROR, |
| 1741 | + (errcode(status), |
| 1742 | + errmsg("ICU error: Could not convert string"))); |
| 1743 | + } |
| 1744 | + |
| 1745 | + // run desired function |
| 1746 | + buflen = u_strToUpper(dest, buflen, source, -1, NULL, &status); |
| 1747 | + if (U_FAILURE(status)) |
| 1748 | + { |
| 1749 | + ereport(ERROR, |
| 1750 | + (errcode(status), |
| 1751 | + errmsg("ICU error: Could not modify case"))); |
| 1752 | + } |
| 1753 | + |
| 1754 | + // and convert modified utf-16 string back to text |
| 1755 | + result_size = UCNV_GET_MAX_BYTES_FOR_STRING(buflen, ucnv_getMaxCharSize(conv)); |
| 1756 | + result = palloc(result_size); |
| 1757 | + |
| 1758 | + usize = ucnv_fromUChars(conv, result, result_size, |
| 1759 | + dest, buflen, &status); |
| 1760 | + |
| 1761 | + if (U_FAILURE(status)) |
| 1762 | + { |
| 1763 | + /* Invalid multibyte character encountered ... shouldn't happen */ |
| 1764 | + ereport(ERROR, |
| 1765 | + (errcode(ERRCODE_CHARACTER_NOT_IN_REPERTOIRE), |
| 1766 | + errmsg("ICU: invalid multibyte character for locale"))); |
| 1767 | + } |
| 1768 | + |
| 1769 | + Assert(usize <= (size_t) (buflen * sizeof(UChar))); |
| 1770 | + |
| 1771 | + if (nbytes >= STACKBUFLEN / sizeof(UChar)) |
| 1772 | + { |
| 1773 | + pfree(source); |
| 1774 | + pfree(dest); |
| 1775 | + } |
| 1776 | + return result; |
| 1777 | + } |
| 1778 | +#else |
1614 | 1779 | #ifdef USE_WIDE_UPPER_LOWER
|
1615 | 1780 | else if (pg_database_encoding_max_length() > 1)
|
1616 | 1781 | {
|
@@ -1664,6 +1829,7 @@ str_toupper(const char *buff, size_t nbytes, Oid collid)
|
1664 | 1829 | pfree(workspace);
|
1665 | 1830 | }
|
1666 | 1831 | #endif /* USE_WIDE_UPPER_LOWER */
|
| 1832 | +#endif /* USE_ICU */ |
1667 | 1833 | else
|
1668 | 1834 | {
|
1669 | 1835 | #ifdef HAVE_LOCALE_T
|
@@ -1732,6 +1898,82 @@ str_initcap(const char *buff, size_t nbytes, Oid collid)
|
1732 | 1898 | {
|
1733 | 1899 | result = asc_initcap(buff, nbytes);
|
1734 | 1900 | }
|
| 1901 | +#ifdef USE_ICU |
| 1902 | + /* use ICU only when max encoding length > one */ |
| 1903 | + if (pg_database_encoding_max_length() > 1) |
| 1904 | + { |
| 1905 | + UChar sourcebuf[STACKBUFLEN], destbuf[STACKBUFLEN]; |
| 1906 | + UChar *source, *dest; |
| 1907 | + int buflen; |
| 1908 | + size_t result_size, usize; |
| 1909 | + UErrorCode status = U_ZERO_ERROR; |
| 1910 | + |
| 1911 | + if (conv == NULL) |
| 1912 | + { |
| 1913 | + conv = ucnv_open(NULL, &status); |
| 1914 | + if (U_FAILURE(status)) |
| 1915 | + { |
| 1916 | + ereport(ERROR, |
| 1917 | + (errcode(status), |
| 1918 | + errmsg("ICU error: oracle_compat.c, could not get converter for \"%s\"", ucnv_getDefaultName()))); |
| 1919 | + } |
| 1920 | + } |
| 1921 | + |
| 1922 | + if (nbytes >= STACKBUFLEN / sizeof(UChar)) |
| 1923 | + { |
| 1924 | + buflen = (nbytes + 1) * sizeof(UChar); |
| 1925 | + source = palloc(buflen); |
| 1926 | + dest = palloc(buflen); |
| 1927 | + } |
| 1928 | + else |
| 1929 | + { |
| 1930 | + buflen = STACKBUFLEN; |
| 1931 | + source = sourcebuf; |
| 1932 | + dest = destbuf; |
| 1933 | + } |
| 1934 | + // convert to UTF-16 |
| 1935 | + ucnv_toUChars(conv, source, buflen, buff, nbytes, &status); |
| 1936 | + if (U_FAILURE(status)) |
| 1937 | + { |
| 1938 | + ereport(ERROR, |
| 1939 | + (errcode(status), |
| 1940 | + errmsg("ICU error: Could not convert string"))); |
| 1941 | + } |
| 1942 | + |
| 1943 | + // run desired function |
| 1944 | + buflen = u_strToTitle(dest, buflen, source, -1, NULL, NULL, &status); |
| 1945 | + if (U_FAILURE(status)) |
| 1946 | + { |
| 1947 | + ereport(ERROR, |
| 1948 | + (errcode(status), |
| 1949 | + errmsg("ICU error: Could not modify case"))); |
| 1950 | + } |
| 1951 | + |
| 1952 | + // and convert modified utf-16 string back to text |
| 1953 | + result_size = UCNV_GET_MAX_BYTES_FOR_STRING(buflen, ucnv_getMaxCharSize(conv)); |
| 1954 | + result = palloc(result_size); |
| 1955 | + |
| 1956 | + usize = ucnv_fromUChars(conv, result, result_size, |
| 1957 | + dest, buflen, &status); |
| 1958 | + |
| 1959 | + if (U_FAILURE(status)) |
| 1960 | + { |
| 1961 | + /* Invalid multibyte character encountered ... shouldn't happen */ |
| 1962 | + ereport(ERROR, |
| 1963 | + (errcode(ERRCODE_CHARACTER_NOT_IN_REPERTOIRE), |
| 1964 | + errmsg("ICU: invalid multibyte character for locale"))); |
| 1965 | + } |
| 1966 | + |
| 1967 | + Assert(usize <= (size_t) (buflen * sizeof(UChar))); |
| 1968 | + |
| 1969 | + if (nbytes >= STACKBUFLEN / sizeof(UChar)) |
| 1970 | + { |
| 1971 | + pfree(source); |
| 1972 | + pfree(dest); |
| 1973 | + } |
| 1974 | + return result; |
| 1975 | + } |
| 1976 | +#else |
1735 | 1977 | #ifdef USE_WIDE_UPPER_LOWER
|
1736 | 1978 | else if (pg_database_encoding_max_length() > 1)
|
1737 | 1979 | {
|
@@ -1797,6 +2039,7 @@ str_initcap(const char *buff, size_t nbytes, Oid collid)
|
1797 | 2039 | pfree(workspace);
|
1798 | 2040 | }
|
1799 | 2041 | #endif /* USE_WIDE_UPPER_LOWER */
|
| 2042 | +#endif /* USE_ICU */ |
1800 | 2043 | else
|
1801 | 2044 | {
|
1802 | 2045 | #ifdef HAVE_LOCALE_T
|
|
0 commit comments