[Replace __builtin_types_compatible_p with _Generic]
Here is an updated and expanded patch set.
The first patch replaces __builtin_types_compatible_p with _Generic. It
is similar to the previous patches in this thread. I added some more
code comments about what is supposed to work and how.
I did not include any C++ support here. I feel this ought to be done as
a separate patch. This patch already carries portability risk and will
require some buildfarm animal changes, so it seems better not to overlay
any C++ issues.
As we had discussed before, this does not work with VS 2019. We no
longer have CI coverage for VS 2019, and I raised this issue at the CI
session at the pgconf.dev unconference, and the consensus was that we
should drop VS 2019 support. So I'm including a patch for that here.
This is just a documentation patch. But we can also drop some support
for early VS 2022 versions (_MSC_VER < 1933), since it's unlikely that
those would be relevant.
And then, since we are dropping support for gcc 4.8, which means RHEL 7,
we also drop support for some old ICU and Tcl versions. I have included
patches for that there, too.
Required buildfarm updates:
VS 2019:
-
https://buildfarm.postgresql.org/cgi-bin/show_history.pl?nm=drongo&br=master
RHEL 7:
-
https://buildfarm.postgresql.org/cgi-bin/show_history.pl?nm=siskin&br=master
-
https://buildfarm.postgresql.org/cgi-bin/show_history.pl?nm=rhinoceros&br=master
- https://buildfarm.postgresql.org/cgi-bin/show_history.pl?nm=buri&br=master
From fcac32277c883bf28196af64b35ac92b9b8e4c96 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email protected]>
Date: Wed, 10 Jun 2026 11:47:35 +0200
Subject: [PATCH v4 1/5] Replace __builtin_types_compatible_p with _Generic
_Generic is the C11 standard equivalent (and superset) of
__builtin_types_compatible_p, so by replacing the latter with the
former, we can now rely on this working on all compilers, instead of
previously just with GCC-compatible ones. And we can drop a configure
test.
This affects StaticAssertVariableIsOfType() and
StaticAssertVariableIsOfTypeMacro() and indirectly unconstify() and
unvolatize().
Neither _Generic nor __builtin_types_compatible_p works in C++, so
this does not change that, but this adds an explicit code comment
about that.
There are some subtle behavior changes, but these do not affect cases
that are in use or likely to be useful. _Generic does lvalue
conversion on the controlling expression, which means it drops
top-level qualifiers and converts arrays to pointers.
__builtin_types_compatible_p on the other hand, supports arrays and
just ignores qualifiers. So before, StaticAssertVariableIsOfType(x,
const int) might have worked, but now it does not. (But note that it
would previously have succeeded even if x was a non-const int, so this
usage would always have been dubious.) Also,
StaticAssertVariableIsOfType(y, char[]) would have worked, but now you
need to write char *. (But this is not backward compatible, because
char * would previously not have succeeded.) Similarly, unconstify of
non-pointers, like unconstify(const int, x) would previously have
worked, but this was just by accident and never useful (you can just
assign directly, without a cast), and the C++ implementation rejects
non-pointers anyway. Some comments are added to explain this a bit.
There are no current uses affected by this.
Note that even though we have required C11 since f5e0186f865, we have
not made use of _Generic until now (except in an MSVC-specific case in
commit 59c2f03d1ec). This now raises the effective compiler
requirement on the trailing edge slightly from GCC 4.8 to GCC 4.9.
This in turn means that we effectively drop support for RHEL 7.
Discussion:
https://www.postgresql.org/message-id/flat/ca+hukgl7trhwij4qxpksbztmmtwdypnp1qn+lq341v7ql77...@mail.gmail.com
---
config/c-compiler.m4 | 19 -------------------
configure | 30 ------------------------------
configure.ac | 1 -
meson.build | 15 ---------------
src/include/c.h | 32 ++++++++++++++++----------------
src/include/pg_config.h.in | 3 ---
6 files changed, 16 insertions(+), 84 deletions(-)
diff --git a/config/c-compiler.m4 b/config/c-compiler.m4
index 3eab0da9cb6..f05b744667c 100644
--- a/config/c-compiler.m4
+++ b/config/c-compiler.m4
@@ -267,25 +267,6 @@ fi])# PGAC_CXX_TYPEOF_UNQUAL
-# PGAC_C_TYPES_COMPATIBLE
-# -----------------------
-# Check if the C compiler understands __builtin_types_compatible_p,
-# and define HAVE__BUILTIN_TYPES_COMPATIBLE_P if so.
-#
-# We check usage with __typeof__, though it's unlikely any compiler would
-# have the former and not the latter.
-AC_DEFUN([PGAC_C_TYPES_COMPATIBLE],
-[AC_CACHE_CHECK(for __builtin_types_compatible_p, pgac_cv__types_compatible,
-[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],
-[[ int x; static int y[__builtin_types_compatible_p(__typeof__(x), int)]; ]])],
-[pgac_cv__types_compatible=yes],
-[pgac_cv__types_compatible=no])])
-if test x"$pgac_cv__types_compatible" = xyes ; then
-AC_DEFINE(HAVE__BUILTIN_TYPES_COMPATIBLE_P, 1,
- [Define to 1 if your compiler understands
__builtin_types_compatible_p.])
-fi])# PGAC_C_TYPES_COMPATIBLE
-
-
# PGAC_C_BUILTIN_CONSTANT_P
# -------------------------
# Check if the C compiler understands __builtin_constant_p(),
diff --git a/configure b/configure
index 5f77f3cac29..abb53707581 100755
--- a/configure
+++ b/configure
@@ -15181,36 +15181,6 @@ cat >>confdefs.h <<_ACEOF
_ACEOF
fi
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for
__builtin_types_compatible_p" >&5
-$as_echo_n "checking for __builtin_types_compatible_p... " >&6; }
-if ${pgac_cv__types_compatible+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main ()
-{
- int x; static int y[__builtin_types_compatible_p(__typeof__(x), int)];
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- pgac_cv__types_compatible=yes
-else
- pgac_cv__types_compatible=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv__types_compatible"
>&5
-$as_echo "$pgac_cv__types_compatible" >&6; }
-if test x"$pgac_cv__types_compatible" = xyes ; then
-
-$as_echo "#define HAVE__BUILTIN_TYPES_COMPATIBLE_P 1" >>confdefs.h
-
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __builtin_constant_p" >&5
$as_echo_n "checking for __builtin_constant_p... " >&6; }
diff --git a/configure.ac b/configure.ac
index 61cee42daa7..a9db28c22c1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1727,7 +1727,6 @@ PGAC_C_TYPEOF
PGAC_CXX_TYPEOF
PGAC_C_TYPEOF_UNQUAL
PGAC_CXX_TYPEOF_UNQUAL
-PGAC_C_TYPES_COMPATIBLE
PGAC_C_BUILTIN_CONSTANT_P
PGAC_C_BUILTIN_OP_OVERFLOW
PGAC_C_BUILTIN_UNREACHABLE
diff --git a/meson.build b/meson.build
index 568e0e150bf..364809a394c 100644
--- a/meson.build
+++ b/meson.build
@@ -2062,21 +2062,6 @@ foreach builtin : builtins
endforeach
-# Check if the C compiler understands __builtin_types_compatible_p,
-# and define HAVE__BUILTIN_TYPES_COMPATIBLE_P if so.
-#
-# We check usage with __typeof__, though it's unlikely any compiler would
-# have the former and not the latter.
-if cc.compiles('''
- static int x;
- static int y[__builtin_types_compatible_p(__typeof__(x), int)];
- ''',
- name: '__builtin_types_compatible_p',
- args: test_c_args)
- cdata.set('HAVE__BUILTIN_TYPES_COMPATIBLE_P', 1)
-endif
-
-
# Check if the C compiler understands __builtin_$op_overflow(),
# and define HAVE__BUILTIN_OP_OVERFLOW if so.
#
diff --git a/src/include/c.h b/src/include/c.h
index f32989a6331..dd90156eb3f 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -1049,29 +1049,24 @@ pg_noreturn extern void ExceptionalCondition(const char
*conditionName,
/*
* Compile-time checks that a variable (or expression) has the specified type.
*
+ * The type must not have top-level qualifiers (const, volatile) and must not
+ * be an array (use pointer instead). (This wouldn't work because _Generic
+ * does lvalue conversion on the controlling expression, which drops
+ * qualifiers and converts arrays to pointers.) Qualifiers inside pointers
+ * are allowed.
+ *
* StaticAssertVariableIsOfType() can be used as a declaration.
* StaticAssertVariableIsOfTypeMacro() is intended for use in macros, eg
* #define foo(x) (StaticAssertVariableIsOfTypeMacro(x, int),
bar(x))
*
- * If we don't have __builtin_types_compatible_p, we can still assert that
- * the types have the same size. This is far from ideal (especially on 32-bit
- * platforms) but it provides at least some coverage.
+ * Note that these do not work in C++.
*/
-#ifdef HAVE__BUILTIN_TYPES_COMPATIBLE_P
-#define StaticAssertVariableIsOfType(varname, typename) \
- StaticAssertDecl(__builtin_types_compatible_p(typeof(varname),
typename), \
- CppAsString(varname) " does not have type " CppAsString(typename))
-#define StaticAssertVariableIsOfTypeMacro(varname, typename) \
- (StaticAssertExpr(__builtin_types_compatible_p(typeof(varname),
typename), \
- CppAsString(varname) " does not have type " CppAsString(typename)))
-#else /*
!HAVE__BUILTIN_TYPES_COMPATIBLE_P */
#define StaticAssertVariableIsOfType(varname, typename) \
- StaticAssertDecl(sizeof(varname) == sizeof(typename), \
+ StaticAssertDecl(_Generic((varname), typename: 1, default: 0), \
CppAsString(varname) " does not have type " CppAsString(typename))
#define StaticAssertVariableIsOfTypeMacro(varname, typename) \
- (StaticAssertExpr(sizeof(varname) == sizeof(typename), \
+ (StaticAssertExpr(_Generic((varname), typename: 1, default: 0), \
CppAsString(varname) " does not have type " CppAsString(typename)))
-#endif /*
HAVE__BUILTIN_TYPES_COMPATIBLE_P */
/* ----------------------------------------------------------------
@@ -1308,8 +1303,13 @@ typedef struct PGAlignedXLogBlock PGAlignedXLogBlock;
/*
* Macro that allows to cast constness and volatile away from an expression,
but doesn't
- * allow changing the underlying type. Enforcement of the latter
- * currently only works for gcc like compilers.
+ * allow changing the underlying type.
+ *
+ * This is only meant to work for qualifiers behind at least one level of
+ * pointer. (In the C implementation, the StaticAssertVariableIsOfTypeMacro
+ * will drop top-level qualifiers, so with a non-pointer, the static assertion
+ * will fail. In the C++ implementation, const_cast will error for
+ * non-pointers.)
*
* Please note IT IS NOT SAFE to cast constness away if the result will ever
* be modified (it would be undefined behaviour). Doing so anyway can cause
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 4f8113c144b..661c4a9b168 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -544,9 +544,6 @@
/* Define to 1 if your compiler understands __builtin_$op_overflow. */
#undef HAVE__BUILTIN_OP_OVERFLOW
-/* Define to 1 if your compiler understands __builtin_types_compatible_p. */
-#undef HAVE__BUILTIN_TYPES_COMPATIBLE_P
-
/* Define to 1 if your compiler understands __builtin_unreachable. */
#undef HAVE__BUILTIN_UNREACHABLE
base-commit: e18b0cb7344cb4bd28468f6c0aeeb9b9241d30aa
--
2.54.0
From 4f31309f74dc0737d129326109ef545f2cdd8e86 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email protected]>
Date: Wed, 10 Jun 2026 11:47:35 +0200
Subject: [PATCH v4 2/5] Raise requirement to Visual Studio 2022
The use of _Generic from commit "Replace __builtin_types_compatible_p
with _Generic" causes compiler errors from VS 2019. Apparently, that
compiler is just broken for that (even though it appears to support
_Generic in general, for example in commit 59c2f03d1ec).
Per discussion, just drop support for VS 2019 and require at least VS
2022. This just updates the documentation about that. In passing,
some information about VS 2026 is added.
Discussion:
https://www.postgresql.org/message-id/flat/ca+hukgl7trhwij4qxpksbztmmtwdypnp1qn+lq341v7ql77...@mail.gmail.com
---
doc/src/sgml/installation.sgml | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/doc/src/sgml/installation.sgml b/doc/src/sgml/installation.sgml
index b345a105674..37a0473d03e 100644
--- a/doc/src/sgml/installation.sgml
+++ b/doc/src/sgml/installation.sgml
@@ -3841,17 +3841,16 @@ <title>Visual Studio</title>
<para>
Both 32-bit and 64-bit builds are possible with the Microsoft Compiler
suite.
32-bit PostgreSQL builds are possible with
- <productname>Visual Studio 2019</productname> to
<productname>Visual Studio 2022</productname>,
as well as standalone Windows SDK releases 10 and above.
64-bit PostgreSQL builds are supported with
<productname>Microsoft Windows SDK</productname> version 10 and above or
- <productname>Visual Studio 2019</productname> and above.
+ <productname>Visual Studio 2022</productname> and above.
<!--
- For 2019 requirements:
-
https://docs.microsoft.com/en-us/visualstudio/releases/2019/system-requirements
For 2022 requirements:
-
https://docs.microsoft.com/en-us/visualstudio/releases/2022/system-requirements
+
https://learn.microsoft.com/en-us/visualstudio/releases/2022/system-requirements
+ For 2026 requirements:
+
https://learn.microsoft.com/en-us/visualstudio/releases/2026/vs-system-requirements
-->
</para>
--
2.54.0
From 63261115e4ec6a9a201aa36f5a541311c8ee1c3b Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email protected]>
Date: Wed, 10 Jun 2026 11:47:35 +0200
Subject: [PATCH v4 3/5] Drop support for _MSC_VER less than 1933
Commit aa7c8685234 added a workaround for _MSC_VER less than 1933,
which is Visual Studio 2022 version 17.3. Since we dropped support
for Visual Studio before 2022, and the versions up to 17.3 are long
EOL, we can drop this extra code.
Discussion:
https://www.postgresql.org/message-id/flat/ca+hukgl7trhwij4qxpksbztmmtwdypnp1qn+lq341v7ql77...@mail.gmail.com
---
src/include/c.h | 14 --------------
1 file changed, 14 deletions(-)
diff --git a/src/include/c.h b/src/include/c.h
index dd90156eb3f..80748718a86 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -1022,24 +1022,10 @@ pg_noreturn extern void ExceptionalCondition(const char
*conditionName,
* rationale for the precise behavior of this implementation. See
* <https://stackoverflow.com/questions/31311748> about the C++
* implementation.
- *
- * For compilers that don't support this, we fall back on a kluge that assumes
- * the compiler will complain about a negative width for a struct bit-field.
- * This will not include a helpful error message, but it beats not getting an
- * error at all.
*/
#ifndef __cplusplus
-#if !defined(_MSC_VER) || _MSC_VER >= 1933
#define StaticAssertExpr(condition, errmessage) \
((void) sizeof(struct {static_assert(condition, errmessage); char a;}))
-#else /* _MSC_VER < 1933 */
-/*
- * This compiler is buggy and fails to compile the previous variant; use a
- * fallback implementation.
- */
-#define StaticAssertExpr(condition, errmessage) \
- ((void) sizeof(struct { int static_assert_failure : (condition) ? 1 :
-1; }))
-#endif /* _MSC_VER < 1933 */
#else /* __cplusplus */
#define StaticAssertExpr(condition, errmessage) \
([]{static_assert(condition, errmessage);})
--
2.54.0
From accdeb8d2ceb8c17dd6e04a8b5a65e07137eb039 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email protected]>
Date: Wed, 10 Jun 2026 11:47:36 +0200
Subject: [PATCH v4 4/5] Make PL/Tcl require Tcl 8.6 or later
Support for Tcl 8.5 and 8.4 is removed. Since we no longer support
RHEL 7, we don't need to support these old versions anymore. This
allows some small amount of code cleanup.
Discussion:
https://www.postgresql.org/message-id/flat/ca+hukgl7trhwij4qxpksbztmmtwdypnp1qn+lq341v7ql77...@mail.gmail.com
---
config/tcl.m4 | 2 +-
configure | 2 +-
doc/src/sgml/installation.sgml | 5 ++---
src/pl/tcl/pltcl.c | 15 +++++----------
4 files changed, 9 insertions(+), 15 deletions(-)
diff --git a/config/tcl.m4 b/config/tcl.m4
index 9de31a57156..d226ef99d05 100644
--- a/config/tcl.m4
+++ b/config/tcl.m4
@@ -4,7 +4,7 @@
AC_DEFUN([PGAC_PATH_TCLSH],
-[PGAC_PATH_PROGS(TCLSH, [tclsh tcl tclsh8.6 tclsh86 tclsh8.5 tclsh85 tclsh8.4
tclsh84])
+[PGAC_PATH_PROGS(TCLSH, [tclsh tcl tclsh8.6 tclsh86])
AC_ARG_VAR(TCLSH, [Tcl interpreter program (tclsh)])dnl
if test x"$TCLSH" = x""; then
AC_MSG_ERROR([Tcl shell not found])
diff --git a/configure b/configure
index abb53707581..0c8c5f46c99 100755
--- a/configure
+++ b/configure
@@ -19003,7 +19003,7 @@ fi
# Check for Tcl configuration script tclConfig.sh
if test "$with_tcl" = yes; then
if test -z "$TCLSH"; then
- for ac_prog in tclsh tcl tclsh8.6 tclsh86 tclsh8.5 tclsh85 tclsh8.4 tclsh84
+ for ac_prog in tclsh tcl tclsh8.6 tclsh86
do
# Extract the first word of "$ac_prog", so it can be a program name with
args.
set dummy $ac_prog; ac_word=$2
diff --git a/doc/src/sgml/installation.sgml b/doc/src/sgml/installation.sgml
index 37a0473d03e..8b98938d2a1 100644
--- a/doc/src/sgml/installation.sgml
+++ b/doc/src/sgml/installation.sgml
@@ -265,7 +265,7 @@ <title>Requirements</title>
To build the <application>PL/Tcl</application>
procedural language, you of course need a <productname>Tcl</productname>
installation. The minimum required version is
- <productname>Tcl</productname> 8.4.
+ <productname>Tcl</productname> 8.6.
</para>
</listitem>
@@ -1936,8 +1936,7 @@ <title><filename>configure</filename> Environment
Variables</title>
Tcl interpreter program. This will be used to
determine the dependencies for building PL/Tcl.
If this is not set, the following are probed in this
- order: <literal>tclsh tcl tclsh8.6 tclsh86 tclsh8.5 tclsh85
- tclsh8.4 tclsh84</literal>.
+ order: <literal>tclsh tcl tclsh8.6 tclsh86</literal>.
</para>
</listitem>
</varlistentry>
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index 85e83bbf1e3..c8a9363aaa1 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -50,14 +50,9 @@ PG_MODULE_MAGIC_EXT(
((TCL_MAJOR_VERSION > maj) || \
(TCL_MAJOR_VERSION == maj && TCL_MINOR_VERSION >= min))
-/* Insist on Tcl >= 8.4 */
-#if !HAVE_TCL_VERSION(8,4)
-#error PostgreSQL only supports Tcl 8.4 or later.
-#endif
-
-/* Hack to deal with Tcl 8.6 const-ification without losing compatibility */
-#ifndef CONST86
-#define CONST86
+/* Insist on Tcl >= 8.6 */
+#if !HAVE_TCL_VERSION(8,6)
+#error PostgreSQL only supports Tcl 8.6 or later.
#endif
#if !HAVE_TCL_VERSION(8,7)
@@ -366,7 +361,7 @@ pltcl_FinalizeNotifier(ClientData clientData)
}
static void
-pltcl_SetTimer(CONST86 Tcl_Time *timePtr)
+pltcl_SetTimer(const Tcl_Time *timePtr)
{
}
@@ -392,7 +387,7 @@ pltcl_ServiceModeHook(int mode)
}
static int
-pltcl_WaitForEvent(CONST86 Tcl_Time *timePtr)
+pltcl_WaitForEvent(const Tcl_Time *timePtr)
{
return 0;
}
--
2.54.0
From b65d7a25039ce14b9ac0f17bc332ccb72984d541 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email protected]>
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+lq341v7ql77...@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 @@ <title>Requirements</title>
<listitem>
<para>
- The ICU library is used by default. If you don't want to use it then you
must specify the <option>--without-icu</option> option to
<filename>configure</filename>. Using this option disables support for ICU
collation features (see <xref linkend="collation"/>).
+ The ICU library is used by default. If you don't want to use it then you
+ must specify the <option>--without-icu</option> option to
+ <filename>configure</filename>. Using this option disables support for
+ ICU collation features (see <xref linkend="collation"/>).
</para>
<para>
ICU support requires the <productname>ICU4C</productname> package to be
installed. The minimum required version of
- <productname>ICU4C</productname> is currently 4.2.
+ <productname>ICU4C</productname> is currently 55.
</para>
<para>
By default,
<productname>pkg-config</productname><indexterm><primary>pkg-config</primary></indexterm>
- will be used to find the required compilation options. This is
- supported for <productname>ICU4C</productname> version 4.6 and later.
- For older versions, or if <productname>pkg-config</productname> is not
+ will be used to find the required compilation options.
+ If <productname>pkg-config</productname> is not
available, the variables <envar>ICU_CFLAGS</envar> and
<envar>ICU_LIBS</envar> can be specified to
<filename>configure</filename>, like in this example:
@@ -2435,7 +2437,7 @@ <title><productname>PostgreSQL</productname>
Features</title>
library, enabling use of ICU collation features (see <xref
linkend="collation"/>). Defaults to auto and requires the
<productname>ICU4C</productname> package to be installed. The minimum
- required version of <productname>ICU4C</productname> is currently 4.2.
+ required version of <productname>ICU4C</productname> is currently 55.
</para>
</listitem>
</varlistentry>
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 <unicode/ustring.h>
/*
- * ucol_strcollUTF8() was introduced in ICU 50, but it is buggy before ICU 53.
- * (see
- *
<https://www.postgresql.org/message-id/flat/f1438ec6-22aa-4029-9a3b-26f79d330e72%40manitou-mail.org>)
+ * 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