|
92 | 92 | #include"utils/numeric.h"
|
93 | 93 | #include"utils/pg_locale.h"
|
94 | 94 |
|
| 95 | +#ifdefUSE_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 | +#ifdefUSE_ICU |
| 950 | +staticUConverter*conv=NULL; |
| 951 | +#defineSTACKBUFLEN1024 / 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 | +#ifdefUSE_ICU |
| 1507 | +/* use ICU only when max encoding length > one */ |
| 1508 | +if (pg_database_encoding_max_length()>1) |
| 1509 | +{ |
| 1510 | +UCharsourcebuf[STACKBUFLEN],destbuf[STACKBUFLEN]; |
| 1511 | +UChar*source,*dest; |
| 1512 | +intbuflen; |
| 1513 | +size_tresult_size,usize; |
| 1514 | +UErrorCodestatus=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 | +returnresult; |
| 1580 | +} |
| 1581 | +#else |
1494 | 1582 | #ifdefUSE_WIDE_UPPER_LOWER
|
1495 | 1583 | elseif (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 | #ifdefHAVE_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 | +#ifdefUSE_ICU |
| 1704 | +/* use ICU only when max encoding length > one */ |
| 1705 | +if (pg_database_encoding_max_length()>1) |
| 1706 | +{ |
| 1707 | +UCharsourcebuf[STACKBUFLEN],destbuf[STACKBUFLEN]; |
| 1708 | +UChar*source,*dest; |
| 1709 | +intbuflen; |
| 1710 | +size_tresult_size,usize; |
| 1711 | +UErrorCodestatus=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 | +returnresult; |
| 1777 | +} |
| 1778 | +#else |
1614 | 1779 | #ifdefUSE_WIDE_UPPER_LOWER
|
1615 | 1780 | elseif (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 | #ifdefHAVE_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 | +#ifdefUSE_ICU |
| 1902 | +/* use ICU only when max encoding length > one */ |
| 1903 | +if (pg_database_encoding_max_length()>1) |
| 1904 | +{ |
| 1905 | +UCharsourcebuf[STACKBUFLEN],destbuf[STACKBUFLEN]; |
| 1906 | +UChar*source,*dest; |
| 1907 | +intbuflen; |
| 1908 | +size_tresult_size,usize; |
| 1909 | +UErrorCodestatus=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 | +returnresult; |
| 1975 | +} |
| 1976 | +#else |
1735 | 1977 | #ifdefUSE_WIDE_UPPER_LOWER
|
1736 | 1978 | elseif (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 | #ifdefHAVE_LOCALE_T
|
|