Fix t_isspace(), etc., when datlocprovider=i and datctype=C.
authorJeff Davis <jdavis@postgresql.org>
Fri, 17 Mar 2023 18:47:35 +0000 (11:47 -0700)
committerJeff Davis <jdavis@postgresql.org>
Fri, 17 Mar 2023 19:08:46 +0000 (12:08 -0700)
Check whether the datctype is C to determine whether t_isspace() and
related functions use isspace() or iswspace().

Previously, t_isspace() checked whether the database default collation
was C; which is incorrect when the default collation uses the ICU
provider.

Discussion: https://postgr.es/m/79e4354d9eccfdb00483146a6b9f6295202e7890.camel@j-davis.com
Reviewed-by: Peter Eisentraut
Backpatch-through: 15

contrib/unaccent/expected/unaccent.out
contrib/unaccent/expected/unaccent_1.out [deleted file]
contrib/unaccent/sql/unaccent.sql
src/backend/tsearch/ts_locale.c
src/backend/tsearch/wparser_def.c
src/backend/utils/adt/pg_locale.c
src/backend/utils/init/postinit.c
src/include/utils/pg_locale.h

index cef98ee60cc87d8e7c0f8efdd9ff265b4e3e84c9..ee0ac71a1cc7cc204e2f2e0d7b04366ff1d3a861 100644 (file)
@@ -1,12 +1,3 @@
--- unaccent is broken if the default collation is provided by ICU and
--- LC_CTYPE=C
-SELECT current_setting('lc_ctype') = 'C' AND
-       (SELECT datlocprovider='i' FROM pg_database
-        WHERE datname=current_database())
-   AS skip_test \gset
-\if :skip_test
-\quit
-\endif
 CREATE EXTENSION unaccent;
 -- must have a UTF8 database
 SELECT getdatabaseencoding();
diff --git a/contrib/unaccent/expected/unaccent_1.out b/contrib/unaccent/expected/unaccent_1.out
deleted file mode 100644 (file)
index 0a4a383..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
--- unaccent is broken if the default collation is provided by ICU and
--- LC_CTYPE=C
-SELECT current_setting('lc_ctype') = 'C' AND
-       (SELECT datlocprovider='i' FROM pg_database
-        WHERE datname=current_database())
-   AS skip_test \gset
-\if :skip_test
-\quit
index 027dfb964a7294b662f6b0487149b5683953a728..3fc0c706be388d9bc7213c8c047064e0d87ff343 100644 (file)
@@ -1,14 +1,3 @@
-
--- unaccent is broken if the default collation is provided by ICU and
--- LC_CTYPE=C
-SELECT current_setting('lc_ctype') = 'C' AND
-       (SELECT datlocprovider='i' FROM pg_database
-        WHERE datname=current_database())
-   AS skip_test \gset
-\if :skip_test
-\quit
-\endif
-
 CREATE EXTENSION unaccent;
 
 -- must have a UTF8 database
