From b65d7a25039ce14b9ac0f17bc332ccb72984d541 Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Wed, 10 Jun 2026 11:47:36 +0200 Subject: [PATCH v4 5/5] Require ICU 55 or later Support for older versions is removed. Since we no longer support RHEL 7, we don't need to support these old versions anymore. This allows a fair amount of code cleanup, including some code blocks that specifically catered to old versions that probably received very little actual testing and use. Discussion: https://www.postgresql.org/message-id/flat/CA+hUKGL7trhWiJ4qxpksBztMMTWDyPnP1QN+Lq341V7QL775DA@mail.gmail.com --- configure | 22 +++---- configure.ac | 2 +- doc/src/sgml/installation.sgml | 14 +++-- meson.build | 4 +- src/backend/utils/adt/pg_locale_icu.c | 84 +++++---------------------- 5 files changed, 35 insertions(+), 91 deletions(-) diff --git a/configure b/configure index 0c8c5f46c99..30cb7e834d2 100755 --- a/configure +++ b/configure @@ -8135,19 +8135,19 @@ $as_echo "$with_icu" >&6; } if test "$with_icu" = yes; then pkg_failed=no -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for icu-uc icu-i18n" >&5 -$as_echo_n "checking for icu-uc icu-i18n... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for icu-uc >= 55 icu-i18n" >&5 +$as_echo_n "checking for icu-uc >= 55 icu-i18n... " >&6; } if test -n "$ICU_CFLAGS"; then pkg_cv_ICU_CFLAGS="$ICU_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"icu-uc icu-i18n\""; } >&5 - ($PKG_CONFIG --exists --print-errors "icu-uc icu-i18n") 2>&5 + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"icu-uc >= 55 icu-i18n\""; } >&5 + ($PKG_CONFIG --exists --print-errors "icu-uc >= 55 icu-i18n") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then - pkg_cv_ICU_CFLAGS=`$PKG_CONFIG --cflags "icu-uc icu-i18n" 2>/dev/null` + pkg_cv_ICU_CFLAGS=`$PKG_CONFIG --cflags "icu-uc >= 55 icu-i18n" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes @@ -8159,12 +8159,12 @@ if test -n "$ICU_LIBS"; then pkg_cv_ICU_LIBS="$ICU_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"icu-uc icu-i18n\""; } >&5 - ($PKG_CONFIG --exists --print-errors "icu-uc icu-i18n") 2>&5 + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"icu-uc >= 55 icu-i18n\""; } >&5 + ($PKG_CONFIG --exists --print-errors "icu-uc >= 55 icu-i18n") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then - pkg_cv_ICU_LIBS=`$PKG_CONFIG --libs "icu-uc icu-i18n" 2>/dev/null` + pkg_cv_ICU_LIBS=`$PKG_CONFIG --libs "icu-uc >= 55 icu-i18n" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes @@ -8185,14 +8185,14 @@ else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then - ICU_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "icu-uc icu-i18n" 2>&1` + ICU_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "icu-uc >= 55 icu-i18n" 2>&1` else - ICU_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "icu-uc icu-i18n" 2>&1` + ICU_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "icu-uc >= 55 icu-i18n" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$ICU_PKG_ERRORS" >&5 - as_fn_error $? "Package requirements (icu-uc icu-i18n) were not met: + as_fn_error $? "Package requirements (icu-uc >= 55 icu-i18n) were not met: $ICU_PKG_ERRORS diff --git a/configure.ac b/configure.ac index a9db28c22c1..7aa568dc9ff 100644 --- a/configure.ac +++ b/configure.ac @@ -874,7 +874,7 @@ AC_MSG_RESULT([$with_icu]) AC_SUBST(with_icu) if test "$with_icu" = yes; then - PKG_CHECK_MODULES(ICU, icu-uc icu-i18n) + PKG_CHECK_MODULES(ICU, icu-uc >= 55 icu-i18n) fi # diff --git a/doc/src/sgml/installation.sgml b/doc/src/sgml/installation.sgml index 8b98938d2a1..ac7e5c44576 100644 --- a/doc/src/sgml/installation.sgml +++ b/doc/src/sgml/installation.sgml @@ -168,20 +168,22 @@ Requirements - The ICU library is used by default. If you don't want to use it then you must specify the option to configure. Using this option disables support for ICU collation features (see ). + The ICU library is used by default. If you don't want to use it then you + must specify the option to + configure. Using this option disables support for + ICU collation features (see ). ICU support requires the ICU4C package to be installed. The minimum required version of - ICU4C is currently 4.2. + ICU4C is currently 55. By default, pkg-configpkg-config - will be used to find the required compilation options. This is - supported for ICU4C version 4.6 and later. - For older versions, or if pkg-config is not + will be used to find the required compilation options. + If pkg-config is not available, the variables ICU_CFLAGS and ICU_LIBS can be specified to configure, like in this example: @@ -2435,7 +2437,7 @@ <productname>PostgreSQL</productname> Features library, enabling use of ICU collation features (see ). Defaults to auto and requires the ICU4C package to be installed. The minimum - required version of ICU4C is currently 4.2. + required version of ICU4C is currently 55. diff --git a/meson.build b/meson.build index 364809a394c..c5d9192f7a3 100644 --- a/meson.build +++ b/meson.build @@ -955,14 +955,14 @@ endif icuopt = get_option('icu') if not icuopt.disabled() - icu = dependency('icu-uc', required: false) + icu = dependency('icu-uc', required: false, version: '>= 55') if icu.found() icu_i18n = dependency('icu-i18n', required: true) endif # Unfortunately the dependency is named differently with cmake if not icu.found() # combine with above once meson 0.60.0 is required - icu = dependency('ICU', required: icuopt, + icu = dependency('ICU', required: icuopt, version: '>= 55', components: ['uc'], modules: ['ICU::uc'], method: 'cmake') if icu.found() icu_i18n = dependency('ICU', required: true, diff --git a/src/backend/utils/adt/pg_locale_icu.c b/src/backend/utils/adt/pg_locale_icu.c index cb92ac6ee59..e8b453cd7eb 100644 --- a/src/backend/utils/adt/pg_locale_icu.c +++ b/src/backend/utils/adt/pg_locale_icu.c @@ -18,16 +18,14 @@ #include /* - * ucol_strcollUTF8() was introduced in ICU 50, but it is buggy before ICU 53. - * (see - * ) + * We require ICU 55 to be able to use the "und" spelling of the root locale. + * (Prior versions do not recognize this locale, and moreover fall back to the + * environment for unrecognized locale names, which could cause confusion and + * corruption.) */ -#if U_ICU_VERSION_MAJOR_NUM >= 53 -#define HAVE_UCOL_STRCOLLUTF8 1 -#else -#undef HAVE_UCOL_STRCOLLUTF8 +#if U_ICU_VERSION_MAJOR_NUM < 55 +#error ICU version 55 or later is required #endif - #endif #include "access/htup_details.h" @@ -105,14 +103,12 @@ static size_t strnxfrm_prefix_icu(char *dest, size_t destsize, pg_locale_t locale); static size_t strxfrm_prefix_icu(char *dest, size_t destsize, const char *src, pg_locale_t locale); -#ifdef HAVE_UCOL_STRCOLLUTF8 static int strncoll_icu_utf8(const char *arg1, size_t len1, const char *arg2, size_t len2, pg_locale_t locale); static int strcoll_icu_utf8(const char *arg1, const char *arg2, pg_locale_t locale); -#endif static size_t strnxfrm_prefix_icu_utf8(char *dest, size_t destsize, const char *src, size_t srclen, pg_locale_t locale); @@ -171,13 +167,8 @@ static const struct collate_methods collate_methods_icu = { }; static const struct collate_methods collate_methods_icu_utf8 = { -#ifdef HAVE_UCOL_STRCOLLUTF8 .strncoll = strncoll_icu_utf8, .strcoll = strcoll_icu_utf8, -#else - .strncoll = strncoll_icu, - .strcoll = strcoll_icu, -#endif .strnxfrm = strnxfrm_icu, .strxfrm = strxfrm_icu, .strnxfrm_prefix = strnxfrm_prefix_icu_utf8, @@ -316,7 +307,7 @@ make_libc_ctype_locale(const char *ctype) return loc; } -#endif +#endif /* USE_ICU */ pg_locale_t create_pg_locale_icu(Oid collid, MemoryContext context) @@ -408,24 +399,20 @@ create_pg_locale_icu(Oid collid, MemoryContext context) } return result; -#else +#else /* not USE_ICU */ /* could get here if a collation was created by a build with ICU */ ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("ICU is not supported in this build"))); return NULL; -#endif +#endif /* not USE_ICU */ } #ifdef USE_ICU /* * Check locale string and fix it if necessary. Returns a new palloc'd string. - * - * In ICU versions 54 and earlier, "und" is not a recognized spelling of the - * root locale. If the first component of the locale is "und", replace with - * "root" before opening. */ static char * fix_icu_locale_str(const char *loc_str) @@ -442,32 +429,10 @@ fix_icu_locale_str(const char *loc_str) if (loc_str == NULL) elog(ERROR, "opening default collator is not supported"); - if (U_ICU_VERSION_MAJOR_NUM < 55) - { - char lang[ULOC_LANG_CAPACITY]; - UErrorCode status = U_ZERO_ERROR; - - uloc_getLanguage(loc_str, lang, ULOC_LANG_CAPACITY, &status); - if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING) - { - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("could not get language from locale \"%s\": %s", - loc_str, u_errorName(status)))); - } - - if (strcmp(lang, "und") == 0) - { - const char *remainder = loc_str + strlen("und"); - char *fixed_str; - - fixed_str = palloc(strlen("root") + strlen(remainder) + 1); - strcpy(fixed_str, "root"); - strcat(fixed_str, remainder); - - return fixed_str; - } - } + /* + * XXX There are currently no fixups required, but they could be added + * here. + */ return pstrdup(loc_str); } @@ -496,25 +461,6 @@ pg_ucol_open(const char *loc_str) errmsg("could not open collator for locale \"%s\": %s", loc_str, u_errorName(status)))); - if (U_ICU_VERSION_MAJOR_NUM < 54) - { - status = U_ZERO_ERROR; - icu_set_collation_attributes(collator, fixed_str, &status); - - /* - * Pretend the error came from ucol_open(), for consistent error - * message across ICU versions. - */ - if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING) - { - ucol_close(collator); - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("could not open collator for locale \"%s\": %s", - loc_str, u_errorName(status)))); - } - } - pfree(fixed_str); return collator; @@ -741,7 +687,6 @@ downcase_ident_icu(char *dst, size_t dstsize, const char *src, * Call ucol_strcollUTF8() or ucol_strcoll() as appropriate for the given * database encoding. */ -#ifdef HAVE_UCOL_STRCOLLUTF8 int strncoll_icu_utf8(const char *arg1, size_t len1, const char *arg2, size_t len2, pg_locale_t locale) @@ -782,7 +727,6 @@ strcoll_icu_utf8(const char *arg1, const char *arg2, pg_locale_t locale) return result; } -#endif static size_t strnxfrm_icu_internal(char *dest, size_t destsize, const char *src, ssize_t srclen, @@ -1085,9 +1029,7 @@ strncoll_icu_internal(const char *arg1, ssize_t len1, int result; /* if encoding is UTF8, use more efficient strncoll_icu_utf8 */ -#ifdef HAVE_UCOL_STRCOLLUTF8 Assert(GetDatabaseEncoding() != PG_UTF8); -#endif init_icu_converter(); -- 2.54.0