Wrap ICU ucol_open().
authorJeff Davis <jdavis@postgresql.org>
Thu, 23 Mar 2023 16:15:25 +0000 (09:15 -0700)
committerJeff Davis <jdavis@postgresql.org>
Thu, 23 Mar 2023 16:15:25 +0000 (09:15 -0700)
Hide details of supporting older ICU versions in a wrapper
function. The current code only needs to handle
icu_set_collation_attributes(), but a subsequent commit will add
additional version-specific code.

Discussion: https://postgr.es/m/7ee414ad-deb5-1144-8a0e-b34ae3b71cd5@enterprisedb.com
Reviewed-by: Peter Eisentraut
src/backend/utils/adt/pg_locale.c

index c3ede994be54f13774a45de4563b6135074c446a..dd0786dff52186ffcbbe23fec030def06d2613f8 100644 (file)
@@ -140,6 +140,7 @@ static char *IsoLocaleName(const char *);
  */
 static UConverter *icu_converter = NULL;
 
+static UCollator *pg_ucol_open(const char *loc_str);
 static void init_icu_converter(void);
 static size_t uchar_length(UConverter *converter,
                                                   const char *str, int32_t len);
@@ -1430,17 +1431,8 @@ make_icu_collator(const char *iculocstr,
 {
 #ifdef USE_ICU
        UCollator  *collator;
-       UErrorCode      status;
 
-       status = U_ZERO_ERROR;
-       collator = ucol_open(iculocstr, &status);
-       if (U_FAILURE(status))
-               ereport(ERROR,
-                               (errmsg("could not open collator for locale \"%s\": %s",
-                                               iculocstr, u_errorName(status))));
-
-       if (U_ICU_VERSION_MAJOR_NUM < 54)
-               icu_set_collation_attributes(collator, iculocstr);
+       collator = pg_ucol_open(iculocstr);
 
        /*
         * If rules are specified, we extract the rules of the standard collation,
@@ -1451,6 +1443,7 @@ make_icu_collator(const char *iculocstr,
                const UChar *default_rules;
                UChar      *agg_rules;
                UChar      *my_rules;
+               UErrorCode      status;
                int32_t         length;
 
                default_rules = ucol_getRules(collator, &length);
@@ -1722,16 +1715,11 @@ get_collation_actual_version(char collprovider, const char *collcollate)
        if (collprovider == COLLPROVIDER_ICU)
        {
                UCollator  *collator;
-               UErrorCode      status;
                UVersionInfo versioninfo;
                char            buf[U_MAX_VERSION_STRING_LENGTH];
 
-               status = U_ZERO_ERROR;
-               collator = ucol_open(collcollate, &status);
-               if (U_FAILURE(status))
-                       ereport(ERROR,
-                                       (errmsg("could not open collator for locale \"%s\": %s",
-                                                       collcollate, u_errorName(status))));
+               collator = pg_ucol_open(collcollate);
+
                ucol_getVersion(collator, versioninfo);
                ucol_close(collator);
 
@@ -2505,6 +2493,43 @@ pg_strnxfrm_prefix(char *dest, size_t destsize, const char *src,
 }
 
 #ifdef USE_ICU
+
+/*
+ * Wrapper around ucol_open() to handle API differences for older ICU
+ * versions.
+ */
+static UCollator *
+pg_ucol_open(const char *loc_str)
+{
+       UCollator  *collator;
+       UErrorCode      status;
+
+       /*
+        * Must never open default collator, because it depends on the environment
+        * and may change at any time.
+        *
+        * NB: the default collator is not the same as the collator for the root
+        * locale. The root locale may be specified as the empty string, "und", or
+        * "root". The default collator is opened by passing NULL to ucol_open().
+        */
+       if (loc_str == NULL)
+               ereport(ERROR,
+                               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                errmsg("opening default collator is not supported")));
+
+       status = U_ZERO_ERROR;
+       collator = ucol_open(loc_str, &status);
+       if (U_FAILURE(status))
+               ereport(ERROR,
+                               (errmsg("could not open collator for locale \"%s\": %s",
+                                               loc_str, u_errorName(status))));
+
+       if (U_ICU_VERSION_MAJOR_NUM < 54)
+               icu_set_collation_attributes(collator, loc_str);
+
+       return collator;
+}
+
 static void
 init_icu_converter(void)
 {
@@ -2771,17 +2796,8 @@ check_icu_locale(const char *icu_locale)
 {
 #ifdef USE_ICU
        UCollator  *collator;
-       UErrorCode      status;
-
-       status = U_ZERO_ERROR;
-       collator = ucol_open(icu_locale, &status);
-       if (U_FAILURE(status))
-               ereport(ERROR,
-                               (errmsg("could not open collator for locale \"%s\": %s",
-                                               icu_locale, u_errorName(status))));
 
-       if (U_ICU_VERSION_MAJOR_NUM < 54)
-               icu_set_collation_attributes(collator, icu_locale);
+       collator = pg_ucol_open(icu_locale);
        ucol_close(collator);
 #else
        ereport(ERROR,