index 0c031709902ef987046292c49418962059f34694..f1150d30b71d1222da9793a955b015bafccea5ee 100644 (file)
@@ -38,10 +38,9 @@ t_isdigit(const char *ptr)
 {
    int         clen = pg_mblen(ptr);
    wchar_t     character[WC_BUF_LEN];
-   Oid         collation = DEFAULT_COLLATION_OID;  /* TODO */
    pg_locale_t mylocale = 0;   /* TODO */
 
-   if (clen == 1 || lc_ctype_is_c(collation))
+   if (clen == 1 || database_ctype_is_c)
        return isdigit(TOUCHAR(ptr));
 
    char2wchar(character, WC_BUF_LEN, ptr, clen, mylocale);
@@ -54,10 +53,9 @@ t_isspace(const char *ptr)
 {
    int         clen = pg_mblen(ptr);
    wchar_t     character[WC_BUF_LEN];
-   Oid         collation = DEFAULT_COLLATION_OID;  /* TODO */
    pg_locale_t mylocale = 0;   /* TODO */
 
-   if (clen == 1 || lc_ctype_is_c(collation))
+   if (clen == 1 || database_ctype_is_c)
        return isspace(TOUCHAR(ptr));
 
    char2wchar(character, WC_BUF_LEN, ptr, clen, mylocale);
@@ -70,10 +68,9 @@ t_isalpha(const char *ptr)
 {
    int         clen = pg_mblen(ptr);
    wchar_t     character[WC_BUF_LEN];
-   Oid         collation = DEFAULT_COLLATION_OID;  /* TODO */
    pg_locale_t mylocale = 0;   /* TODO */
 
-   if (clen == 1 || lc_ctype_is_c(collation))
+   if (clen == 1 || database_ctype_is_c)
        return isalpha(TOUCHAR(ptr));
 
    char2wchar(character, WC_BUF_LEN, ptr, clen, mylocale);
@@ -86,10 +83,9 @@ t_isalnum(const char *ptr)
 {
    int         clen = pg_mblen(ptr);
    wchar_t     character[WC_BUF_LEN];
-   Oid         collation = DEFAULT_COLLATION_OID;  /* TODO */
    pg_locale_t mylocale = 0;   /* TODO */
 
-   if (clen == 1 || lc_ctype_is_c(collation))
+   if (clen == 1 || database_ctype_is_c)
        return isalnum(TOUCHAR(ptr));
 
    char2wchar(character, WC_BUF_LEN, ptr, clen, mylocale);
@@ -102,10 +98,9 @@ t_isprint(const char *ptr)
 {
    int         clen = pg_mblen(ptr);
    wchar_t     character[WC_BUF_LEN];
-   Oid         collation = DEFAULT_COLLATION_OID;  /* TODO */
    pg_locale_t mylocale = 0;   /* TODO */
 
-   if (clen == 1 || lc_ctype_is_c(collation))
+   if (clen == 1 || database_ctype_is_c)
        return isprint(TOUCHAR(ptr));
 
    char2wchar(character, WC_BUF_LEN, ptr, clen, mylocale);
@@ -273,7 +268,6 @@ char *
 lowerstr_with_len(const char *str, int len)
 {
    char       *out;
-   Oid         collation = DEFAULT_COLLATION_OID;  /* TODO */
    pg_locale_t mylocale = 0;   /* TODO */
 
    if (len == 0)
@@ -285,7 +279,7 @@ lowerstr_with_len(const char *str, int len)
     * Also, for a C locale there is no need to process as multibyte. From
     * backend/utils/adt/oracle_compat.c Teodor
     */
-   if (pg_database_encoding_max_length() > 1 && !lc_ctype_is_c(collation))
+   if (pg_database_encoding_max_length() > 1 && !database_ctype_is_c)
    {
        wchar_t    *wstr,
                   *wptr;
index cc3736454ecadfaf722fd63de298fde6b909c0f4..840a44ec007b105d6e4f78023959f62740d988aa 100644 (file)
@@ -297,11 +297,10 @@ TParserInit(char *str, int len)
     */
    if (prs->charmaxlen > 1)
    {
-       Oid         collation = DEFAULT_COLLATION_OID;  /* TODO */
        pg_locale_t mylocale = 0;   /* TODO */
 
        prs->usewide = true;
-       if (lc_ctype_is_c(collation))
+       if (database_ctype_is_c)
        {
            /*
             * char2wchar doesn't work for C-locale and sizeof(pg_wchar) could
index 1d3d4d86d39d2d9c314a62b6326b951ae7fb2855..90ec773c02473024e222f5dbbdf97d38e601d1a2 100644 (file)
@@ -107,6 +107,9 @@ char       *localized_full_days[7 + 1];
 char      *localized_abbrev_months[12 + 1];
 char      *localized_full_months[12 + 1];
 
+/* is the databases's LC_CTYPE the C locale? */
+bool       database_ctype_is_c = false;
+
 /* indicates whether locale information cache is valid */
 static bool CurrentLocaleConvValid = false;
 static bool CurrentLCTimeValid = false;
index 92bac8b63f544cf9c297c0c0ffca3ab410b24243..31d6a054260ff25c9a5c87e981b5a776ed7d222f 100644 (file)
@@ -419,6 +419,10 @@ CheckMyDatabase(const char *name, bool am_superuser, bool override_allow_connect
                           " which is not recognized by setlocale().", ctype),
                 errhint("Recreate the database with another locale or install the missing locale.")));
 
+   if (strcmp(ctype, "C") == 0 ||
+       strcmp(ctype, "POSIX") == 0)
+       database_ctype_is_c = true;
+
    if (dbform->datlocprovider == COLLPROVIDER_ICU)
    {
        char       *icurules;
index f9ce428233e3538dcf0255aeb748ff1e2229c21d..dd822a68be168b181369ab6a39748dcd4499d7a4 100644 (file)
@@ -47,6 +47,8 @@ extern PGDLLIMPORT char *localized_full_days[];
 extern PGDLLIMPORT char *localized_abbrev_months[];
 extern PGDLLIMPORT char *localized_full_months[];
 
+/* is the databases's LC_CTYPE the C locale? */
+extern PGDLLIMPORT bool    database_ctype_is_c;
 
 extern bool check_locale(int category, const char *locale, char **canonname);
 extern char *pg_perm_setlocale(int category, const char *locale);