PRI?64 vs Visual Studio (2022)

Started by Kyotaro Horiguchi10 months ago40 messages
#1Kyotaro Horiguchi
horikyota.ntt@gmail.com

Hello,

If you're already aware of this and have taken it into account, please
feel free to ignore this.

As described in the recent commit a0ed19e0a9e, many %ll? format
specifiers are being replaced with %<PRI?64>.

I hadn’t paid much attention to this before, but I happened to check
how this behaves on Windows, and it seems that with VS2022, PRId64
expands to "%lld". As a result, I suspect the gettext message catalog
won't match these messages correctly.

I haven't been able to build with -Dnls=enabled myself, but I did
check the strings embedded in a binary compiled with VS2022, and they
indeed use %lld.

Just wanted to share this in case it’s helpful.

regards.

--
Kyotaro Horiguchi
NTT Open Source Software Center

#2Peter Eisentraut
peter@eisentraut.org
In reply to: Kyotaro Horiguchi (#1)
Re: PRI?64 vs Visual Studio (2022)

On 31.03.25 08:28, Kyotaro Horiguchi wrote:

If you're already aware of this and have taken it into account, please
feel free to ignore this.

As described in the recent commit a0ed19e0a9e, many %ll? format
specifiers are being replaced with %<PRI?64>.

I hadn’t paid much attention to this before, but I happened to check
how this behaves on Windows, and it seems that with VS2022, PRId64
expands to "%lld". As a result, I suspect the gettext message catalog
won't match these messages correctly.

I think this is working correctly. Gettext has a built-in mechanism to
translate the %<PRI...> back to the appropriate %lld or %ld. See also
<https://www.gnu.org/software/gettext/manual/html_node/c_002dformat.html&gt;.

#3Thomas Munro
thomas.munro@gmail.com
In reply to: Peter Eisentraut (#2)
2 attachment(s)
Re: PRI?64 vs Visual Studio (2022)

On Wed, Apr 2, 2025 at 2:04 AM Peter Eisentraut <peter@eisentraut.org> wrote:

On 31.03.25 08:28, Kyotaro Horiguchi wrote:

I hadn’t paid much attention to this before, but I happened to check
how this behaves on Windows, and it seems that with VS2022, PRId64
expands to "%lld". As a result, I suspect the gettext message catalog
won't match these messages correctly.

I think this is working correctly. Gettext has a built-in mechanism to
translate the %<PRI...> back to the appropriate %lld or %ld. See also
<https://www.gnu.org/software/gettext/manual/html_node/c_002dformat.html&gt;.

Interesting report though. Commit 962da900 assumed that our in-tree
printf implementation still needed to understand that %I64 stuff in
case it came to us from system headers, but it looks like it
disappeared with MSVCRT:

1. I checked with CI (VS 2019). puts(PRId64) prints out "lld".
2. MinGW's inttypes.h[1]https://github.com/mingw-w64/mingw-w64/blob/master/mingw-w64-headers/crt/inttypes.h only uses "I64" et al if you build against MSVCRT.

So I think we should delete that stuff. Attached.

I worried that GNU gettext() might still know about %I64 somewhere,
but it just expands the macros to whatever inttypes.h defines[2]https://github.com/autotools-mirror/gettext/blob/637b208fbe13f1c306f19d4f31c21fec7e9986d2/gettext-runtime/intl/loadmsgcat.c#L473.
Good.

We don't even test -Dnls on the Windows CI task, so the fact that it
passes there doesn't mean much (if our tests would even pick up
<PRI*64> expansion failure, not sure). We should probably do
something about that and/or its absence from the build farm. We're
effectively counting on the EDB packaging team or end users to tell us
if we break localisation on this platform.

I was also curious to know if the nearby floating point formatting
kludge added by commit f1885386 was still needed today. CI passes
without it, and the standard is pretty clear: "The exponent always
contains at least two digits, and only as many more digits as
necessary to represent the exponent". I didn't look too closely at
the fine print, but that text was already present in C89 so I guess
MSVCRT just failed to conform on that point.

[1]: https://github.com/mingw-w64/mingw-w64/blob/master/mingw-w64-headers/crt/inttypes.h
[2]: https://github.com/autotools-mirror/gettext/blob/637b208fbe13f1c306f19d4f31c21fec7e9986d2/gettext-runtime/intl/loadmsgcat.c#L473

Attachments:

0001-Drop-support-for-MSVCRT-s-I64-format-strings.patchtext/x-patch; charset=US-ASCII; name=0001-Drop-support-for-MSVCRT-s-I64-format-strings.patchDownload
From 213d845611e5b357b6ff8af84f5365d96c32f51b Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@gmail.com>
Date: Wed, 19 Nov 2025 13:45:27 +1300
Subject: [PATCH 1/2] Drop support for MSVCRT's %I64 format strings.

MSVCRT predated C99 and invented non-standard placeholders for 64-bit
numbers, and then later used them in standard macros when C99
<inttypes.h> arrived.  Those macros just use %lld etc when building with
UCRT, so there should be no way for our interposed sprintf.c code to
receive the pre-standard kind.  Time to drop the code that parses them.

That code was in fact already dead when commit 962da900 landed, as we'd
officially disclaimed MSVCRT support a couple of weeks earlier in commit
1758d424, but patch development overlapped and the history hadn't been
investigated.
---
 src/port/snprintf.c | 44 --------------------------------------------
 1 file changed, 44 deletions(-)

diff --git a/src/port/snprintf.c b/src/port/snprintf.c
index d7f18b42d19..dded6c3f65b 100644
--- a/src/port/snprintf.c
+++ b/src/port/snprintf.c
@@ -557,28 +557,6 @@ nextch2:
 					fmtpos = accum;
 				accum = 0;
 				goto nextch2;
-#ifdef WIN32
-			case 'I':
-				/* Windows PRI*{32,64,PTR} size */
-				if (format[0] == '3' && format[1] == '2')
-					format += 2;
-				else if (format[0] == '6' && format[1] == '4')
-				{
-					format += 2;
-					longlongflag = 1;
-				}
-				else
-				{
-#if SIZEOF_VOID_P == SIZEOF_LONG
-					longflag = 1;
-#elif SIZEOF_VOID_P == SIZEOF_LONG_LONG
-					longlongflag = 1;
-#else
-#error "cannot find integer type of the same size as intptr_t"
-#endif
-				}
-				goto nextch2;
-#endif
 			case 'l':
 				if (longflag)
 					longlongflag = 1;
@@ -842,28 +820,6 @@ nextch1:
 					fmtpos = accum;
 				accum = 0;
 				goto nextch1;
-#ifdef WIN32
-			case 'I':
-				/* Windows PRI*{32,64,PTR} size */
-				if (format[0] == '3' && format[1] == '2')
-					format += 2;
-				else if (format[0] == '6' && format[1] == '4')
-				{
-					format += 2;
-					longlongflag = 1;
-				}
-				else
-				{
-#if SIZEOF_VOID_P == SIZEOF_LONG
-					longflag = 1;
-#elif SIZEOF_VOID_P == SIZEOF_LONG_LONG
-					longlongflag = 1;
-#else
-#error "cannot find integer type of the same size as intptr_t"
-#endif
-				}
-				goto nextch1;
-#endif
 			case 'l':
 				if (longflag)
 					longlongflag = 1;
-- 
2.51.2

0002-Drop-support-for-MSVCRT-s-float-formatting-quirk.patchtext/x-patch; charset=US-ASCII; name=0002-Drop-support-for-MSVCRT-s-float-formatting-quirk.patchDownload
From 368a43f169a92c9ec172f229a650f7dd6acf97a1 Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@gmail.com>
Date: Wed, 19 Nov 2025 14:25:42 +1300
Subject: [PATCH 2/2] Drop support for MSVCRT's float formatting quirk.

Commit f1885386 added code to remove an unnecessary leading zero from
the exponent in a float formatted by the system snprintf().  The C
standard doesn't allow unnecessary digits beyond two, and the tests pass
without this kludge on modern UCRT-based Windows systems.
---
 src/port/snprintf.c | 27 ---------------------------
 1 file changed, 27 deletions(-)

diff --git a/src/port/snprintf.c b/src/port/snprintf.c
index dded6c3f65b..6541182df6d 100644
--- a/src/port/snprintf.c
+++ b/src/port/snprintf.c
@@ -1205,22 +1205,6 @@ fmtfloat(double value, char type, int forcesign, int leftjust,
 		}
 		if (vallen < 0)
 			goto fail;
-
-		/*
-		 * Windows, alone among our supported platforms, likes to emit
-		 * three-digit exponent fields even when two digits would do.  Hack
-		 * such results to look like the way everyone else does it.
-		 */
-#ifdef WIN32
-		if (vallen >= 6 &&
-			convert[vallen - 5] == 'e' &&
-			convert[vallen - 3] == '0')
-		{
-			convert[vallen - 3] = convert[vallen - 2];
-			convert[vallen - 2] = convert[vallen - 1];
-			vallen--;
-		}
-#endif
 	}
 
 	padlen = compute_padlen(minlen, vallen + zeropadlen, leftjust);
@@ -1336,17 +1320,6 @@ pg_strfromd(char *str, size_t count, int precision, double value)
 				target.failed = true;
 				goto fail;
 			}
-
-#ifdef WIN32
-			if (vallen >= 6 &&
-				convert[vallen - 5] == 'e' &&
-				convert[vallen - 3] == '0')
-			{
-				convert[vallen - 3] = convert[vallen - 2];
-				convert[vallen - 2] = convert[vallen - 1];
-				vallen--;
-			}
-#endif
 		}
 	}
 
-- 
2.51.2

#4Tom Lane
tgl@sss.pgh.pa.us
In reply to: Thomas Munro (#3)
Re: PRI?64 vs Visual Studio (2022)

Thomas Munro <thomas.munro@gmail.com> writes:

We don't even test -Dnls on the Windows CI task, so the fact that it
passes there doesn't mean much (if our tests would even pick up
<PRI*64> expansion failure, not sure). We should probably do
something about that and/or its absence from the build farm. We're
effectively counting on the EDB packaging team or end users to tell us
if we break localisation on this platform.

I'm pretty certain that we do not test NLS localization at all,
anywhere :-(. (There are no test cases checking enable_nls,
which would be a necessary thing to not fail on buildfarm critters
not using NLS.)

I agree that starting to rely on PRI?64 in translatable strings
is raising the bar a good deal, so maybe it's time to do something
about that.

regards, tom lane

#5Thomas Munro
thomas.munro@gmail.com
In reply to: Tom Lane (#4)
Re: PRI?64 vs Visual Studio (2022)

On Wed, Nov 19, 2025 at 3:28 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:

I agree that starting to rely on PRI?64 in translatable strings
is raising the bar a good deal, so maybe it's time to do something
about that.

Perhaps meson/configure should do a po -> mo -> gettext() check with a
canned test message? That'd also make sure your msgfmt and libintl
are compatible, something I worried about when I wrote about musl
recently.

#6Tom Lane
tgl@sss.pgh.pa.us
In reply to: Thomas Munro (#5)
Re: PRI?64 vs Visual Studio (2022)

Thomas Munro <thomas.munro@gmail.com> writes:

Perhaps meson/configure should do a po -> mo -> gettext() check with a
canned test message? That'd also make sure your msgfmt and libintl
are compatible, something I worried about when I wrote about musl
recently.

No, I don't think that's a good approach. That is testing the library
available at configure time, not the one you are actually running
with (possibly years later and on a different machine, even without
considering cross-compilation cases). I think we should do it
honestly with a regression test. It doesn't need to be very
complicated --- I think checking one message in one translation is
sufficient, so long as it includes a PRI?64 usage.

regards, tom lane

#7Peter Eisentraut
peter@eisentraut.org
In reply to: Tom Lane (#6)
1 attachment(s)
Re: PRI?64 vs Visual Studio (2022)

On 19.11.25 04:15, Tom Lane wrote:

Thomas Munro <thomas.munro@gmail.com> writes:

Perhaps meson/configure should do a po -> mo -> gettext() check with a
canned test message? That'd also make sure your msgfmt and libintl
are compatible, something I worried about when I wrote about musl
recently.

No, I don't think that's a good approach. That is testing the library
available at configure time, not the one you are actually running
with (possibly years later and on a different machine, even without
considering cross-compilation cases). I think we should do it
honestly with a regression test. It doesn't need to be very
complicated --- I think checking one message in one translation is
sufficient, so long as it includes a PRI?64 usage.

We could generate an English message catalog that translates all
messages unchanged, and run the whole test suite with that. This would
exercise the whole gettext run-time machinery.

Generating the message catalog is easy, gettext provides a tool for
that. What's a little tricky is convincing all our testing
infrastructure to *not* disable NLS-related locale settings. See
attached for a rough, incomplete demo.

Attachments:

0001-Create-English-message-catalog-for-testing.patchtext/plain; charset=UTF-8; name=0001-Create-English-message-catalog-for-testing.patchDownload
From a4d5f001880d057e8692cfad49abf4a87096a88c Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Wed, 19 Nov 2025 10:13:28 +0100
Subject: [PATCH] Create English message catalog for testing

---
 src/Makefile.global.in        |  2 +-
 src/nls-global.mk             | 11 ++++++++++-
 src/test/regress/pg_regress.c |  3 ++-
 3 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/src/Makefile.global.in b/src/Makefile.global.in
index 0aa389bc710..63b25cd8db6 100644
--- a/src/Makefile.global.in
+++ b/src/Makefile.global.in
@@ -439,7 +439,7 @@ ifeq ($(MAKELEVEL),0)
 	$(MAKE) -C '$(top_builddir)' DESTDIR='$(abs_top_builddir)'/tmp_install install >'$(abs_top_builddir)'/tmp_install/log/install.log 2>&1
 	$(MAKE) -j1 $(if $(CHECKPREP_TOP),-C $(CHECKPREP_TOP),) checkprep >>'$(abs_top_builddir)'/tmp_install/log/install.log 2>&1
 
-	$(with_temp_install) initdb --auth trust --no-sync --no-instructions --lc-messages=C --no-clean '$(abs_top_builddir)'/tmp_install/initdb-template >>'$(abs_top_builddir)'/tmp_install/log/initdb-template.log 2>&1
+	$(with_temp_install) initdb --auth trust --no-sync --no-instructions --lc-messages=en_US.UTF-8 --no-clean '$(abs_top_builddir)'/tmp_install/initdb-template >>'$(abs_top_builddir)'/tmp_install/log/initdb-template.log 2>&1
 endif
 endif
 endif
diff --git a/src/nls-global.mk b/src/nls-global.mk
index 73a6db10a1d..481a50af701 100644
--- a/src/nls-global.mk
+++ b/src/nls-global.mk
@@ -34,7 +34,7 @@ AVAIL_LANGUAGES := $(shell cat $(srcdir)/po/LINGUAS)
 # If user specified the languages he wants in --enable-nls=LANGUAGES,
 # filter out the rest.  Else use all available ones.
 ifdef WANTED_LANGUAGES
-LANGUAGES = $(filter $(WANTED_LANGUAGES), $(AVAIL_LANGUAGES))
+LANGUAGES = $(filter $(WANTED_LANGUAGES), $(AVAIL_LANGUAGES) en)
 else
 LANGUAGES = $(AVAIL_LANGUAGES)
 endif
@@ -51,6 +51,11 @@ ifdef MSGMERGE
 MSGMERGE += --no-wrap --previous --sort-by-file
 endif
 
+MSGEN = msgen
+ifdef MSGEN
+MSGEN += --no-wrap --sort-by-file
+endif
+
 # _ is defined in c.h, so it's global
 GETTEXT_TRIGGERS += _
 GETTEXT_FLAGS    += _:1:pass-c-format
@@ -90,6 +95,10 @@ FRONTEND_COMMON_GETTEXT_FLAGS = \
 
 all-po: $(MO_FILES)
 
+po/en.po: po/$(CATALOG_NAME).pot
+	$(MSGEN) --lang=en -o $@.tmp $<
+	sed -e '/Plural-Forms:/s/INTEGER/2/' -e '/Plural-Forms:/s/EXPRESSION/(n != 1)/' $@.tmp > $@
+
 %.mo: %.po
 	$(MSGFMT) $(MSGFMT_FLAGS) -o $@ $<
 
diff --git a/src/test/regress/pg_regress.c b/src/test/regress/pg_regress.c
index efc41fca2ba..0d32bc44335 100644
--- a/src/test/regress/pg_regress.c
+++ b/src/test/regress/pg_regress.c
@@ -768,8 +768,9 @@ initialize_environment(void)
 	 * is actually called.)
 	 */
 	unsetenv("LANGUAGE");
+	setenv("LANGUAGE", "en", 1);
 	unsetenv("LC_ALL");
-	setenv("LC_MESSAGES", "C", 1);
+	setenv("LC_MESSAGES", "en_US.UTF-8", 1);
 
 	/*
 	 * Set encoding as requested
-- 
2.51.0

#8Peter Eisentraut
peter@eisentraut.org
In reply to: Thomas Munro (#3)
Re: PRI?64 vs Visual Studio (2022)

On 19.11.25 03:13, Thomas Munro wrote:

Interesting report though. Commit 962da900 assumed that our in-tree
printf implementation still needed to understand that %I64 stuff in
case it came to us from system headers, but it looks like it
disappeared with MSVCRT:

1. I checked with CI (VS 2019). puts(PRId64) prints out "lld".
2. MinGW's inttypes.h[1] only uses "I64" et al if you build against MSVCRT.

So I think we should delete that stuff. Attached.

Looks good to me.

#9Tom Lane
tgl@sss.pgh.pa.us
In reply to: Peter Eisentraut (#7)
Re: PRI?64 vs Visual Studio (2022)

Peter Eisentraut <peter@eisentraut.org> writes:

On 19.11.25 04:15, Tom Lane wrote:

I think we should do it
honestly with a regression test. It doesn't need to be very
complicated --- I think checking one message in one translation is
sufficient, so long as it includes a PRI?64 usage.

We could generate an English message catalog that translates all
messages unchanged, and run the whole test suite with that. This would
exercise the whole gettext run-time machinery.

... except that if it were actually doing nothing whatsoever, you
could not tell. This seems particularly troublesome for gettext,
since its fallback behavior is exactly to return the given string.
I'd prefer a test that fails in a visible way.

regards, tom lane

#10Álvaro Herrera
alvherre@kurilemu.de
In reply to: Tom Lane (#9)
Re: PRI?64 vs Visual Studio (2022)

On 2025-Nov-19, Tom Lane wrote:

Peter Eisentraut <peter@eisentraut.org> writes:

On 19.11.25 04:15, Tom Lane wrote:

I think we should do it
honestly with a regression test. It doesn't need to be very
complicated --- I think checking one message in one translation is
sufficient, so long as it includes a PRI?64 usage.

We could generate an English message catalog that translates all
messages unchanged, and run the whole test suite with that. This would
exercise the whole gettext run-time machinery.

... except that if it were actually doing nothing whatsoever, you
could not tell.

You could feed the message catalog a translated string that differs from
the original in some simple way, say, by adding a constant prefix
"[translated]" or something like that.

--
Álvaro Herrera PostgreSQL Developer — https://www.EnterpriseDB.com/

#11Jacob Champion
jacob.champion@enterprisedb.com
In reply to: Álvaro Herrera (#10)
Re: PRI?64 vs Visual Studio (2022)

On Wed, Nov 19, 2025 at 9:07 AM Álvaro Herrera <alvherre@kurilemu.de> wrote:

You could feed the message catalog a translated string that differs from
the original in some simple way, say, by adding a constant prefix
"[translated]" or something like that.

`xgettext -m` can do that. (But I wish I'd known about msgen earlier...)

We could additionally use preloadable_libintl.so, in combination with
GETTEXT_LOG_UNTRANSLATED, and check if the log contains entries from
our domains. I was doing that just last week. But beware that the log
file can grow very quickly. And we'd probably have to differentiate
the "no domain" text belonging to other software from accidental
no-domain strings in our own code, like what I described in [1]/messages/by-id/CAOYmi+kQQ8vpRcoSrA5EQ98Wa3G6jFj1yRHs6mh1V7ohkTC7JA@mail.gmail.com.

--Jacob

[1]: /messages/by-id/CAOYmi+kQQ8vpRcoSrA5EQ98Wa3G6jFj1yRHs6mh1V7ohkTC7JA@mail.gmail.com

#12Thomas Munro
thomas.munro@gmail.com
In reply to: Tom Lane (#9)
Re: PRI?64 vs Visual Studio (2022)

On Thu, Nov 20, 2025 at 4:44 AM Tom Lane <tgl@sss.pgh.pa.us> wrote:

Peter Eisentraut <peter@eisentraut.org> writes:

On 19.11.25 04:15, Tom Lane wrote:

I think we should do it
honestly with a regression test. It doesn't need to be very
complicated --- I think checking one message in one translation is
sufficient, so long as it includes a PRI?64 usage.

We could generate an English message catalog that translates all
messages unchanged, and run the whole test suite with that. This would
exercise the whole gettext run-time machinery.

... except that if it were actually doing nothing whatsoever, you
could not tell. This seems particularly troublesome for gettext,
since its fallback behavior is exactly to return the given string.
I'd prefer a test that fails in a visible way.

How about a test module with a test_nls() function that just raises an
error containing "hello %" PRId64 ", ..." with all the macros we care
about, and regression test that calls it, and two alternative expected
files with "hello ...", "hola ...", matching en.po and es.po (or
choose some other second language that we think is likely to be tested
by a subset of BF animals and/or a CI task)? Then if you didn't
enable -Dnls it'd still pass with English, and if you did it'd pass
for any language. Since there are no other .po files, if you had some
third language it'd fall back to English, and the .po would have a "do
not translate" comment or even prefix in the message to avoid
confusing the translation team. That assumes that modules are allowed
to supply .po files, I didn't check, if that's not true then maybe
it'd have to be in core instead. That'd test quite a lot of moving
parts at once.

The reason I thought about a contrived message with lots of macros is
that I'd stumbled across a partial implementation[1]/messages/by-id/CA+hUKG+pp==d-3LVhdNOvOAzwQN0vP4gBSxtHkmxnmfQD3NY=w@mail.gmail.com in Alpine's
alternative non-GNU msgfmt program, which appears to have PRIu64 but
not PRIx64 and others. It also has some other way of encoding this
stuff in the .mo that musl's alternative built-in libintl
implementation can understand (it looks like they have arranged to be
able to mmap the .mo and use it directly as shared read-only memory,
while GNU's implementation has to allocate memory to translate them to
%lld etc in every process, clever but (I assume) broken if
msgfmt/libintl implementations are mixed), so I figured it'd be a good
idea to make sure that we test that all the macros actually work. I
didn't try to understand the implications of Wolfgang's reply, but I
guess that to have any chance of Alpine's libintl pickle being
straightened out, we'd ideally want a test case that someone
interested in that could use to validate the whole localisation
pipeline conclusively.

[1]: /messages/by-id/CA+hUKG+pp==d-3LVhdNOvOAzwQN0vP4gBSxtHkmxnmfQD3NY=w@mail.gmail.com

#13Thomas Munro
thomas.munro@gmail.com
In reply to: Álvaro Herrera (#10)
Re: PRI?64 vs Visual Studio (2022)

On Thu, Nov 20, 2025 at 6:07 AM Álvaro Herrera <alvherre@kurilemu.de> wrote:

You could feed the message catalog a translated string that differs from
the original in some simple way, say, by adding a constant prefix
"[translated]" or something like that.

Oh, that's probably better than my nearby en.po + es.po suggestion.
Combining the ideas, you could have just an en.po translation, but
expected files to match "hello ..." and "[translated] hello ...".
Though, hmm, I suppose that fails to fail if it didn't translate when
it should have, so maybe a TAP test or a test_nls() function that
internally checks the translation rather than using error() and
expected files...

#14Tom Lane
tgl@sss.pgh.pa.us
In reply to: Thomas Munro (#13)
Re: PRI?64 vs Visual Studio (2022)

Thomas Munro <thomas.munro@gmail.com> writes:

On Thu, Nov 20, 2025 at 6:07 AM Álvaro Herrera <alvherre@kurilemu.de> wrote:

You could feed the message catalog a translated string that differs from
the original in some simple way, say, by adding a constant prefix
"[translated]" or something like that.

Oh, that's probably better than my nearby en.po + es.po suggestion.
Combining the ideas, you could have just an en.po translation, but
expected files to match "hello ..." and "[translated] hello ...".
Though, hmm, I suppose that fails to fail if it didn't translate when
it should have,

Yeah. I think it's critical that the test be set up so that
failure-to-translate cannot look like a success.

I agree with the idea of just using a single test message that checks
all the PRI* macros we care about. I don't think we need to invent a
whole new translation for this. I'd be inclined to just get the
desired translated string pushed into one or two .po files in HEAD,
then we can start testing with those specific languages, and we're
good. Over time the translators would presumably get translations
into other .po files, and then maybe we'd want to expand the set of
tested languages, or maybe that wouldn't really buy much. (Managing
the encoding of the expected-file might be tricky if you got too
ambitious about that.)

regards, tom lane

#15Tom Lane
tgl@sss.pgh.pa.us
In reply to: Tom Lane (#14)
1 attachment(s)
Re: PRI?64 vs Visual Studio (2022)

I wrote:

I agree with the idea of just using a single test message that checks
all the PRI* macros we care about. I don't think we need to invent a
whole new translation for this. I'd be inclined to just get the
desired translated string pushed into one or two .po files in HEAD,
then we can start testing with those specific languages, and we're
good. Over time the translators would presumably get translations
into other .po files, and then maybe we'd want to expand the set of
tested languages, or maybe that wouldn't really buy much. (Managing
the encoding of the expected-file might be tricky if you got too
ambitious about that.)

Just as proof-of-concept, this is approximately what I think we
should do to begin with.

The main thing that's likely wrong here is that I just manually
shoved a new entry into src/backend/po/es.po. I suspect that
the .po-extraction machinery would fail to pick up that string
because it's in src/test/regress/regress.c. We could hack it
to do that, or we could put the test function into some backend
file. I don't have much sense of which would be cleaner.

Lesser loose ends: I didn't bother fleshing out the test message
to cover all of the likely PRI* cases, and my Spanish probably
sucks. I'm also unsure if this will work as-is on Windows;
are the LC_MESSAGES settings the same there?

regards, tom lane

Attachments:

v1-0001-Simple-test-of-NLS-translation.patchtext/x-diff; charset=us-ascii; name=v1-0001-Simple-test-of-NLS-translation.patchDownload
From 3f89fb8f0070a35e26e35eb63fe54caea647a4ec Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Wed, 19 Nov 2025 17:16:04 -0500
Subject: [PATCH v1] Simple test of NLS translation.

This is just intended to verify minimal functionality of the
NLS message-translation system, and in particular to check that
the PRI* macros work.
---
 src/backend/po/es.po                |  5 +++++
 src/test/regress/expected/nls.out   | 17 +++++++++++++++++
 src/test/regress/expected/nls_1.out | 17 +++++++++++++++++
 src/test/regress/parallel_schedule  |  2 +-
 src/test/regress/regress.c          | 18 ++++++++++++++++++
 src/test/regress/sql/nls.sql        | 16 ++++++++++++++++
 6 files changed, 74 insertions(+), 1 deletion(-)
 create mode 100644 src/test/regress/expected/nls.out
 create mode 100644 src/test/regress/expected/nls_1.out
 create mode 100644 src/test/regress/sql/nls.sql

diff --git a/src/backend/po/es.po b/src/backend/po/es.po
index e2593b52271..861aea61b68 100644
--- a/src/backend/po/es.po
+++ b/src/backend/po/es.po
@@ -31143,3 +31143,8 @@ msgstr "uso no estandar de escape en un literal de cadena"
 #, c-format
 msgid "Use the escape string syntax for escapes, e.g., E'\\r\\n'."
 msgstr "Use la sintaxis de escape para cadenas, por ej. E'\\r\\n'."
+
+#: regress.c:1041
+#, c-format
+msgid "translated PRId64 = %<PRId64>, PRId32 = %<PRId32>"
+msgstr "traducido PRId64 = %<PRId64>, PRId32 = %<PRId32>"
diff --git a/src/test/regress/expected/nls.out b/src/test/regress/expected/nls.out
new file mode 100644
index 00000000000..b97802aeee8
--- /dev/null
+++ b/src/test/regress/expected/nls.out
@@ -0,0 +1,17 @@
+-- directory paths and dlsuffix are passed to us in environment variables
+\getenv libdir PG_LIBDIR
+\getenv dlsuffix PG_DLSUFFIX
+\set regresslib :libdir '/regress' :dlsuffix
+CREATE FUNCTION test_translation()
+    RETURNS void
+    AS :'regresslib'
+    LANGUAGE C;
+SET lc_messages = 'es_ES';
+SELECT test_translation();
+NOTICE:  traducido PRId64 = 4242, PRId32 = -1234
+ test_translation 
+------------------
+ 
+(1 row)
+
+RESET lc_messages;
diff --git a/src/test/regress/expected/nls_1.out b/src/test/regress/expected/nls_1.out
new file mode 100644
index 00000000000..4b707e9dad4
--- /dev/null
+++ b/src/test/regress/expected/nls_1.out
@@ -0,0 +1,17 @@
+-- directory paths and dlsuffix are passed to us in environment variables
+\getenv libdir PG_LIBDIR
+\getenv dlsuffix PG_DLSUFFIX
+\set regresslib :libdir '/regress' :dlsuffix
+CREATE FUNCTION test_translation()
+    RETURNS void
+    AS :'regresslib'
+    LANGUAGE C;
+SET lc_messages = 'es_ES';
+SELECT test_translation();
+NOTICE:  NLS is not enabled
+ test_translation 
+------------------
+ 
+(1 row)
+
+RESET lc_messages;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index f56482fb9f1..66ce1b7d9cd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -76,7 +76,7 @@ test: brin_bloom brin_multi
 # ----------
 # Another group of parallel tests
 # ----------
-test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/regress.c b/src/test/regress/regress.c
index a2db6080876..7d939565e2e 100644
--- a/src/test/regress/regress.c
+++ b/src/test/regress/regress.c
@@ -1028,3 +1028,21 @@ test_relpath(PG_FUNCTION_ARGS)
 
 	PG_RETURN_VOID();
 }
+
+/*
+ * Simple test to verify NLS support, particularly that the PRI* macros work.
+ */
+PG_FUNCTION_INFO_V1(test_translation);
+Datum
+test_translation(PG_FUNCTION_ARGS)
+{
+#ifdef ENABLE_NLS
+	ereport(NOTICE,
+			(errmsg("translated PRId64 = %" PRId64 ", PRId32 = %" PRId32,
+					(int64) 4242, (int32) -1234)));
+#else
+	elog(NOTICE, "NLS is not enabled");
+#endif
+
+	PG_RETURN_VOID();
+}
diff --git a/src/test/regress/sql/nls.sql b/src/test/regress/sql/nls.sql
new file mode 100644
index 00000000000..53b4add86eb
--- /dev/null
+++ b/src/test/regress/sql/nls.sql
@@ -0,0 +1,16 @@
+-- directory paths and dlsuffix are passed to us in environment variables
+\getenv libdir PG_LIBDIR
+\getenv dlsuffix PG_DLSUFFIX
+
+\set regresslib :libdir '/regress' :dlsuffix
+
+CREATE FUNCTION test_translation()
+    RETURNS void
+    AS :'regresslib'
+    LANGUAGE C;
+
+SET lc_messages = 'es_ES';
+
+SELECT test_translation();
+
+RESET lc_messages;
-- 
2.43.7

#16Thomas Munro
thomas.munro@gmail.com
In reply to: Tom Lane (#15)
Re: PRI?64 vs Visual Studio (2022)

On Thu, Nov 20, 2025 at 11:23 AM Tom Lane <tgl@sss.pgh.pa.us> wrote:

I'm also unsure if this will work as-is on Windows;
are the LC_MESSAGES settings the same there?

Bilal [CC'd], have you ever looked into gettext support for Windows
CI? I think we'd need at least msgfmt.exe, libintl.{dll,lib,h}
installed on the image, though I have no clue which
distribution/package/whatever would be appropriate. I assume a script
in pg-vm-images[1]https://github.com/anarazel/pg-vm-images/tree/main/scripts would need to install that, once we pick one. Does
anyone happen to know where EDB's installer pipeline pulls gettext
from?

[1]: https://github.com/anarazel/pg-vm-images/tree/main/scripts

#17Tom Lane
tgl@sss.pgh.pa.us
In reply to: Tom Lane (#15)
1 attachment(s)
Re: PRI?64 vs Visual Studio (2022)

I wrote:

The main thing that's likely wrong here is that I just manually
shoved a new entry into src/backend/po/es.po. I suspect that
the .po-extraction machinery would fail to pick up that string
because it's in src/test/regress/regress.c. We could hack it
to do that, or we could put the test function into some backend
file. I don't have much sense of which would be cleaner.

Oh, better idea about that: let's make regress.so have its own
translation domain. This allows testing the TEXTDOMAIN mechanism
as well as the basics, and it keeps the patch pretty self-contained.

I was amused to see that "make update-po" was able to fill in
translations for all of the pre-existing ereport's in regress.c.
I guess they all had duplicates somewhere else? But I take no
credit or blame for any of those translations.

The other loose ends remain.

regards, tom lane

Attachments:

v2-0001-Simple-test-of-NLS-translation.patchtext/x-diff; charset=UTF-8; name=v2-0001-Simple-test-of-NLS-translation.patchDownload
From 4cc78e9deea5cd69d711bdf15d20d9b8e80d363f Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Wed, 19 Nov 2025 20:16:57 -0500
Subject: [PATCH v2] Simple test of NLS translation.

This is just intended to verify minimal functionality of the
NLS message-translation system, and in particular to check that
the PRI* macros work.
---
 src/test/regress/expected/nls.out   | 18 +++++++++
 src/test/regress/expected/nls_1.out | 17 +++++++++
 src/test/regress/meson.build        |  2 +
 src/test/regress/nls.mk             |  5 +++
 src/test/regress/parallel_schedule  |  2 +-
 src/test/regress/po/LINGUAS         |  1 +
 src/test/regress/po/es.po           | 59 +++++++++++++++++++++++++++++
 src/test/regress/po/meson.build     |  3 ++
 src/test/regress/regress.c          | 32 ++++++++++++++++
 src/test/regress/sql/nls.sql        | 16 ++++++++
 10 files changed, 154 insertions(+), 1 deletion(-)
 create mode 100644 src/test/regress/expected/nls.out
 create mode 100644 src/test/regress/expected/nls_1.out
 create mode 100644 src/test/regress/nls.mk
 create mode 100644 src/test/regress/po/LINGUAS
 create mode 100644 src/test/regress/po/es.po
 create mode 100644 src/test/regress/po/meson.build
 create mode 100644 src/test/regress/sql/nls.sql

diff --git a/src/test/regress/expected/nls.out b/src/test/regress/expected/nls.out
new file mode 100644
index 00000000000..d16c29741db
--- /dev/null
+++ b/src/test/regress/expected/nls.out
@@ -0,0 +1,18 @@
+-- directory paths and dlsuffix are passed to us in environment variables
+\getenv libdir PG_LIBDIR
+\getenv dlsuffix PG_DLSUFFIX
+\set regresslib :libdir '/regress' :dlsuffix
+CREATE FUNCTION test_translation()
+    RETURNS void
+    AS :'regresslib'
+    LANGUAGE C;
+SET lc_messages = 'es_ES';
+SELECT test_translation();
+NOTICE:  traducido PRId64 = 4242
+NOTICE:  traducido PRId32 = -1234
+ test_translation 
+------------------
+ 
+(1 row)
+
+RESET lc_messages;
diff --git a/src/test/regress/expected/nls_1.out b/src/test/regress/expected/nls_1.out
new file mode 100644
index 00000000000..4b707e9dad4
--- /dev/null
+++ b/src/test/regress/expected/nls_1.out
@@ -0,0 +1,17 @@
+-- directory paths and dlsuffix are passed to us in environment variables
+\getenv libdir PG_LIBDIR
+\getenv dlsuffix PG_DLSUFFIX
+\set regresslib :libdir '/regress' :dlsuffix
+CREATE FUNCTION test_translation()
+    RETURNS void
+    AS :'regresslib'
+    LANGUAGE C;
+SET lc_messages = 'es_ES';
+SELECT test_translation();
+NOTICE:  NLS is not enabled
+ test_translation 
+------------------
+ 
+(1 row)
+
+RESET lc_messages;
diff --git a/src/test/regress/meson.build b/src/test/regress/meson.build
index 1da9e9462a9..4001a81ffe5 100644
--- a/src/test/regress/meson.build
+++ b/src/test/regress/meson.build
@@ -57,3 +57,5 @@ tests += {
     'dbname': 'regression',
   },
 }
+
+subdir('po', if_found: libintl)
diff --git a/src/test/regress/nls.mk b/src/test/regress/nls.mk
new file mode 100644
index 00000000000..43227c64f09
--- /dev/null
+++ b/src/test/regress/nls.mk
@@ -0,0 +1,5 @@
+# src/test/regress/nls.mk
+CATALOG_NAME     = regress
+GETTEXT_FILES    = regress.c
+GETTEXT_TRIGGERS = $(BACKEND_COMMON_GETTEXT_TRIGGERS)
+GETTEXT_FLAGS    = $(BACKEND_COMMON_GETTEXT_FLAGS)
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index f56482fb9f1..66ce1b7d9cd 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -76,7 +76,7 @@ test: brin_bloom brin_multi
 # ----------
 # Another group of parallel tests
 # ----------
-test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
+test: create_table_like alter_generic alter_operator misc async dbsize merge misc_functions nls sysviews tsrf tid tidscan tidrangescan collate.utf8 collate.icu.utf8 incremental_sort create_role without_overlaps generated_virtual
 
 # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other
 # psql depends on create_am
diff --git a/src/test/regress/po/LINGUAS b/src/test/regress/po/LINGUAS
new file mode 100644
index 00000000000..8357fcaaed4
--- /dev/null
+++ b/src/test/regress/po/LINGUAS
@@ -0,0 +1 @@
+es
diff --git a/src/test/regress/po/es.po b/src/test/regress/po/es.po
new file mode 100644
index 00000000000..3049b73f9f9
--- /dev/null
+++ b/src/test/regress/po/es.po
@@ -0,0 +1,59 @@
+# Spanish message translation file for regress test library
+#
+# Copyright (C) 2025 PostgreSQL Global Development Group
+# This file is distributed under the same license as the regress (PostgreSQL) package.
+#
+# Tom Lane <tgl@sss.pgh.pa.us>, 2025.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: regress (PostgreSQL) 19\n"
+"Report-Msgid-Bugs-To: pgsql-bugs@lists.postgresql.org\n"
+"POT-Creation-Date: 2025-11-19 19:01-0500\n"
+"PO-Revision-Date: 2025-11-19 19:01-0500\n"
+"Last-Translator: Tom Lane <tgl@sss.pgh.pa.us>\n"
+"Language-Team: PgSQL-es-Ayuda <pgsql-es-ayuda@lists.postgresql.org>\n"
+"Language: es\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: regress.c:200
+#, c-format
+msgid "invalid input syntax for type %s: \"%s\""
+msgstr "la sintaxis de entrada no es válida para tipo %s: «%s»"
+
+#: regress.c:907
+#, c-format
+msgid "invalid source encoding name \"%s\""
+msgstr "la codificación de origen «%s» no es válida"
+
+#: regress.c:912
+#, c-format
+msgid "invalid destination encoding name \"%s\""
+msgstr "la codificación de destino «%s» no es válida"
+
+#: regress.c:957
+#, c-format
+msgid "default conversion function for encoding \"%s\" to \"%s\" does not exist"
+msgstr "no existe el procedimiento por omisión de conversión desde la codificación «%s» a «%s»"
+
+#: regress.c:964
+#, c-format
+msgid "out of memory"
+msgstr "memoria agotada"
+
+#: regress.c:965
+#, c-format
+msgid "String of %d bytes is too long for encoding conversion."
+msgstr "La cadena de %d bytes es demasiado larga para la recodificación."
+
+#: regress.c:1054
+#, c-format
+msgid "translated PRId64 = %<PRId64>"
+msgstr "traducido PRId64 = %<PRId64>"
+
+#: regress.c:1056
+#, c-format
+msgid "translated PRId32 = %<PRId32>"
+msgstr "traducido PRId32 = %<PRId32>"
diff --git a/src/test/regress/po/meson.build b/src/test/regress/po/meson.build
new file mode 100644
index 00000000000..e9bd964aa7f
--- /dev/null
+++ b/src/test/regress/po/meson.build
@@ -0,0 +1,3 @@
+# Copyright (c) 2022-2025, PostgreSQL Global Development Group
+
+nls_targets += [i18n.gettext('regress-' + pg_version_major.to_string())]
diff --git a/src/test/regress/regress.c b/src/test/regress/regress.c
index a2db6080876..4a584ca88ae 100644
--- a/src/test/regress/regress.c
+++ b/src/test/regress/regress.c
@@ -46,6 +46,10 @@
 #include "utils/rel.h"
 #include "utils/typcache.h"
 
+/* define our text domain for translations */
+#undef TEXTDOMAIN
+#define TEXTDOMAIN PG_TEXTDOMAIN("regress")
+
 #define EXPECT_TRUE(expr)	\
 	do { \
 		if (!(expr)) \
@@ -1028,3 +1032,31 @@ test_relpath(PG_FUNCTION_ARGS)
 
 	PG_RETURN_VOID();
 }
+
+/*
+ * Simple test to verify NLS support, particularly that the PRI* macros work.
+ */
+PG_FUNCTION_INFO_V1(test_translation);
+Datum
+test_translation(PG_FUNCTION_ARGS)
+{
+#ifdef ENABLE_NLS
+	/* This would be better done in _PG_init(), if this module had one */
+	static bool inited = false;
+
+	if (!inited)
+	{
+		pg_bindtextdomain(TEXTDOMAIN);
+		inited = true;
+	}
+
+	ereport(NOTICE,
+			errmsg("translated PRId64 = %" PRId64, (int64) 4242));
+	ereport(NOTICE,
+			errmsg("translated PRId32 = %" PRId32, (int32) -1234));
+#else
+	elog(NOTICE, "NLS is not enabled");
+#endif
+
+	PG_RETURN_VOID();
+}
diff --git a/src/test/regress/sql/nls.sql b/src/test/regress/sql/nls.sql
new file mode 100644
index 00000000000..53b4add86eb
--- /dev/null
+++ b/src/test/regress/sql/nls.sql
@@ -0,0 +1,16 @@
+-- directory paths and dlsuffix are passed to us in environment variables
+\getenv libdir PG_LIBDIR
+\getenv dlsuffix PG_DLSUFFIX
+
+\set regresslib :libdir '/regress' :dlsuffix
+
+CREATE FUNCTION test_translation()
+    RETURNS void
+    AS :'regresslib'
+    LANGUAGE C;
+
+SET lc_messages = 'es_ES';
+
+SELECT test_translation();
+
+RESET lc_messages;
-- 
2.43.7

#18Nazir Bilal Yavuz
byavuz81@gmail.com
In reply to: Thomas Munro (#16)
Re: PRI?64 vs Visual Studio (2022)

Hi,

On Thu, 20 Nov 2025 at 01:44, Thomas Munro <thomas.munro@gmail.com> wrote:

On Thu, Nov 20, 2025 at 11:23 AM Tom Lane <tgl@sss.pgh.pa.us> wrote:

I'm also unsure if this will work as-is on Windows;
are the LC_MESSAGES settings the same there?

Bilal [CC'd], have you ever looked into gettext support for Windows
CI? I think we'd need at least msgfmt.exe, libintl.{dll,lib,h}
installed on the image, though I have no clue which
distribution/package/whatever would be appropriate. I assume a script
in pg-vm-images[1] would need to install that, once we pick one. Does
anyone happen to know where EDB's installer pipeline pulls gettext
from?

[1] https://github.com/anarazel/pg-vm-images/tree/main/scripts

Yes, I was working on that some time ago and I was able to enable NLS
(and many other dependencies) on Windows CI image by using the
dependencies from Dave Page's winpgbuild repository [1]https://github.com/dpage/winpgbuild. I was going
to share these changes but some other things came up and this one got
delayed. I am planning to return to this again soon.

As an example, I re-generated the Windows CI image and tested it with
VS 2019 [2]https://cirrus-ci.com/task/4655787001249792 and VS 2022 [3]https://cirrus-ci.com/task/5786281818456064. There are 3 tests failed on both but they
are not related to NLS. A portion of configure output:

[07:40:23.149] External libraries
[07:40:23.149] bonjour : NO
[07:40:23.149] bsd_auth : NO
[07:40:23.149] docs : YES
[07:40:23.149] docs_pdf : NO
[07:40:23.149] gss : YES 1.22.1
[07:40:23.149] icu : YES 77.1
[07:40:23.149] ldap : YES
[07:40:23.149] libcurl : NO
[07:40:23.149] libnuma : NO
[07:40:23.149] liburing : NO
[07:40:23.149] libxml : YES 2.13.9
[07:40:23.149] libxslt : YES 1.1.43
[07:40:23.149] llvm : NO
[07:40:23.149] lz4 : YES 1.10.0
[07:40:23.149] nls : YES
[07:40:23.149] openssl : YES 3.0.18
[07:40:23.149] pam : NO
[07:40:23.149] plperl : YES 5.42.0
[07:40:23.149] plpython : YES 3.10
[07:40:23.149] pltcl : NO
[07:40:23.149] readline : NO
[07:40:23.149] selinux : NO
[07:40:23.149] systemd : NO
[07:40:23.149] uuid : YES 1.6.2
[07:40:23.149] zlib : YES 1.3.1
[07:40:23.149] zstd : YES 1.5.7

[1]: https://github.com/dpage/winpgbuild
[2]: https://cirrus-ci.com/task/4655787001249792
[3]: https://cirrus-ci.com/task/5786281818456064

--
Regards,
Nazir Bilal Yavuz
Microsoft

#19Thomas Munro
thomas.munro@gmail.com
In reply to: Thomas Munro (#3)
2 attachment(s)
Re: PRI?64 vs Visual Studio (2022)

On Wed, Nov 19, 2025 at 3:13 PM Thomas Munro <thomas.munro@gmail.com> wrote:

I was also curious to know if the nearby floating point formatting
kludge added by commit f1885386 was still needed today. CI passes
without it, and the standard is pretty clear: "The exponent always
contains at least two digits, and only as many more digits as
necessary to represent the exponent". I didn't look too closely at
the fine print, but that text was already present in C89 so I guess
MSVCRT just failed to conform on that point.

We can also drop HAVE_BUGGY_STRTOF for MinGW. This passes on CI.

That'd leave only Cygwin with HAVE BUGGY_STRTOF. Perhaps they have
fixed their implementation[1]https://github.com/cygwin/cygwin/commit/fb01286fab9b370c86323f84a46285cfbebfe4ff? Here's an experimental patch to drop
all remnants, which could be used to find out. No Windows/Cygwin
here. Hmm, what if we just commit it anyway? If their strtof() is
still broken and someone out there is running the tests and sees this
test fail, why shouldn't they take that up with libc at this stage?

[1]: https://github.com/cygwin/cygwin/commit/fb01286fab9b370c86323f84a46285cfbebfe4ff

Attachments:

0001-Drop-HAVE_BUGGY_STRTOF-for-MinGW.patchtext/x-patch; charset=US-ASCII; name=0001-Drop-HAVE_BUGGY_STRTOF-for-MinGW.patchDownload
From fb3f839947441cdcf06c7115f2c7f9ec90a3bee7 Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@gmail.com>
Date: Sun, 23 Nov 2025 12:22:46 +1300
Subject: [PATCH 1/2] Drop HAVE_BUGGY_STRTOF for MinGW.

Commit 72880ac182c8 pointed MinGW builds at our replacement strtof()
function.  This isn't necessary with UCRT.  Also remove a stray
reference to Visual Studio 2013 (another desupported way to use MSVCRT)
from meson.build.
---
 configure                     |  9 ++++-----
 configure.ac                  |  9 ++++-----
 src/include/port/win32_port.h | 14 --------------
 src/port/meson.build          | 11 ++++-------
 src/test/regress/resultmap    |  1 -
 5 files changed, 12 insertions(+), 32 deletions(-)

diff --git a/configure b/configure
index 3a0ed11fa8e..b7bc44b017e 100755
--- a/configure
+++ b/configure
@@ -16192,11 +16192,10 @@ fi
 
 
 
-if test "$PORTNAME" = "win32" -o "$PORTNAME" = "cygwin"; then
-	# Cygwin and (apparently, based on test results) Mingw both
-	# have a broken strtof(), so substitute its implementation.
-	# That's not a perfect fix, since it doesn't avoid double-rounding,
-	# but we have no better options.
+if test "$PORTNAME" = "cygwin"; then
+	# Cygwin has a broken strtof(), so substitute its implementation.  That's
+	# not a perfect fix, since it doesn't avoid double-rounding, but we have no
+	# better options.
 	case " $LIBOBJS " in
   *" strtof.$ac_objext "* ) ;;
   *) LIBOBJS="$LIBOBJS strtof.$ac_objext"
diff --git a/configure.ac b/configure.ac
index c2413720a18..69a5c0d2e5d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1850,11 +1850,10 @@ AC_REPLACE_FUNCS(m4_normalize([
 
 AC_REPLACE_FUNCS(pthread_barrier_wait)
 
-if test "$PORTNAME" = "win32" -o "$PORTNAME" = "cygwin"; then
-	# Cygwin and (apparently, based on test results) Mingw both
-	# have a broken strtof(), so substitute its implementation.
-	# That's not a perfect fix, since it doesn't avoid double-rounding,
-	# but we have no better options.
+if test "$PORTNAME" = "cygwin"; then
+	# Cygwin has a broken strtof(), so substitute its implementation.  That's
+	# not a perfect fix, since it doesn't avoid double-rounding, but we have no
+	# better options.
 	AC_LIBOBJ([strtof])
 	AC_MSG_NOTICE([On $host_os we will use our strtof wrapper.])
 fi
diff --git a/src/include/port/win32_port.h b/src/include/port/win32_port.h
index f54ccef7db8..2ff54df5811 100644
--- a/src/include/port/win32_port.h
+++ b/src/include/port/win32_port.h
@@ -569,20 +569,6 @@ typedef unsigned short mode_t;
 
 #endif							/* _MSC_VER */
 
-#if defined(__MINGW32__) || defined(__MINGW64__)
-/*
- * Mingw claims to have a strtof, and my reading of its source code suggests
- * that it ought to work (and not need this hack), but the regression test
- * results disagree with me; whether this is a version issue or not is not
- * clear. However, using our wrapper (and the misrounded-input variant file,
- * already required for supporting ancient systems) can't make things any
- * worse, except for a tiny performance loss when reading zeros.
- *
- * See also cygwin.h for another instance of this.
- */
-#define HAVE_BUGGY_STRTOF 1
-#endif
-
 /* in port/win32pread.c */
 extern ssize_t pg_pread(int fd, void *buf, size_t nbyte, pgoff_t offset);
 
diff --git a/src/port/meson.build b/src/port/meson.build
index fc7b059fee5..9eba75a75f7 100644
--- a/src/port/meson.build
+++ b/src/port/meson.build
@@ -135,13 +135,10 @@ foreach f : replace_funcs_pos
 endforeach
 
 
-if (host_system == 'windows' or host_system == 'cygwin') and \
-  (cc.get_id() != 'msvc' or cc.version().version_compare('<14.0'))
-
-  # Cygwin and (apparently, based on test results) Mingw both
-  # have a broken strtof(), so substitute its implementation.
-  # That's not a perfect fix, since it doesn't avoid double-rounding,
-  # but we have no better options.
+if host_system == 'cygwin'
+  # Cygwin has a broken strtof(), so substitute its implementation.  That's not
+  # a perfect fix, since it doesn't avoid double-rounding, but we have no
+  # better options.
   pgport_sources += files('strtof.c')
   message('On @0@ with compiler @1@ @2@ we will use our strtof wrapper.'.format(
     host_system, cc.get_id(), cc.version()))
diff --git a/src/test/regress/resultmap b/src/test/regress/resultmap
index 8a3ed50585e..9ccc08c7cf3 100644
--- a/src/test/regress/resultmap
+++ b/src/test/regress/resultmap
@@ -1,2 +1 @@
 float4:out:.*-.*-cygwin.*=float4-misrounded-input.out
-float4:out:.*-.*-mingw.*=float4-misrounded-input.out
-- 
2.51.2

0002-Drop-HAVE_BUGGY_STRTOF-for-Cygwin.patchtext/x-patch; charset=US-ASCII; name=0002-Drop-HAVE_BUGGY_STRTOF-for-Cygwin.patchDownload
From 5fecb2e1345f7e8e1d24f8c5787d046e2890fde0 Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@gmail.com>
Date: Sun, 23 Nov 2025 13:17:59 +1300
Subject: [PATCH 2/2] Drop HAVE_BUGGY_STRTOF for Cygwin.

Also drop the fallback code and alternative test output.  Cygwin's
strtof() might have been fixed:

https://github.com/cygwin/cygwin/commit/fb01286fab9b370c86323f84a46285cfbebfe4ff

If it is still broken, then an interested party should file a report
against Cygwin's strtof().  Cygwin is not currently tested in our build
farm.
---
 configure                                     |  14 -
 configure.ac                                  |   8 -
 doc/src/sgml/regress.sgml                     |  18 -
 src/include/port.h                            |   5 -
 src/include/port/cygwin.h                     |   8 -
 src/port/meson.build                          |  11 -
 src/port/strtof.c                             |  89 --
 .../expected/float4-misrounded-input.out      | 988 ------------------
 src/test/regress/resultmap                    |   1 -
 9 files changed, 1142 deletions(-)
 delete mode 100644 src/port/strtof.c
 delete mode 100644 src/test/regress/expected/float4-misrounded-input.out

diff --git a/configure b/configure
index b7bc44b017e..1c63d5388fc 100755
--- a/configure
+++ b/configure
@@ -16192,20 +16192,6 @@ fi
 
 
 
-if test "$PORTNAME" = "cygwin"; then
-	# Cygwin has a broken strtof(), so substitute its implementation.  That's
-	# not a perfect fix, since it doesn't avoid double-rounding, but we have no
-	# better options.
-	case " $LIBOBJS " in
-  *" strtof.$ac_objext "* ) ;;
-  *) LIBOBJS="$LIBOBJS strtof.$ac_objext"
- ;;
-esac
-
-	{ $as_echo "$as_me:${as_lineno-$LINENO}: On $host_os we will use our strtof wrapper." >&5
-$as_echo "$as_me: On $host_os we will use our strtof wrapper." >&6;}
-fi
-
 # Similarly, use system's getopt_long() only if system provides struct option.
 if test x"$ac_cv_type_struct_option" = xyes ; then
   ac_fn_c_check_func "$LINENO" "getopt_long" "ac_cv_func_getopt_long"
diff --git a/configure.ac b/configure.ac
index 69a5c0d2e5d..d347b17329f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1850,14 +1850,6 @@ AC_REPLACE_FUNCS(m4_normalize([
 
 AC_REPLACE_FUNCS(pthread_barrier_wait)
 
-if test "$PORTNAME" = "cygwin"; then
-	# Cygwin has a broken strtof(), so substitute its implementation.  That's
-	# not a perfect fix, since it doesn't avoid double-rounding, but we have no
-	# better options.
-	AC_LIBOBJ([strtof])
-	AC_MSG_NOTICE([On $host_os we will use our strtof wrapper.])
-fi
-
 # Similarly, use system's getopt_long() only if system provides struct option.
 if test x"$ac_cv_type_struct_option" = xyes ; then
   AC_REPLACE_FUNCS([getopt_long])
diff --git a/doc/src/sgml/regress.sgml b/doc/src/sgml/regress.sgml
index fd1e142d559..160f38bef9e 100644
--- a/doc/src/sgml/regress.sgml
+++ b/doc/src/sgml/regress.sgml
@@ -784,24 +784,6 @@ testname:output:platformpattern=comparisonfilename
     comparison file.
    </para>
 
-   <para>
-    For example: some systems lack a working <literal>strtof</literal> function,
-    for which our workaround causes rounding errors in the
-    <filename>float4</filename> regression test.
-    Therefore, we provide a variant comparison file,
-    <filename>float4-misrounded-input.out</filename>, which includes
-    the results to be expected on these systems.  To silence the bogus
-    <quote>failure</quote> message on <systemitem>Cygwin</systemitem>
-    platforms, <filename>resultmap</filename> includes:
-<programlisting>
-float4:out:.*-.*-cygwin.*=float4-misrounded-input.out
-</programlisting>
-    which will trigger on any machine where the output of
-    <command>config.guess</command> matches <literal>.*-.*-cygwin.*</literal>.
-    Other lines in <filename>resultmap</filename> select the variant comparison
-    file for other platforms where it's appropriate.
-   </para>
-
    <para>
     The second selection mechanism for variant comparison files is
     much more automatic: it simply uses the <quote>best match</quote> among
diff --git a/src/include/port.h b/src/include/port.h
index 3964d3b1293..8e6a5ac4671 100644
--- a/src/include/port.h
+++ b/src/include/port.h
@@ -428,11 +428,6 @@ extern int	getpeereid(int sock, uid_t *uid, gid_t *gid);
 extern void explicit_bzero(void *buf, size_t len);
 #endif
 
-#ifdef HAVE_BUGGY_STRTOF
-extern float pg_strtof(const char *nptr, char **endptr);
-#define strtof(a,b) (pg_strtof((a),(b)))
-#endif
-
 #ifdef WIN32
 /* src/port/win32link.c */
 extern int	link(const char *src, const char *dst);
diff --git a/src/include/port/cygwin.h b/src/include/port/cygwin.h
index 44bf8533729..aa07b8c12a9 100644
--- a/src/include/port/cygwin.h
+++ b/src/include/port/cygwin.h
@@ -13,11 +13,3 @@
 #define PGDLLIMPORT __declspec (dllimport)
 #endif
 #endif
-
-/*
- * Cygwin has a strtof() which is literally just (float)strtod(), which means
- * we get misrounding _and_ silent over/underflow. Using our wrapper doesn't
- * fix the misrounding but does fix the error checks, which cuts down on the
- * number of test variant files needed.
- */
-#define HAVE_BUGGY_STRTOF 1
diff --git a/src/port/meson.build b/src/port/meson.build
index 9eba75a75f7..bf3f03770b4 100644
--- a/src/port/meson.build
+++ b/src/port/meson.build
@@ -135,17 +135,6 @@ foreach f : replace_funcs_pos
 endforeach
 
 
-if host_system == 'cygwin'
-  # Cygwin has a broken strtof(), so substitute its implementation.  That's not
-  # a perfect fix, since it doesn't avoid double-rounding, but we have no
-  # better options.
-  pgport_sources += files('strtof.c')
-  message('On @0@ with compiler @1@ @2@ we will use our strtof wrapper.'.format(
-    host_system, cc.get_id(), cc.version()))
-endif
-
-
-
 # Build pgport once for backend, once for use in frontend binaries, and once
 # for use in shared libraries
 pgport = {}
diff --git a/src/port/strtof.c b/src/port/strtof.c
deleted file mode 100644
index e7258b3d6db..00000000000
--- a/src/port/strtof.c
+++ /dev/null
@@ -1,89 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * strtof.c
- *
- * Portions Copyright (c) 2019-2025, PostgreSQL Global Development Group
- *
- *
- * IDENTIFICATION
- *	  src/port/strtof.c
- *
- *-------------------------------------------------------------------------
- */
-
-#include "c.h"
-
-#include <float.h>
-#include <math.h>
-
-
-/*
- * Cygwin has a strtof() which is literally just (float)strtod(), which means
- * we can't avoid the double-rounding problem; but using this wrapper does get
- * us proper over/underflow checks. (Also, if they fix their strtof(), the
- * wrapper doesn't break anything.)
- *
- * Test results on Mingw suggest that it has the same problem, though looking
- * at the code I can't figure out why.
- */
-float
-pg_strtof(const char *nptr, char **endptr)
-{
-	int			caller_errno = errno;
-	float		fresult;
-	char	   *myendptr;
-
-	errno = 0;
-	fresult = (strtof) (nptr, &myendptr);
-	if (endptr)
-		*endptr = myendptr;
-	if (errno)
-	{
-		/* On error, just return the error to the caller. */
-		return fresult;
-	}
-	else if ((myendptr == nptr) || isnan(fresult) ||
-			 ((fresult >= FLT_MIN || fresult <= -FLT_MIN) && !isinf(fresult)))
-	{
-		/*
-		 * If we got nothing parseable, or if we got a non-0 non-subnormal
-		 * finite value (or NaN) without error, then return that to the caller
-		 * without error.
-		 */
-		errno = caller_errno;
-		return fresult;
-	}
-	else
-	{
-		/*
-		 * Try again.  errno is already 0 here, and we assume that the endptr
-		 * won't be any different.
-		 */
-		double		dresult = strtod(nptr, NULL);
-
-		if (errno)
-		{
-			/* On error, just return the error */
-			return fresult;
-		}
-		else if ((dresult == 0.0 && fresult == 0.0) ||
-				 (isinf(dresult) && isinf(fresult) && (fresult == dresult)))
-		{
-			/* both values are 0 or infinities of the same sign */
-			errno = caller_errno;
-			return fresult;
-		}
-		else if ((dresult > 0 && dresult <= FLT_MIN && (float) dresult != 0.0) ||
-				 (dresult < 0 && dresult >= -FLT_MIN && (float) dresult != 0.0))
-		{
-			/* subnormal but nonzero value */
-			errno = caller_errno;
-			return (float) dresult;
-		}
-		else
-		{
-			errno = ERANGE;
-			return fresult;
-		}
-	}
-}
diff --git a/src/test/regress/expected/float4-misrounded-input.out b/src/test/regress/expected/float4-misrounded-input.out
deleted file mode 100644
index 61c68a6c9ff..00000000000
--- a/src/test/regress/expected/float4-misrounded-input.out
+++ /dev/null
@@ -1,988 +0,0 @@
---
--- FLOAT4
---
-CREATE TABLE FLOAT4_TBL (f1  float4);
-INSERT INTO FLOAT4_TBL(f1) VALUES ('    0.0');
-INSERT INTO FLOAT4_TBL(f1) VALUES ('1004.30   ');
-INSERT INTO FLOAT4_TBL(f1) VALUES ('     -34.84    ');
-INSERT INTO FLOAT4_TBL(f1) VALUES ('1.2345678901234e+20');
-INSERT INTO FLOAT4_TBL(f1) VALUES ('1.2345678901234e-20');
--- test for over and under flow
-INSERT INTO FLOAT4_TBL(f1) VALUES ('10e70');
-ERROR:  "10e70" is out of range for type real
-LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('10e70');
-                                           ^
-INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e70');
-ERROR:  "-10e70" is out of range for type real
-LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e70');
-                                           ^
-INSERT INTO FLOAT4_TBL(f1) VALUES ('10e-70');
-ERROR:  "10e-70" is out of range for type real
-LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('10e-70');
-                                           ^
-INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e-70');
-ERROR:  "-10e-70" is out of range for type real
-LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e-70');
-                                           ^
-INSERT INTO FLOAT4_TBL(f1) VALUES ('10e70'::float8);
-ERROR:  value out of range: overflow
-INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e70'::float8);
-ERROR:  value out of range: overflow
-INSERT INTO FLOAT4_TBL(f1) VALUES ('10e-70'::float8);
-ERROR:  value out of range: underflow
-INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e-70'::float8);
-ERROR:  value out of range: underflow
-INSERT INTO FLOAT4_TBL(f1) VALUES ('10e400');
-ERROR:  "10e400" is out of range for type real
-LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('10e400');
-                                           ^
-INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e400');
-ERROR:  "-10e400" is out of range for type real
-LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e400');
-                                           ^
-INSERT INTO FLOAT4_TBL(f1) VALUES ('10e-400');
-ERROR:  "10e-400" is out of range for type real
-LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('10e-400');
-                                           ^
-INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e-400');
-ERROR:  "-10e-400" is out of range for type real
-LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e-400');
-                                           ^
--- bad input
-INSERT INTO FLOAT4_TBL(f1) VALUES ('');
-ERROR:  invalid input syntax for type real: ""
-LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('');
-                                           ^
-INSERT INTO FLOAT4_TBL(f1) VALUES ('       ');
-ERROR:  invalid input syntax for type real: "       "
-LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('       ');
-                                           ^
-INSERT INTO FLOAT4_TBL(f1) VALUES ('xyz');
-ERROR:  invalid input syntax for type real: "xyz"
-LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('xyz');
-                                           ^
-INSERT INTO FLOAT4_TBL(f1) VALUES ('5.0.0');
-ERROR:  invalid input syntax for type real: "5.0.0"
-LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('5.0.0');
-                                           ^
-INSERT INTO FLOAT4_TBL(f1) VALUES ('5 . 0');
-ERROR:  invalid input syntax for type real: "5 . 0"
-LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('5 . 0');
-                                           ^
-INSERT INTO FLOAT4_TBL(f1) VALUES ('5.   0');
-ERROR:  invalid input syntax for type real: "5.   0"
-LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('5.   0');
-                                           ^
-INSERT INTO FLOAT4_TBL(f1) VALUES ('     - 3.0');
-ERROR:  invalid input syntax for type real: "     - 3.0"
-LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('     - 3.0');
-                                           ^
-INSERT INTO FLOAT4_TBL(f1) VALUES ('123            5');
-ERROR:  invalid input syntax for type real: "123            5"
-LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('123            5');
-                                           ^
--- Also try it with non-error-throwing API
-SELECT pg_input_is_valid('34.5', 'float4');
- pg_input_is_valid 
--------------------
- t
-(1 row)
-
-SELECT pg_input_is_valid('xyz', 'float4');
- pg_input_is_valid 
--------------------
- f
-(1 row)
-
-SELECT pg_input_is_valid('1e400', 'float4');
- pg_input_is_valid 
--------------------
- f
-(1 row)
-
-SELECT * FROM pg_input_error_info('1e400', 'float4');
-                message                | detail | hint | sql_error_code 
----------------------------------------+--------+------+----------------
- "1e400" is out of range for type real |        |      | 22003
-(1 row)
-
--- special inputs
-SELECT 'NaN'::float4;
- float4 
---------
-    NaN
-(1 row)
-
-SELECT 'nan'::float4;
- float4 
---------
-    NaN
-(1 row)
-
-SELECT '   NAN  '::float4;
- float4 
---------
-    NaN
-(1 row)
-
-SELECT 'infinity'::float4;
-  float4  
-----------
- Infinity
-(1 row)
-
-SELECT '          -INFINiTY   '::float4;
-  float4   
------------
- -Infinity
-(1 row)
-
--- bad special inputs
-SELECT 'N A N'::float4;
-ERROR:  invalid input syntax for type real: "N A N"
-LINE 1: SELECT 'N A N'::float4;
-               ^
-SELECT 'NaN x'::float4;
-ERROR:  invalid input syntax for type real: "NaN x"
-LINE 1: SELECT 'NaN x'::float4;
-               ^
-SELECT ' INFINITY    x'::float4;
-ERROR:  invalid input syntax for type real: " INFINITY    x"
-LINE 1: SELECT ' INFINITY    x'::float4;
-               ^
-SELECT 'Infinity'::float4 + 100.0;
- ?column? 
-----------
- Infinity
-(1 row)
-
-SELECT 'Infinity'::float4 / 'Infinity'::float4;
- ?column? 
-----------
-      NaN
-(1 row)
-
-SELECT '42'::float4 / 'Infinity'::float4;
- ?column? 
-----------
-        0
-(1 row)
-
-SELECT 'nan'::float4 / 'nan'::float4;
- ?column? 
-----------
-      NaN
-(1 row)
-
-SELECT 'nan'::float4 / '0'::float4;
- ?column? 
-----------
-      NaN
-(1 row)
-
-SELECT 'nan'::numeric::float4;
- float4 
---------
-    NaN
-(1 row)
-
-SELECT * FROM FLOAT4_TBL;
-      f1       
----------------
-             0
-        1004.3
-        -34.84
- 1.2345679e+20
- 1.2345679e-20
-(5 rows)
-
-SELECT f.* FROM FLOAT4_TBL f WHERE f.f1 <> '1004.3';
-      f1       
----------------
-             0
-        -34.84
- 1.2345679e+20
- 1.2345679e-20
-(4 rows)
-
-SELECT f.* FROM FLOAT4_TBL f WHERE f.f1 = '1004.3';
-   f1   
---------
- 1004.3
-(1 row)
-
-SELECT f.* FROM FLOAT4_TBL f WHERE '1004.3' > f.f1;
-      f1       
----------------
-             0
-        -34.84
- 1.2345679e-20
-(3 rows)
-
-SELECT f.* FROM FLOAT4_TBL f WHERE  f.f1 < '1004.3';
-      f1       
----------------
-             0
-        -34.84
- 1.2345679e-20
-(3 rows)
-
-SELECT f.* FROM FLOAT4_TBL f WHERE '1004.3' >= f.f1;
-      f1       
----------------
-             0
-        1004.3
-        -34.84
- 1.2345679e-20
-(4 rows)
-
-SELECT f.* FROM FLOAT4_TBL f WHERE  f.f1 <= '1004.3';
-      f1       
----------------
-             0
-        1004.3
-        -34.84
- 1.2345679e-20
-(4 rows)
-
-SELECT f.f1, f.f1 * '-10' AS x FROM FLOAT4_TBL f
-   WHERE f.f1 > '0.0';
-      f1       |       x        
----------------+----------------
-        1004.3 |         -10043
- 1.2345679e+20 | -1.2345678e+21
- 1.2345679e-20 | -1.2345678e-19
-(3 rows)
-
-SELECT f.f1, f.f1 + '-10' AS x FROM FLOAT4_TBL f
-   WHERE f.f1 > '0.0';
-      f1       |       x       
----------------+---------------
-        1004.3 |         994.3
- 1.2345679e+20 | 1.2345679e+20
- 1.2345679e-20 |           -10
-(3 rows)
-
-SELECT f.f1, f.f1 / '-10' AS x FROM FLOAT4_TBL f
-   WHERE f.f1 > '0.0';
-      f1       |       x        
----------------+----------------
-        1004.3 |        -100.43
- 1.2345679e+20 | -1.2345679e+19
- 1.2345679e-20 | -1.2345679e-21
-(3 rows)
-
-SELECT f.f1, f.f1 - '-10' AS x FROM FLOAT4_TBL f
-   WHERE f.f1 > '0.0';
-      f1       |       x       
----------------+---------------
-        1004.3 |        1014.3
- 1.2345679e+20 | 1.2345679e+20
- 1.2345679e-20 |            10
-(3 rows)
-
--- test divide by zero
-SELECT f.f1 / '0.0' from FLOAT4_TBL f;
-ERROR:  division by zero
-SELECT * FROM FLOAT4_TBL;
-      f1       
----------------
-             0
-        1004.3
-        -34.84
- 1.2345679e+20
- 1.2345679e-20
-(5 rows)
-
--- test the unary float4abs operator
-SELECT f.f1, @f.f1 AS abs_f1 FROM FLOAT4_TBL f;
-      f1       |    abs_f1     
----------------+---------------
-             0 |             0
-        1004.3 |        1004.3
-        -34.84 |         34.84
- 1.2345679e+20 | 1.2345679e+20
- 1.2345679e-20 | 1.2345679e-20
-(5 rows)
-
-UPDATE FLOAT4_TBL
-   SET f1 = FLOAT4_TBL.f1 * '-1'
-   WHERE FLOAT4_TBL.f1 > '0.0';
-SELECT * FROM FLOAT4_TBL ORDER BY 1;
-       f1       
-----------------
- -1.2345679e+20
-        -1004.3
-         -34.84
- -1.2345679e-20
-              0
-(5 rows)
-
--- test edge-case coercions to integer
-SELECT '32767.4'::float4::int2;
- int2  
--------
- 32767
-(1 row)
-
-SELECT '32767.6'::float4::int2;
-ERROR:  smallint out of range
-SELECT '-32768.4'::float4::int2;
-  int2  
---------
- -32768
-(1 row)
-
-SELECT '-32768.6'::float4::int2;
-ERROR:  smallint out of range
-SELECT '2147483520'::float4::int4;
-    int4    
-------------
- 2147483520
-(1 row)
-
-SELECT '2147483647'::float4::int4;
-ERROR:  integer out of range
-SELECT '-2147483648.5'::float4::int4;
-    int4     
--------------
- -2147483648
-(1 row)
-
-SELECT '-2147483900'::float4::int4;
-ERROR:  integer out of range
-SELECT '9223369837831520256'::float4::int8;
-        int8         
----------------------
- 9223369837831520256
-(1 row)
-
-SELECT '9223372036854775807'::float4::int8;
-ERROR:  bigint out of range
-SELECT '-9223372036854775808.5'::float4::int8;
-         int8         
-----------------------
- -9223372036854775808
-(1 row)
-
-SELECT '-9223380000000000000'::float4::int8;
-ERROR:  bigint out of range
--- Test for correct input rounding in edge cases.
--- These lists are from Paxson 1991, excluding subnormals and
--- inputs of over 9 sig. digits.
-SELECT float4send('5e-20'::float4);
- float4send 
-------------
- \x1f6c1e4a
-(1 row)
-
-SELECT float4send('67e14'::float4);
- float4send 
-------------
- \x59be6cea
-(1 row)
-
-SELECT float4send('985e15'::float4);
- float4send 
-------------
- \x5d5ab6c4
-(1 row)
-
-SELECT float4send('55895e-16'::float4);
- float4send 
-------------
- \x2cc4a9bd
-(1 row)
-
-SELECT float4send('7038531e-32'::float4);
- float4send 
-------------
- \x15ae43fe
-(1 row)
-
-SELECT float4send('702990899e-20'::float4);
- float4send 
-------------
- \x2cf757ca
-(1 row)
-
-SELECT float4send('3e-23'::float4);
- float4send 
-------------
- \x1a111234
-(1 row)
-
-SELECT float4send('57e18'::float4);
- float4send 
-------------
- \x6045c22c
-(1 row)
-
-SELECT float4send('789e-35'::float4);
- float4send 
-------------
- \x0a23de70
-(1 row)
-
-SELECT float4send('2539e-18'::float4);
- float4send 
-------------
- \x2736f449
-(1 row)
-
-SELECT float4send('76173e28'::float4);
- float4send 
-------------
- \x7616398a
-(1 row)
-
-SELECT float4send('887745e-11'::float4);
- float4send 
-------------
- \x3714f05c
-(1 row)
-
-SELECT float4send('5382571e-37'::float4);
- float4send 
-------------
- \x0d2eaca7
-(1 row)
-
-SELECT float4send('82381273e-35'::float4);
- float4send 
-------------
- \x128289d0
-(1 row)
-
-SELECT float4send('750486563e-38'::float4);
- float4send 
-------------
- \x0f18377e
-(1 row)
-
--- Test that the smallest possible normalized input value inputs
--- correctly, either in 9-significant-digit or shortest-decimal
--- format.
---
--- exact val is             1.1754943508...
--- shortest val is          1.1754944000
--- midpoint to next val is  1.1754944208...
-SELECT float4send('1.17549435e-38'::float4);
- float4send 
-------------
- \x00800000
-(1 row)
-
-SELECT float4send('1.1754944e-38'::float4);
- float4send 
-------------
- \x00800000
-(1 row)
-
--- test output (and round-trip safety) of various values.
--- To ensure we're testing what we think we're testing, start with
--- float values specified by bit patterns (as a useful side effect,
--- this means we'll fail on non-IEEE platforms).
-create type xfloat4;
-create function xfloat4in(cstring) returns xfloat4 immutable strict
-  language internal as 'int4in';
-NOTICE:  return type xfloat4 is only a shell
-create function xfloat4out(xfloat4) returns cstring immutable strict
-  language internal as 'int4out';
-NOTICE:  argument type xfloat4 is only a shell
-LINE 1: create function xfloat4out(xfloat4) returns cstring immutabl...
-                                   ^
-create type xfloat4 (input = xfloat4in, output = xfloat4out, like = float4);
-create cast (xfloat4 as float4) without function;
-create cast (float4 as xfloat4) without function;
-create cast (xfloat4 as integer) without function;
-create cast (integer as xfloat4) without function;
--- float4: seeeeeee emmmmmmm mmmmmmmm mmmmmmmm
--- we don't care to assume the platform's strtod() handles subnormals
--- correctly; those are "use at your own risk". However we do test
--- subnormal outputs, since those are under our control.
-with testdata(bits) as (values
-  -- small subnormals
-  (x'00000001'),
-  (x'00000002'), (x'00000003'),
-  (x'00000010'), (x'00000011'), (x'00000100'), (x'00000101'),
-  (x'00004000'), (x'00004001'), (x'00080000'), (x'00080001'),
-  -- stress values
-  (x'0053c4f4'),  -- 7693e-42
-  (x'006c85c4'),  -- 996622e-44
-  (x'0041ca76'),  -- 60419369e-46
-  (x'004b7678'),  -- 6930161142e-48
-  -- taken from upstream testsuite
-  (x'00000007'),
-  (x'00424fe2'),
-  -- borderline between subnormal and normal
-  (x'007ffff0'), (x'007ffff1'), (x'007ffffe'), (x'007fffff'))
-select float4send(flt) as ibits,
-       flt
-  from (select bits::integer::xfloat4::float4 as flt
-          from testdata
-	offset 0) s;
-   ibits    |      flt      
-------------+---------------
- \x00000001 |         1e-45
- \x00000002 |         3e-45
- \x00000003 |         4e-45
- \x00000010 |       2.2e-44
- \x00000011 |       2.4e-44
- \x00000100 |      3.59e-43
- \x00000101 |       3.6e-43
- \x00004000 |    2.2959e-41
- \x00004001 |     2.296e-41
- \x00080000 |   7.34684e-40
- \x00080001 |   7.34685e-40
- \x0053c4f4 |     7.693e-39
- \x006c85c4 |   9.96622e-39
- \x0041ca76 |  6.041937e-39
- \x004b7678 |  6.930161e-39
- \x00000007 |         1e-44
- \x00424fe2 |    6.0898e-39
- \x007ffff0 | 1.1754921e-38
- \x007ffff1 | 1.1754922e-38
- \x007ffffe | 1.1754941e-38
- \x007fffff | 1.1754942e-38
-(21 rows)
-
-with testdata(bits) as (values
-  (x'00000000'),
-  -- smallest normal values
-  (x'00800000'), (x'00800001'), (x'00800004'), (x'00800005'),
-  (x'00800006'),
-  -- small normal values chosen for short vs. long output
-  (x'008002f1'), (x'008002f2'), (x'008002f3'),
-  (x'00800e17'), (x'00800e18'), (x'00800e19'),
-  -- assorted values (random mantissae)
-  (x'01000001'), (x'01102843'), (x'01a52c98'),
-  (x'0219c229'), (x'02e4464d'), (x'037343c1'), (x'03a91b36'),
-  (x'047ada65'), (x'0496fe87'), (x'0550844f'), (x'05999da3'),
-  (x'060ea5e2'), (x'06e63c45'), (x'07f1e548'), (x'0fc5282b'),
-  (x'1f850283'), (x'2874a9d6'),
-  -- values around 5e-08
-  (x'3356bf94'), (x'3356bf95'), (x'3356bf96'),
-  -- around 1e-07
-  (x'33d6bf94'), (x'33d6bf95'), (x'33d6bf96'),
-  -- around 3e-07 .. 1e-04
-  (x'34a10faf'), (x'34a10fb0'), (x'34a10fb1'),
-  (x'350637bc'), (x'350637bd'), (x'350637be'),
-  (x'35719786'), (x'35719787'), (x'35719788'),
-  (x'358637bc'), (x'358637bd'), (x'358637be'),
-  (x'36a7c5ab'), (x'36a7c5ac'), (x'36a7c5ad'),
-  (x'3727c5ab'), (x'3727c5ac'), (x'3727c5ad'),
-  -- format crossover at 1e-04
-  (x'38d1b714'), (x'38d1b715'), (x'38d1b716'),
-  (x'38d1b717'), (x'38d1b718'), (x'38d1b719'),
-  (x'38d1b71a'), (x'38d1b71b'), (x'38d1b71c'),
-  (x'38d1b71d'),
-  --
-  (x'38dffffe'), (x'38dfffff'), (x'38e00000'),
-  (x'38efffff'), (x'38f00000'), (x'38f00001'),
-  (x'3a83126e'), (x'3a83126f'), (x'3a831270'),
-  (x'3c23d709'), (x'3c23d70a'), (x'3c23d70b'),
-  (x'3dcccccc'), (x'3dcccccd'), (x'3dccccce'),
-  -- chosen to need 9 digits for 3dcccd70
-  (x'3dcccd6f'), (x'3dcccd70'), (x'3dcccd71'),
-  --
-  (x'3effffff'), (x'3f000000'), (x'3f000001'),
-  (x'3f333332'), (x'3f333333'), (x'3f333334'),
-  -- approach 1.0 with increasing numbers of 9s
-  (x'3f666665'), (x'3f666666'), (x'3f666667'),
-  (x'3f7d70a3'), (x'3f7d70a4'), (x'3f7d70a5'),
-  (x'3f7fbe76'), (x'3f7fbe77'), (x'3f7fbe78'),
-  (x'3f7ff971'), (x'3f7ff972'), (x'3f7ff973'),
-  (x'3f7fff57'), (x'3f7fff58'), (x'3f7fff59'),
-  (x'3f7fffee'), (x'3f7fffef'),
-  -- values very close to 1
-  (x'3f7ffff0'), (x'3f7ffff1'), (x'3f7ffff2'),
-  (x'3f7ffff3'), (x'3f7ffff4'), (x'3f7ffff5'),
-  (x'3f7ffff6'), (x'3f7ffff7'), (x'3f7ffff8'),
-  (x'3f7ffff9'), (x'3f7ffffa'), (x'3f7ffffb'),
-  (x'3f7ffffc'), (x'3f7ffffd'), (x'3f7ffffe'),
-  (x'3f7fffff'),
-  (x'3f800000'),
-  (x'3f800001'), (x'3f800002'), (x'3f800003'),
-  (x'3f800004'), (x'3f800005'), (x'3f800006'),
-  (x'3f800007'), (x'3f800008'), (x'3f800009'),
-  -- values 1 to 1.1
-  (x'3f80000f'), (x'3f800010'), (x'3f800011'),
-  (x'3f800012'), (x'3f800013'), (x'3f800014'),
-  (x'3f800017'), (x'3f800018'), (x'3f800019'),
-  (x'3f80001a'), (x'3f80001b'), (x'3f80001c'),
-  (x'3f800029'), (x'3f80002a'), (x'3f80002b'),
-  (x'3f800053'), (x'3f800054'), (x'3f800055'),
-  (x'3f800346'), (x'3f800347'), (x'3f800348'),
-  (x'3f8020c4'), (x'3f8020c5'), (x'3f8020c6'),
-  (x'3f8147ad'), (x'3f8147ae'), (x'3f8147af'),
-  (x'3f8ccccc'), (x'3f8ccccd'), (x'3f8cccce'),
-  --
-  (x'3fc90fdb'), -- pi/2
-  (x'402df854'), -- e
-  (x'40490fdb'), -- pi
-  --
-  (x'409fffff'), (x'40a00000'), (x'40a00001'),
-  (x'40afffff'), (x'40b00000'), (x'40b00001'),
-  (x'411fffff'), (x'41200000'), (x'41200001'),
-  (x'42c7ffff'), (x'42c80000'), (x'42c80001'),
-  (x'4479ffff'), (x'447a0000'), (x'447a0001'),
-  (x'461c3fff'), (x'461c4000'), (x'461c4001'),
-  (x'47c34fff'), (x'47c35000'), (x'47c35001'),
-  (x'497423ff'), (x'49742400'), (x'49742401'),
-  (x'4b18967f'), (x'4b189680'), (x'4b189681'),
-  (x'4cbebc1f'), (x'4cbebc20'), (x'4cbebc21'),
-  (x'4e6e6b27'), (x'4e6e6b28'), (x'4e6e6b29'),
-  (x'501502f8'), (x'501502f9'), (x'501502fa'),
-  (x'51ba43b6'), (x'51ba43b7'), (x'51ba43b8'),
-  -- stress values
-  (x'1f6c1e4a'),  -- 5e-20
-  (x'59be6cea'),  -- 67e14
-  (x'5d5ab6c4'),  -- 985e15
-  (x'2cc4a9bd'),  -- 55895e-16
-  (x'15ae43fd'),  -- 7038531e-32
-  (x'2cf757ca'),  -- 702990899e-20
-  (x'665ba998'),  -- 25933168707e13
-  (x'743c3324'),  -- 596428896559e20
-  -- exercise fixed-point memmoves
-  (x'47f1205a'),
-  (x'4640e6ae'),
-  (x'449a5225'),
-  (x'42f6e9d5'),
-  (x'414587dd'),
-  (x'3f9e064b'),
-  -- these cases come from the upstream's testsuite
-  -- BoundaryRoundEven
-  (x'4c000004'),
-  (x'50061c46'),
-  (x'510006a8'),
-  -- ExactValueRoundEven
-  (x'48951f84'),
-  (x'45fd1840'),
-  -- LotsOfTrailingZeros
-  (x'39800000'),
-  (x'3b200000'),
-  (x'3b900000'),
-  (x'3bd00000'),
-  -- Regression
-  (x'63800000'),
-  (x'4b000000'),
-  (x'4b800000'),
-  (x'4c000001'),
-  (x'4c800b0d'),
-  (x'00d24584'),
-  (x'00d90b88'),
-  (x'45803f34'),
-  (x'4f9f24f7'),
-  (x'3a8722c3'),
-  (x'5c800041'),
-  (x'15ae43fd'),
-  (x'5d4cccfb'),
-  (x'4c800001'),
-  (x'57800ed8'),
-  (x'5f000000'),
-  (x'700000f0'),
-  (x'5f23e9ac'),
-  (x'5e9502f9'),
-  (x'5e8012b1'),
-  (x'3c000028'),
-  (x'60cde861'),
-  (x'03aa2a50'),
-  (x'43480000'),
-  (x'4c000000'),
-  -- LooksLikePow5
-  (x'5D1502F9'),
-  (x'5D9502F9'),
-  (x'5E1502F9'),
-  -- OutputLength
-  (x'3f99999a'),
-  (x'3f9d70a4'),
-  (x'3f9df3b6'),
-  (x'3f9e0419'),
-  (x'3f9e0610'),
-  (x'3f9e064b'),
-  (x'3f9e0651'),
-  (x'03d20cfe')
-)
-select float4send(flt) as ibits,
-       flt,
-       flt::text::float4 as r_flt,
-       float4send(flt::text::float4) as obits,
-       float4send(flt::text::float4) = float4send(flt) as correct
-  from (select bits::integer::xfloat4::float4 as flt
-          from testdata
-	offset 0) s;
-   ibits    |      flt       |     r_flt      |   obits    | correct 
-------------+----------------+----------------+------------+---------
- \x00000000 |              0 |              0 | \x00000000 | t
- \x00800000 |  1.1754944e-38 |  1.1754944e-38 | \x00800000 | t
- \x00800001 |  1.1754945e-38 |  1.1754945e-38 | \x00800001 | t
- \x00800004 |  1.1754949e-38 |  1.1754949e-38 | \x00800004 | t
- \x00800005 |   1.175495e-38 |   1.175495e-38 | \x00800005 | t
- \x00800006 |  1.1754952e-38 |  1.1754952e-38 | \x00800006 | t
- \x008002f1 |  1.1755999e-38 |  1.1755999e-38 | \x008002f1 | t
- \x008002f2 |     1.1756e-38 |     1.1756e-38 | \x008002f2 | t
- \x008002f3 |  1.1756001e-38 |  1.1756001e-38 | \x008002f3 | t
- \x00800e17 |  1.1759998e-38 |  1.1759998e-38 | \x00800e17 | t
- \x00800e18 |      1.176e-38 |      1.176e-38 | \x00800e18 | t
- \x00800e19 |  1.1760001e-38 |  1.1760001e-38 | \x00800e19 | t
- \x01000001 |   2.350989e-38 |   2.350989e-38 | \x01000001 | t
- \x01102843 |   2.647751e-38 |   2.647751e-38 | \x01102843 | t
- \x01a52c98 |  6.0675416e-38 |  6.0675416e-38 | \x01a52c98 | t
- \x0219c229 |  1.1296386e-37 |  1.1296386e-37 | \x0219c229 | t
- \x02e4464d |   3.354194e-37 |   3.354194e-37 | \x02e4464d | t
- \x037343c1 |   7.148906e-37 |   7.148906e-37 | \x037343c1 | t
- \x03a91b36 |   9.939175e-37 |   9.939175e-37 | \x03a91b36 | t
- \x047ada65 |   2.948764e-36 |   2.948764e-36 | \x047ada65 | t
- \x0496fe87 |  3.5498577e-36 |  3.5498577e-36 | \x0496fe87 | t
- \x0550844f |   9.804414e-36 |   9.804414e-36 | \x0550844f | t
- \x05999da3 |  1.4445957e-35 |  1.4445957e-35 | \x05999da3 | t
- \x060ea5e2 |  2.6829103e-35 |  2.6829103e-35 | \x060ea5e2 | t
- \x06e63c45 |   8.660494e-35 |   8.660494e-35 | \x06e63c45 | t
- \x07f1e548 |   3.639641e-34 |   3.639641e-34 | \x07f1e548 | t
- \x0fc5282b |  1.9441172e-29 |  1.9441172e-29 | \x0fc5282b | t
- \x1f850283 |  5.6331846e-20 |  5.6331846e-20 | \x1f850283 | t
- \x2874a9d6 |  1.3581548e-14 |  1.3581548e-14 | \x2874a9d6 | t
- \x3356bf94 |  4.9999997e-08 |  4.9999997e-08 | \x3356bf94 | t
- \x3356bf95 |          5e-08 |          5e-08 | \x3356bf95 | t
- \x3356bf96 |  5.0000004e-08 |  5.0000004e-08 | \x3356bf96 | t
- \x33d6bf94 |  9.9999994e-08 |  9.9999994e-08 | \x33d6bf94 | t
- \x33d6bf95 |          1e-07 |          1e-07 | \x33d6bf95 | t
- \x33d6bf96 |  1.0000001e-07 |  1.0000001e-07 | \x33d6bf96 | t
- \x34a10faf |  2.9999998e-07 |  2.9999998e-07 | \x34a10faf | t
- \x34a10fb0 |          3e-07 |          3e-07 | \x34a10fb0 | t
- \x34a10fb1 |  3.0000004e-07 |  3.0000004e-07 | \x34a10fb1 | t
- \x350637bc |  4.9999994e-07 |  4.9999994e-07 | \x350637bc | t
- \x350637bd |          5e-07 |          5e-07 | \x350637bd | t
- \x350637be |  5.0000006e-07 |  5.0000006e-07 | \x350637be | t
- \x35719786 |   8.999999e-07 |   8.999999e-07 | \x35719786 | t
- \x35719787 |          9e-07 |          9e-07 | \x35719787 | t
- \x35719788 |  9.0000003e-07 |  9.0000003e-07 | \x35719788 | t
- \x358637bc |   9.999999e-07 |   9.999999e-07 | \x358637bc | t
- \x358637bd |          1e-06 |          1e-06 | \x358637bd | t
- \x358637be |  1.0000001e-06 |  1.0000001e-06 | \x358637be | t
- \x36a7c5ab |  4.9999994e-06 |  4.9999994e-06 | \x36a7c5ab | t
- \x36a7c5ac |          5e-06 |          5e-06 | \x36a7c5ac | t
- \x36a7c5ad |  5.0000003e-06 |  5.0000003e-06 | \x36a7c5ad | t
- \x3727c5ab |   9.999999e-06 |   9.999999e-06 | \x3727c5ab | t
- \x3727c5ac |          1e-05 |          1e-05 | \x3727c5ac | t
- \x3727c5ad |  1.0000001e-05 |  1.0000001e-05 | \x3727c5ad | t
- \x38d1b714 |  9.9999976e-05 |  9.9999976e-05 | \x38d1b714 | t
- \x38d1b715 |   9.999998e-05 |   9.999998e-05 | \x38d1b715 | t
- \x38d1b716 |   9.999999e-05 |   9.999999e-05 | \x38d1b716 | t
- \x38d1b717 |         0.0001 |         0.0001 | \x38d1b717 | t
- \x38d1b718 | 0.000100000005 | 0.000100000005 | \x38d1b718 | t
- \x38d1b719 |  0.00010000001 |  0.00010000001 | \x38d1b719 | t
- \x38d1b71a |  0.00010000002 |  0.00010000002 | \x38d1b71a | t
- \x38d1b71b |  0.00010000003 |  0.00010000003 | \x38d1b71b | t
- \x38d1b71c | 0.000100000034 | 0.000100000034 | \x38d1b71c | t
- \x38d1b71d |  0.00010000004 |  0.00010000004 | \x38d1b71d | t
- \x38dffffe |  0.00010681151 |  0.00010681151 | \x38dffffe | t
- \x38dfffff | 0.000106811516 | 0.000106811516 | \x38dfffff | t
- \x38e00000 |  0.00010681152 |  0.00010681152 | \x38e00000 | t
- \x38efffff |  0.00011444091 |  0.00011444091 | \x38efffff | t
- \x38f00000 |  0.00011444092 |  0.00011444092 | \x38f00000 | t
- \x38f00001 | 0.000114440925 | 0.000114440925 | \x38f00001 | t
- \x3a83126e |   0.0009999999 |   0.0009999999 | \x3a83126e | t
- \x3a83126f |          0.001 |          0.001 | \x3a83126f | t
- \x3a831270 |   0.0010000002 |   0.0010000002 | \x3a831270 | t
- \x3c23d709 |    0.009999999 |    0.009999999 | \x3c23d709 | t
- \x3c23d70a |           0.01 |           0.01 | \x3c23d70a | t
- \x3c23d70b |    0.010000001 |    0.010000001 | \x3c23d70b | t
- \x3dcccccc |    0.099999994 |    0.099999994 | \x3dcccccc | t
- \x3dcccccd |            0.1 |            0.1 | \x3dcccccd | t
- \x3dccccce |     0.10000001 |     0.10000001 | \x3dccccce | t
- \x3dcccd6f |     0.10000121 |     0.10000121 | \x3dcccd6f | t
- \x3dcccd70 |    0.100001216 |    0.100001216 | \x3dcccd70 | t
- \x3dcccd71 |     0.10000122 |     0.10000122 | \x3dcccd71 | t
- \x3effffff |     0.49999997 |     0.49999997 | \x3effffff | t
- \x3f000000 |            0.5 |            0.5 | \x3f000000 | t
- \x3f000001 |     0.50000006 |     0.50000006 | \x3f000001 | t
- \x3f333332 |      0.6999999 |      0.6999999 | \x3f333332 | t
- \x3f333333 |            0.7 |            0.7 | \x3f333333 | t
- \x3f333334 |     0.70000005 |     0.70000005 | \x3f333334 | t
- \x3f666665 |      0.8999999 |      0.8999999 | \x3f666665 | t
- \x3f666666 |            0.9 |            0.9 | \x3f666666 | t
- \x3f666667 |     0.90000004 |     0.90000004 | \x3f666667 | t
- \x3f7d70a3 |     0.98999995 |     0.98999995 | \x3f7d70a3 | t
- \x3f7d70a4 |           0.99 |           0.99 | \x3f7d70a4 | t
- \x3f7d70a5 |     0.99000007 |     0.99000007 | \x3f7d70a5 | t
- \x3f7fbe76 |     0.99899995 |     0.99899995 | \x3f7fbe76 | t
- \x3f7fbe77 |          0.999 |          0.999 | \x3f7fbe77 | t
- \x3f7fbe78 |      0.9990001 |      0.9990001 | \x3f7fbe78 | t
- \x3f7ff971 |      0.9998999 |      0.9998999 | \x3f7ff971 | t
- \x3f7ff972 |         0.9999 |         0.9999 | \x3f7ff972 | t
- \x3f7ff973 |     0.99990004 |     0.99990004 | \x3f7ff973 | t
- \x3f7fff57 |      0.9999899 |      0.9999899 | \x3f7fff57 | t
- \x3f7fff58 |        0.99999 |        0.99999 | \x3f7fff58 | t
- \x3f7fff59 |     0.99999005 |     0.99999005 | \x3f7fff59 | t
- \x3f7fffee |      0.9999989 |      0.9999989 | \x3f7fffee | t
- \x3f7fffef |       0.999999 |       0.999999 | \x3f7fffef | t
- \x3f7ffff0 |     0.99999905 |     0.99999905 | \x3f7ffff0 | t
- \x3f7ffff1 |      0.9999991 |      0.9999991 | \x3f7ffff1 | t
- \x3f7ffff2 |     0.99999917 |     0.99999917 | \x3f7ffff2 | t
- \x3f7ffff3 |      0.9999992 |      0.9999992 | \x3f7ffff3 | t
- \x3f7ffff4 |      0.9999993 |      0.9999993 | \x3f7ffff4 | t
- \x3f7ffff5 |     0.99999934 |     0.99999934 | \x3f7ffff5 | t
- \x3f7ffff6 |      0.9999994 |      0.9999994 | \x3f7ffff6 | t
- \x3f7ffff7 |     0.99999946 |     0.99999946 | \x3f7ffff7 | t
- \x3f7ffff8 |      0.9999995 |      0.9999995 | \x3f7ffff8 | t
- \x3f7ffff9 |      0.9999996 |      0.9999996 | \x3f7ffff9 | t
- \x3f7ffffa |     0.99999964 |     0.99999964 | \x3f7ffffa | t
- \x3f7ffffb |      0.9999997 |      0.9999997 | \x3f7ffffb | t
- \x3f7ffffc |     0.99999976 |     0.99999976 | \x3f7ffffc | t
- \x3f7ffffd |      0.9999998 |      0.9999998 | \x3f7ffffd | t
- \x3f7ffffe |      0.9999999 |      0.9999999 | \x3f7ffffe | t
- \x3f7fffff |     0.99999994 |     0.99999994 | \x3f7fffff | t
- \x3f800000 |              1 |              1 | \x3f800000 | t
- \x3f800001 |      1.0000001 |      1.0000001 | \x3f800001 | t
- \x3f800002 |      1.0000002 |      1.0000002 | \x3f800002 | t
- \x3f800003 |      1.0000004 |      1.0000004 | \x3f800003 | t
- \x3f800004 |      1.0000005 |      1.0000005 | \x3f800004 | t
- \x3f800005 |      1.0000006 |      1.0000006 | \x3f800005 | t
- \x3f800006 |      1.0000007 |      1.0000007 | \x3f800006 | t
- \x3f800007 |      1.0000008 |      1.0000008 | \x3f800007 | t
- \x3f800008 |       1.000001 |       1.000001 | \x3f800008 | t
- \x3f800009 |      1.0000011 |      1.0000011 | \x3f800009 | t
- \x3f80000f |      1.0000018 |      1.0000018 | \x3f80000f | t
- \x3f800010 |      1.0000019 |      1.0000019 | \x3f800010 | t
- \x3f800011 |       1.000002 |       1.000002 | \x3f800011 | t
- \x3f800012 |      1.0000021 |      1.0000021 | \x3f800012 | t
- \x3f800013 |      1.0000023 |      1.0000023 | \x3f800013 | t
- \x3f800014 |      1.0000024 |      1.0000024 | \x3f800014 | t
- \x3f800017 |      1.0000027 |      1.0000027 | \x3f800017 | t
- \x3f800018 |      1.0000029 |      1.0000029 | \x3f800018 | t
- \x3f800019 |       1.000003 |       1.000003 | \x3f800019 | t
- \x3f80001a |      1.0000031 |      1.0000031 | \x3f80001a | t
- \x3f80001b |      1.0000032 |      1.0000032 | \x3f80001b | t
- \x3f80001c |      1.0000033 |      1.0000033 | \x3f80001c | t
- \x3f800029 |      1.0000049 |      1.0000049 | \x3f800029 | t
- \x3f80002a |       1.000005 |       1.000005 | \x3f80002a | t
- \x3f80002b |      1.0000051 |      1.0000051 | \x3f80002b | t
- \x3f800053 |      1.0000099 |      1.0000099 | \x3f800053 | t
- \x3f800054 |        1.00001 |        1.00001 | \x3f800054 | t
- \x3f800055 |      1.0000101 |      1.0000101 | \x3f800055 | t
- \x3f800346 |      1.0000999 |      1.0000999 | \x3f800346 | t
- \x3f800347 |         1.0001 |         1.0001 | \x3f800347 | t
- \x3f800348 |      1.0001001 |      1.0001001 | \x3f800348 | t
- \x3f8020c4 |      1.0009999 |      1.0009999 | \x3f8020c4 | t
- \x3f8020c5 |          1.001 |          1.001 | \x3f8020c5 | t
- \x3f8020c6 |      1.0010002 |      1.0010002 | \x3f8020c6 | t
- \x3f8147ad |      1.0099999 |      1.0099999 | \x3f8147ad | t
- \x3f8147ae |           1.01 |           1.01 | \x3f8147ae | t
- \x3f8147af |      1.0100001 |      1.0100001 | \x3f8147af | t
- \x3f8ccccc |      1.0999999 |      1.0999999 | \x3f8ccccc | t
- \x3f8ccccd |            1.1 |            1.1 | \x3f8ccccd | t
- \x3f8cccce |      1.1000001 |      1.1000001 | \x3f8cccce | t
- \x3fc90fdb |      1.5707964 |      1.5707964 | \x3fc90fdb | t
- \x402df854 |      2.7182817 |      2.7182817 | \x402df854 | t
- \x40490fdb |      3.1415927 |      3.1415927 | \x40490fdb | t
- \x409fffff |      4.9999995 |      4.9999995 | \x409fffff | t
- \x40a00000 |              5 |              5 | \x40a00000 | t
- \x40a00001 |      5.0000005 |      5.0000005 | \x40a00001 | t
- \x40afffff |      5.4999995 |      5.4999995 | \x40afffff | t
- \x40b00000 |            5.5 |            5.5 | \x40b00000 | t
- \x40b00001 |      5.5000005 |      5.5000005 | \x40b00001 | t
- \x411fffff |       9.999999 |       9.999999 | \x411fffff | t
- \x41200000 |             10 |             10 | \x41200000 | t
- \x41200001 |      10.000001 |      10.000001 | \x41200001 | t
- \x42c7ffff |       99.99999 |       99.99999 | \x42c7ffff | t
- \x42c80000 |            100 |            100 | \x42c80000 | t
- \x42c80001 |      100.00001 |      100.00001 | \x42c80001 | t
- \x4479ffff |      999.99994 |      999.99994 | \x4479ffff | t
- \x447a0000 |           1000 |           1000 | \x447a0000 | t
- \x447a0001 |     1000.00006 |     1000.00006 | \x447a0001 | t
- \x461c3fff |       9999.999 |       9999.999 | \x461c3fff | t
- \x461c4000 |          10000 |          10000 | \x461c4000 | t
- \x461c4001 |      10000.001 |      10000.001 | \x461c4001 | t
- \x47c34fff |       99999.99 |       99999.99 | \x47c34fff | t
- \x47c35000 |         100000 |         100000 | \x47c35000 | t
- \x47c35001 |      100000.01 |      100000.01 | \x47c35001 | t
- \x497423ff |      999999.94 |      999999.94 | \x497423ff | t
- \x49742400 |          1e+06 |          1e+06 | \x49742400 | t
- \x49742401 | 1.00000006e+06 | 1.00000006e+06 | \x49742401 | t
- \x4b18967f |   9.999999e+06 |   9.999999e+06 | \x4b18967f | t
- \x4b189680 |          1e+07 |          1e+07 | \x4b189680 | t
- \x4b189681 |  1.0000001e+07 |  1.0000001e+07 | \x4b189681 | t
- \x4cbebc1f |   9.999999e+07 |   9.999999e+07 | \x4cbebc1f | t
- \x4cbebc20 |          1e+08 |          1e+08 | \x4cbebc20 | t
- \x4cbebc21 |  1.0000001e+08 |  1.0000001e+08 | \x4cbebc21 | t
- \x4e6e6b27 |  9.9999994e+08 |  9.9999994e+08 | \x4e6e6b27 | t
- \x4e6e6b28 |          1e+09 |          1e+09 | \x4e6e6b28 | t
- \x4e6e6b29 | 1.00000006e+09 | 1.00000006e+09 | \x4e6e6b29 | t
- \x501502f8 |   9.999999e+09 |   9.999999e+09 | \x501502f8 | t
- \x501502f9 |          1e+10 |          1e+10 | \x501502f9 | t
- \x501502fa |  1.0000001e+10 |  1.0000001e+10 | \x501502fa | t
- \x51ba43b6 |   9.999999e+10 |   9.999999e+10 | \x51ba43b6 | t
- \x51ba43b7 |          1e+11 |          1e+11 | \x51ba43b7 | t
- \x51ba43b8 |  1.0000001e+11 |  1.0000001e+11 | \x51ba43b8 | t
- \x1f6c1e4a |          5e-20 |          5e-20 | \x1f6c1e4a | t
- \x59be6cea |        6.7e+15 |        6.7e+15 | \x59be6cea | t
- \x5d5ab6c4 |       9.85e+17 |       9.85e+17 | \x5d5ab6c4 | t
- \x2cc4a9bd |     5.5895e-12 |     5.5895e-12 | \x2cc4a9bd | t
- \x15ae43fd |   7.038531e-26 |  7.0385313e-26 | \x15ae43fe | f
- \x2cf757ca |  7.0299088e-12 |  7.0299088e-12 | \x2cf757ca | t
- \x665ba998 |  2.5933168e+23 |  2.5933168e+23 | \x665ba998 | t
- \x743c3324 |  5.9642887e+31 |  5.9642887e+31 | \x743c3324 | t
- \x47f1205a |       123456.7 |       123456.7 | \x47f1205a | t
- \x4640e6ae |       12345.67 |       12345.67 | \x4640e6ae | t
- \x449a5225 |       1234.567 |       1234.567 | \x449a5225 | t
- \x42f6e9d5 |       123.4567 |       123.4567 | \x42f6e9d5 | t
- \x414587dd |       12.34567 |       12.34567 | \x414587dd | t
- \x3f9e064b |       1.234567 |       1.234567 | \x3f9e064b | t
- \x4c000004 |  3.3554448e+07 |  3.3554448e+07 | \x4c000004 | t
- \x50061c46 |   8.999999e+09 |   8.999999e+09 | \x50061c46 | t
- \x510006a8 |  3.4366718e+10 |  3.4366718e+10 | \x510006a8 | t
- \x48951f84 |      305404.12 |      305404.12 | \x48951f84 | t
- \x45fd1840 |      8099.0312 |      8099.0312 | \x45fd1840 | t
- \x39800000 |  0.00024414062 |  0.00024414062 | \x39800000 | t
- \x3b200000 |   0.0024414062 |   0.0024414062 | \x3b200000 | t
- \x3b900000 |   0.0043945312 |   0.0043945312 | \x3b900000 | t
- \x3bd00000 |   0.0063476562 |   0.0063476562 | \x3bd00000 | t
- \x63800000 |  4.7223665e+21 |  4.7223665e+21 | \x63800000 | t
- \x4b000000 |   8.388608e+06 |   8.388608e+06 | \x4b000000 | t
- \x4b800000 |  1.6777216e+07 |  1.6777216e+07 | \x4b800000 | t
- \x4c000001 |  3.3554436e+07 |  3.3554436e+07 | \x4c000001 | t
- \x4c800b0d |  6.7131496e+07 |  6.7131496e+07 | \x4c800b0d | t
- \x00d24584 |  1.9310392e-38 |  1.9310392e-38 | \x00d24584 | t
- \x00d90b88 |   1.993244e-38 |   1.993244e-38 | \x00d90b88 | t
- \x45803f34 |      4103.9004 |      4103.9004 | \x45803f34 | t
- \x4f9f24f7 |  5.3399997e+09 |  5.3399997e+09 | \x4f9f24f7 | t
- \x3a8722c3 |   0.0010310042 |   0.0010310042 | \x3a8722c3 | t
- \x5c800041 |   2.882326e+17 |   2.882326e+17 | \x5c800041 | t
- \x15ae43fd |   7.038531e-26 |  7.0385313e-26 | \x15ae43fe | f
- \x5d4cccfb |   9.223404e+17 |   9.223404e+17 | \x5d4cccfb | t
- \x4c800001 |   6.710887e+07 |   6.710887e+07 | \x4c800001 | t
- \x57800ed8 |   2.816025e+14 |   2.816025e+14 | \x57800ed8 | t
- \x5f000000 |   9.223372e+18 |   9.223372e+18 | \x5f000000 | t
- \x700000f0 |  1.5846086e+29 |  1.5846086e+29 | \x700000f0 | t
- \x5f23e9ac |  1.1811161e+19 |  1.1811161e+19 | \x5f23e9ac | t
- \x5e9502f9 |   5.368709e+18 |   5.368709e+18 | \x5e9502f9 | t
- \x5e8012b1 |  4.6143166e+18 |  4.6143166e+18 | \x5e8012b1 | t
- \x3c000028 |    0.007812537 |    0.007812537 | \x3c000028 | t
- \x60cde861 | 1.18697725e+20 | 1.18697725e+20 | \x60cde861 | t
- \x03aa2a50 | 1.00014165e-36 | 1.00014165e-36 | \x03aa2a50 | t
- \x43480000 |            200 |            200 | \x43480000 | t
- \x4c000000 |  3.3554432e+07 |  3.3554432e+07 | \x4c000000 | t
- \x5d1502f9 |  6.7108864e+17 |  6.7108864e+17 | \x5d1502f9 | t
- \x5d9502f9 |  1.3421773e+18 |  1.3421773e+18 | \x5d9502f9 | t
- \x5e1502f9 |  2.6843546e+18 |  2.6843546e+18 | \x5e1502f9 | t
- \x3f99999a |            1.2 |            1.2 | \x3f99999a | t
- \x3f9d70a4 |           1.23 |           1.23 | \x3f9d70a4 | t
- \x3f9df3b6 |          1.234 |          1.234 | \x3f9df3b6 | t
- \x3f9e0419 |         1.2345 |         1.2345 | \x3f9e0419 | t
- \x3f9e0610 |        1.23456 |        1.23456 | \x3f9e0610 | t
- \x3f9e064b |       1.234567 |       1.234567 | \x3f9e064b | t
- \x3f9e0651 |      1.2345678 |      1.2345678 | \x3f9e0651 | t
- \x03d20cfe | 1.23456735e-36 | 1.23456735e-36 | \x03d20cfe | t
-(261 rows)
-
--- clean up, lest opr_sanity complain
-drop type xfloat4 cascade;
-NOTICE:  drop cascades to 6 other objects
-DETAIL:  drop cascades to function xfloat4in(cstring)
-drop cascades to function xfloat4out(xfloat4)
-drop cascades to cast from xfloat4 to real
-drop cascades to cast from real to xfloat4
-drop cascades to cast from xfloat4 to integer
-drop cascades to cast from integer to xfloat4
diff --git a/src/test/regress/resultmap b/src/test/regress/resultmap
index 9ccc08c7cf3..e69de29bb2d 100644
--- a/src/test/regress/resultmap
+++ b/src/test/regress/resultmap
@@ -1 +0,0 @@
-float4:out:.*-.*-cygwin.*=float4-misrounded-input.out
-- 
2.51.2

#20Tom Lane
tgl@sss.pgh.pa.us
In reply to: Thomas Munro (#19)
Re: PRI?64 vs Visual Studio (2022)

Thomas Munro <thomas.munro@gmail.com> writes:

That'd leave only Cygwin with HAVE BUGGY_STRTOF. Perhaps they have
fixed their implementation[1]? Here's an experimental patch to drop
all remnants, which could be used to find out. No Windows/Cygwin
here. Hmm, what if we just commit it anyway? If their strtof() is
still broken and someone out there is running the tests and sees this
test fail, why shouldn't they take that up with libc at this stage?

Hmm, we could get rid of the whole resultmap mechanism ...

regards, tom lane

#21Thomas Munro
thomas.munro@gmail.com
In reply to: Tom Lane (#20)
3 attachment(s)
Re: PRI?64 vs Visual Studio (2022)

On Sun, Nov 23, 2025 at 4:25 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:

Thomas Munro <thomas.munro@gmail.com> writes:

That'd leave only Cygwin with HAVE BUGGY_STRTOF. Perhaps they have
fixed their implementation[1]? Here's an experimental patch to drop
all remnants, which could be used to find out. No Windows/Cygwin
here. Hmm, what if we just commit it anyway? If their strtof() is
still broken and someone out there is running the tests and sees this
test fail, why shouldn't they take that up with libc at this stage?

Hmm, we could get rid of the whole resultmap mechanism ...

Yeah. I thought I'd see what blowback my
if-Cygwin-strtof()-really-is-still-broken-they-should-fix-it argument
attracted before spending the time to nuke all those lines too.
Here's that patch. We could always revert resultmap we found a new
reason to need it, but I hope we wouldn't.

Attachments:

v2-0001-Drop-HAVE_BUGGY_STRTOF-for-MinGW.patchtext/x-patch; charset=US-ASCII; name=v2-0001-Drop-HAVE_BUGGY_STRTOF-for-MinGW.patchDownload
From d72a63b0ba1e0c176abbcefaf674ff1fb9e00992 Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@gmail.com>
Date: Sun, 23 Nov 2025 12:22:46 +1300
Subject: [PATCH v2 1/3] Drop HAVE_BUGGY_STRTOF for MinGW.

Commit 72880ac182c8 pointed MinGW builds at our replacement strtof()
function.  This isn't necessary with UCRT.  Also remove a stray
reference to Visual Studio 2013 (another desupported way to use MSVCRT)
from meson.build.

Discussion: https://postgr.es/m/CA%2BhUKGJ0J-H8C51HK8pEGdbD7tVuut5igkRhFt0byWm_CezeoQ%40mail.gmail.com
---
 configure                     |  9 ++++-----
 configure.ac                  |  9 ++++-----
 src/include/port/win32_port.h | 14 --------------
 src/port/meson.build          | 11 ++++-------
 src/test/regress/resultmap    |  1 -
 5 files changed, 12 insertions(+), 32 deletions(-)

diff --git a/configure b/configure
index 3a0ed11fa8e..b7bc44b017e 100755
--- a/configure
+++ b/configure
@@ -16192,11 +16192,10 @@ fi
 
 
 
-if test "$PORTNAME" = "win32" -o "$PORTNAME" = "cygwin"; then
-	# Cygwin and (apparently, based on test results) Mingw both
-	# have a broken strtof(), so substitute its implementation.
-	# That's not a perfect fix, since it doesn't avoid double-rounding,
-	# but we have no better options.
+if test "$PORTNAME" = "cygwin"; then
+	# Cygwin has a broken strtof(), so substitute its implementation.  That's
+	# not a perfect fix, since it doesn't avoid double-rounding, but we have no
+	# better options.
 	case " $LIBOBJS " in
   *" strtof.$ac_objext "* ) ;;
   *) LIBOBJS="$LIBOBJS strtof.$ac_objext"
diff --git a/configure.ac b/configure.ac
index c2413720a18..69a5c0d2e5d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1850,11 +1850,10 @@ AC_REPLACE_FUNCS(m4_normalize([
 
 AC_REPLACE_FUNCS(pthread_barrier_wait)
 
-if test "$PORTNAME" = "win32" -o "$PORTNAME" = "cygwin"; then
-	# Cygwin and (apparently, based on test results) Mingw both
-	# have a broken strtof(), so substitute its implementation.
-	# That's not a perfect fix, since it doesn't avoid double-rounding,
-	# but we have no better options.
+if test "$PORTNAME" = "cygwin"; then
+	# Cygwin has a broken strtof(), so substitute its implementation.  That's
+	# not a perfect fix, since it doesn't avoid double-rounding, but we have no
+	# better options.
 	AC_LIBOBJ([strtof])
 	AC_MSG_NOTICE([On $host_os we will use our strtof wrapper.])
 fi
diff --git a/src/include/port/win32_port.h b/src/include/port/win32_port.h
index f54ccef7db8..2ff54df5811 100644
--- a/src/include/port/win32_port.h
+++ b/src/include/port/win32_port.h
@@ -569,20 +569,6 @@ typedef unsigned short mode_t;
 
 #endif							/* _MSC_VER */
 
-#if defined(__MINGW32__) || defined(__MINGW64__)
-/*
- * Mingw claims to have a strtof, and my reading of its source code suggests
- * that it ought to work (and not need this hack), but the regression test
- * results disagree with me; whether this is a version issue or not is not
- * clear. However, using our wrapper (and the misrounded-input variant file,
- * already required for supporting ancient systems) can't make things any
- * worse, except for a tiny performance loss when reading zeros.
- *
- * See also cygwin.h for another instance of this.
- */
-#define HAVE_BUGGY_STRTOF 1
-#endif
-
 /* in port/win32pread.c */
 extern ssize_t pg_pread(int fd, void *buf, size_t nbyte, pgoff_t offset);
 
diff --git a/src/port/meson.build b/src/port/meson.build
index fc7b059fee5..9eba75a75f7 100644
--- a/src/port/meson.build
+++ b/src/port/meson.build
@@ -135,13 +135,10 @@ foreach f : replace_funcs_pos
 endforeach
 
 
-if (host_system == 'windows' or host_system == 'cygwin') and \
-  (cc.get_id() != 'msvc' or cc.version().version_compare('<14.0'))
-
-  # Cygwin and (apparently, based on test results) Mingw both
-  # have a broken strtof(), so substitute its implementation.
-  # That's not a perfect fix, since it doesn't avoid double-rounding,
-  # but we have no better options.
+if host_system == 'cygwin'
+  # Cygwin has a broken strtof(), so substitute its implementation.  That's not
+  # a perfect fix, since it doesn't avoid double-rounding, but we have no
+  # better options.
   pgport_sources += files('strtof.c')
   message('On @0@ with compiler @1@ @2@ we will use our strtof wrapper.'.format(
     host_system, cc.get_id(), cc.version()))
diff --git a/src/test/regress/resultmap b/src/test/regress/resultmap
index 8a3ed50585e..9ccc08c7cf3 100644
--- a/src/test/regress/resultmap
+++ b/src/test/regress/resultmap
@@ -1,2 +1 @@
 float4:out:.*-.*-cygwin.*=float4-misrounded-input.out
-float4:out:.*-.*-mingw.*=float4-misrounded-input.out
-- 
2.51.2

v2-0002-Drop-HAVE_BUGGY_STRTOF-for-Cygwin.patchtext/x-patch; charset=US-ASCII; name=v2-0002-Drop-HAVE_BUGGY_STRTOF-for-Cygwin.patchDownload
From a1aed062f513b1ec375b93d5431d2406d8c35983 Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@gmail.com>
Date: Sun, 23 Nov 2025 13:17:59 +1300
Subject: [PATCH v2 2/3] Drop HAVE_BUGGY_STRTOF for Cygwin.

Also drop the fallback code and alternative test output.  Cygwin's
strtof() might have been fixed:

https://github.com/cygwin/cygwin/commit/fb01286fab9b370c86323f84a46285cfbebfe4ff

If it is still broken, then an interested party should file a report
against that project.  Cygwin is not currently tested in our build farm.

Discussion: https://postgr.es/m/CA%2BhUKGJ0J-H8C51HK8pEGdbD7tVuut5igkRhFt0byWm_CezeoQ%40mail.gmail.com
---
 configure                                     |  14 -
 configure.ac                                  |   8 -
 doc/src/sgml/regress.sgml                     |  18 -
 src/include/port.h                            |   5 -
 src/include/port/cygwin.h                     |   8 -
 src/port/meson.build                          |  11 -
 src/port/strtof.c                             |  89 --
 .../expected/float4-misrounded-input.out      | 988 ------------------
 src/test/regress/resultmap                    |   1 -
 9 files changed, 1142 deletions(-)
 delete mode 100644 src/port/strtof.c
 delete mode 100644 src/test/regress/expected/float4-misrounded-input.out

diff --git a/configure b/configure
index b7bc44b017e..1c63d5388fc 100755
--- a/configure
+++ b/configure
@@ -16192,20 +16192,6 @@ fi
 
 
 
-if test "$PORTNAME" = "cygwin"; then
-	# Cygwin has a broken strtof(), so substitute its implementation.  That's
-	# not a perfect fix, since it doesn't avoid double-rounding, but we have no
-	# better options.
-	case " $LIBOBJS " in
-  *" strtof.$ac_objext "* ) ;;
-  *) LIBOBJS="$LIBOBJS strtof.$ac_objext"
- ;;
-esac
-
-	{ $as_echo "$as_me:${as_lineno-$LINENO}: On $host_os we will use our strtof wrapper." >&5
-$as_echo "$as_me: On $host_os we will use our strtof wrapper." >&6;}
-fi
-
 # Similarly, use system's getopt_long() only if system provides struct option.
 if test x"$ac_cv_type_struct_option" = xyes ; then
   ac_fn_c_check_func "$LINENO" "getopt_long" "ac_cv_func_getopt_long"
diff --git a/configure.ac b/configure.ac
index 69a5c0d2e5d..d347b17329f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1850,14 +1850,6 @@ AC_REPLACE_FUNCS(m4_normalize([
 
 AC_REPLACE_FUNCS(pthread_barrier_wait)
 
-if test "$PORTNAME" = "cygwin"; then
-	# Cygwin has a broken strtof(), so substitute its implementation.  That's
-	# not a perfect fix, since it doesn't avoid double-rounding, but we have no
-	# better options.
-	AC_LIBOBJ([strtof])
-	AC_MSG_NOTICE([On $host_os we will use our strtof wrapper.])
-fi
-
 # Similarly, use system's getopt_long() only if system provides struct option.
 if test x"$ac_cv_type_struct_option" = xyes ; then
   AC_REPLACE_FUNCS([getopt_long])
diff --git a/doc/src/sgml/regress.sgml b/doc/src/sgml/regress.sgml
index fd1e142d559..160f38bef9e 100644
--- a/doc/src/sgml/regress.sgml
+++ b/doc/src/sgml/regress.sgml
@@ -784,24 +784,6 @@ testname:output:platformpattern=comparisonfilename
     comparison file.
    </para>
 
-   <para>
-    For example: some systems lack a working <literal>strtof</literal> function,
-    for which our workaround causes rounding errors in the
-    <filename>float4</filename> regression test.
-    Therefore, we provide a variant comparison file,
-    <filename>float4-misrounded-input.out</filename>, which includes
-    the results to be expected on these systems.  To silence the bogus
-    <quote>failure</quote> message on <systemitem>Cygwin</systemitem>
-    platforms, <filename>resultmap</filename> includes:
-<programlisting>
-float4:out:.*-.*-cygwin.*=float4-misrounded-input.out
-</programlisting>
-    which will trigger on any machine where the output of
-    <command>config.guess</command> matches <literal>.*-.*-cygwin.*</literal>.
-    Other lines in <filename>resultmap</filename> select the variant comparison
-    file for other platforms where it's appropriate.
-   </para>
-
    <para>
     The second selection mechanism for variant comparison files is
     much more automatic: it simply uses the <quote>best match</quote> among
diff --git a/src/include/port.h b/src/include/port.h
index 3964d3b1293..8e6a5ac4671 100644
--- a/src/include/port.h
+++ b/src/include/port.h
@@ -428,11 +428,6 @@ extern int	getpeereid(int sock, uid_t *uid, gid_t *gid);
 extern void explicit_bzero(void *buf, size_t len);
 #endif
 
-#ifdef HAVE_BUGGY_STRTOF
-extern float pg_strtof(const char *nptr, char **endptr);
-#define strtof(a,b) (pg_strtof((a),(b)))
-#endif
-
 #ifdef WIN32
 /* src/port/win32link.c */
 extern int	link(const char *src, const char *dst);
diff --git a/src/include/port/cygwin.h b/src/include/port/cygwin.h
index 44bf8533729..aa07b8c12a9 100644
--- a/src/include/port/cygwin.h
+++ b/src/include/port/cygwin.h
@@ -13,11 +13,3 @@
 #define PGDLLIMPORT __declspec (dllimport)
 #endif
 #endif
-
-/*
- * Cygwin has a strtof() which is literally just (float)strtod(), which means
- * we get misrounding _and_ silent over/underflow. Using our wrapper doesn't
- * fix the misrounding but does fix the error checks, which cuts down on the
- * number of test variant files needed.
- */
-#define HAVE_BUGGY_STRTOF 1
diff --git a/src/port/meson.build b/src/port/meson.build
index 9eba75a75f7..bf3f03770b4 100644
--- a/src/port/meson.build
+++ b/src/port/meson.build
@@ -135,17 +135,6 @@ foreach f : replace_funcs_pos
 endforeach
 
 
-if host_system == 'cygwin'
-  # Cygwin has a broken strtof(), so substitute its implementation.  That's not
-  # a perfect fix, since it doesn't avoid double-rounding, but we have no
-  # better options.
-  pgport_sources += files('strtof.c')
-  message('On @0@ with compiler @1@ @2@ we will use our strtof wrapper.'.format(
-    host_system, cc.get_id(), cc.version()))
-endif
-
-
-
 # Build pgport once for backend, once for use in frontend binaries, and once
 # for use in shared libraries
 pgport = {}
diff --git a/src/port/strtof.c b/src/port/strtof.c
deleted file mode 100644
index e7258b3d6db..00000000000
--- a/src/port/strtof.c
+++ /dev/null
@@ -1,89 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * strtof.c
- *
- * Portions Copyright (c) 2019-2025, PostgreSQL Global Development Group
- *
- *
- * IDENTIFICATION
- *	  src/port/strtof.c
- *
- *-------------------------------------------------------------------------
- */
-
-#include "c.h"
-
-#include <float.h>
-#include <math.h>
-
-
-/*
- * Cygwin has a strtof() which is literally just (float)strtod(), which means
- * we can't avoid the double-rounding problem; but using this wrapper does get
- * us proper over/underflow checks. (Also, if they fix their strtof(), the
- * wrapper doesn't break anything.)
- *
- * Test results on Mingw suggest that it has the same problem, though looking
- * at the code I can't figure out why.
- */
-float
-pg_strtof(const char *nptr, char **endptr)
-{
-	int			caller_errno = errno;
-	float		fresult;
-	char	   *myendptr;
-
-	errno = 0;
-	fresult = (strtof) (nptr, &myendptr);
-	if (endptr)
-		*endptr = myendptr;
-	if (errno)
-	{
-		/* On error, just return the error to the caller. */
-		return fresult;
-	}
-	else if ((myendptr == nptr) || isnan(fresult) ||
-			 ((fresult >= FLT_MIN || fresult <= -FLT_MIN) && !isinf(fresult)))
-	{
-		/*
-		 * If we got nothing parseable, or if we got a non-0 non-subnormal
-		 * finite value (or NaN) without error, then return that to the caller
-		 * without error.
-		 */
-		errno = caller_errno;
-		return fresult;
-	}
-	else
-	{
-		/*
-		 * Try again.  errno is already 0 here, and we assume that the endptr
-		 * won't be any different.
-		 */
-		double		dresult = strtod(nptr, NULL);
-
-		if (errno)
-		{
-			/* On error, just return the error */
-			return fresult;
-		}
-		else if ((dresult == 0.0 && fresult == 0.0) ||
-				 (isinf(dresult) && isinf(fresult) && (fresult == dresult)))
-		{
-			/* both values are 0 or infinities of the same sign */
-			errno = caller_errno;
-			return fresult;
-		}
-		else if ((dresult > 0 && dresult <= FLT_MIN && (float) dresult != 0.0) ||
-				 (dresult < 0 && dresult >= -FLT_MIN && (float) dresult != 0.0))
-		{
-			/* subnormal but nonzero value */
-			errno = caller_errno;
-			return (float) dresult;
-		}
-		else
-		{
-			errno = ERANGE;
-			return fresult;
-		}
-	}
-}
diff --git a/src/test/regress/expected/float4-misrounded-input.out b/src/test/regress/expected/float4-misrounded-input.out
deleted file mode 100644
index 61c68a6c9ff..00000000000
--- a/src/test/regress/expected/float4-misrounded-input.out
+++ /dev/null
@@ -1,988 +0,0 @@
---
--- FLOAT4
---
-CREATE TABLE FLOAT4_TBL (f1  float4);
-INSERT INTO FLOAT4_TBL(f1) VALUES ('    0.0');
-INSERT INTO FLOAT4_TBL(f1) VALUES ('1004.30   ');
-INSERT INTO FLOAT4_TBL(f1) VALUES ('     -34.84    ');
-INSERT INTO FLOAT4_TBL(f1) VALUES ('1.2345678901234e+20');
-INSERT INTO FLOAT4_TBL(f1) VALUES ('1.2345678901234e-20');
--- test for over and under flow
-INSERT INTO FLOAT4_TBL(f1) VALUES ('10e70');
-ERROR:  "10e70" is out of range for type real
-LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('10e70');
-                                           ^
-INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e70');
-ERROR:  "-10e70" is out of range for type real
-LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e70');
-                                           ^
-INSERT INTO FLOAT4_TBL(f1) VALUES ('10e-70');
-ERROR:  "10e-70" is out of range for type real
-LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('10e-70');
-                                           ^
-INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e-70');
-ERROR:  "-10e-70" is out of range for type real
-LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e-70');
-                                           ^
-INSERT INTO FLOAT4_TBL(f1) VALUES ('10e70'::float8);
-ERROR:  value out of range: overflow
-INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e70'::float8);
-ERROR:  value out of range: overflow
-INSERT INTO FLOAT4_TBL(f1) VALUES ('10e-70'::float8);
-ERROR:  value out of range: underflow
-INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e-70'::float8);
-ERROR:  value out of range: underflow
-INSERT INTO FLOAT4_TBL(f1) VALUES ('10e400');
-ERROR:  "10e400" is out of range for type real
-LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('10e400');
-                                           ^
-INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e400');
-ERROR:  "-10e400" is out of range for type real
-LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e400');
-                                           ^
-INSERT INTO FLOAT4_TBL(f1) VALUES ('10e-400');
-ERROR:  "10e-400" is out of range for type real
-LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('10e-400');
-                                           ^
-INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e-400');
-ERROR:  "-10e-400" is out of range for type real
-LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e-400');
-                                           ^
--- bad input
-INSERT INTO FLOAT4_TBL(f1) VALUES ('');
-ERROR:  invalid input syntax for type real: ""
-LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('');
-                                           ^
-INSERT INTO FLOAT4_TBL(f1) VALUES ('       ');
-ERROR:  invalid input syntax for type real: "       "
-LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('       ');
-                                           ^
-INSERT INTO FLOAT4_TBL(f1) VALUES ('xyz');
-ERROR:  invalid input syntax for type real: "xyz"
-LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('xyz');
-                                           ^
-INSERT INTO FLOAT4_TBL(f1) VALUES ('5.0.0');
-ERROR:  invalid input syntax for type real: "5.0.0"
-LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('5.0.0');
-                                           ^
-INSERT INTO FLOAT4_TBL(f1) VALUES ('5 . 0');
-ERROR:  invalid input syntax for type real: "5 . 0"
-LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('5 . 0');
-                                           ^
-INSERT INTO FLOAT4_TBL(f1) VALUES ('5.   0');
-ERROR:  invalid input syntax for type real: "5.   0"
-LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('5.   0');
-                                           ^
-INSERT INTO FLOAT4_TBL(f1) VALUES ('     - 3.0');
-ERROR:  invalid input syntax for type real: "     - 3.0"
-LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('     - 3.0');
-                                           ^
-INSERT INTO FLOAT4_TBL(f1) VALUES ('123            5');
-ERROR:  invalid input syntax for type real: "123            5"
-LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('123            5');
-                                           ^
--- Also try it with non-error-throwing API
-SELECT pg_input_is_valid('34.5', 'float4');
- pg_input_is_valid 
--------------------
- t
-(1 row)
-
-SELECT pg_input_is_valid('xyz', 'float4');
- pg_input_is_valid 
--------------------
- f
-(1 row)
-
-SELECT pg_input_is_valid('1e400', 'float4');
- pg_input_is_valid 
--------------------
- f
-(1 row)
-
-SELECT * FROM pg_input_error_info('1e400', 'float4');
-                message                | detail | hint | sql_error_code 
----------------------------------------+--------+------+----------------
- "1e400" is out of range for type real |        |      | 22003
-(1 row)
-
--- special inputs
-SELECT 'NaN'::float4;
- float4 
---------
-    NaN
-(1 row)
-
-SELECT 'nan'::float4;
- float4 
---------
-    NaN
-(1 row)
-
-SELECT '   NAN  '::float4;
- float4 
---------
-    NaN
-(1 row)
-
-SELECT 'infinity'::float4;
-  float4  
-----------
- Infinity
-(1 row)
-
-SELECT '          -INFINiTY   '::float4;
-  float4   
------------
- -Infinity
-(1 row)
-
--- bad special inputs
-SELECT 'N A N'::float4;
-ERROR:  invalid input syntax for type real: "N A N"
-LINE 1: SELECT 'N A N'::float4;
-               ^
-SELECT 'NaN x'::float4;
-ERROR:  invalid input syntax for type real: "NaN x"
-LINE 1: SELECT 'NaN x'::float4;
-               ^
-SELECT ' INFINITY    x'::float4;
-ERROR:  invalid input syntax for type real: " INFINITY    x"
-LINE 1: SELECT ' INFINITY    x'::float4;
-               ^
-SELECT 'Infinity'::float4 + 100.0;
- ?column? 
-----------
- Infinity
-(1 row)
-
-SELECT 'Infinity'::float4 / 'Infinity'::float4;
- ?column? 
-----------
-      NaN
-(1 row)
-
-SELECT '42'::float4 / 'Infinity'::float4;
- ?column? 
-----------
-        0
-(1 row)
-
-SELECT 'nan'::float4 / 'nan'::float4;
- ?column? 
-----------
-      NaN
-(1 row)
-
-SELECT 'nan'::float4 / '0'::float4;
- ?column? 
-----------
-      NaN
-(1 row)
-
-SELECT 'nan'::numeric::float4;
- float4 
---------
-    NaN
-(1 row)
-
-SELECT * FROM FLOAT4_TBL;
-      f1       
----------------
-             0
-        1004.3
-        -34.84
- 1.2345679e+20
- 1.2345679e-20
-(5 rows)
-
-SELECT f.* FROM FLOAT4_TBL f WHERE f.f1 <> '1004.3';
-      f1       
----------------
-             0
-        -34.84
- 1.2345679e+20
- 1.2345679e-20
-(4 rows)
-
-SELECT f.* FROM FLOAT4_TBL f WHERE f.f1 = '1004.3';
-   f1   
---------
- 1004.3
-(1 row)
-
-SELECT f.* FROM FLOAT4_TBL f WHERE '1004.3' > f.f1;
-      f1       
----------------
-             0
-        -34.84
- 1.2345679e-20
-(3 rows)
-
-SELECT f.* FROM FLOAT4_TBL f WHERE  f.f1 < '1004.3';
-      f1       
----------------
-             0
-        -34.84
- 1.2345679e-20
-(3 rows)
-
-SELECT f.* FROM FLOAT4_TBL f WHERE '1004.3' >= f.f1;
-      f1       
----------------
-             0
-        1004.3
-        -34.84
- 1.2345679e-20
-(4 rows)
-
-SELECT f.* FROM FLOAT4_TBL f WHERE  f.f1 <= '1004.3';
-      f1       
----------------
-             0
-        1004.3
-        -34.84
- 1.2345679e-20
-(4 rows)
-
-SELECT f.f1, f.f1 * '-10' AS x FROM FLOAT4_TBL f
-   WHERE f.f1 > '0.0';
-      f1       |       x        
----------------+----------------
-        1004.3 |         -10043
- 1.2345679e+20 | -1.2345678e+21
- 1.2345679e-20 | -1.2345678e-19
-(3 rows)
-
-SELECT f.f1, f.f1 + '-10' AS x FROM FLOAT4_TBL f
-   WHERE f.f1 > '0.0';
-      f1       |       x       
----------------+---------------
-        1004.3 |         994.3
- 1.2345679e+20 | 1.2345679e+20
- 1.2345679e-20 |           -10
-(3 rows)
-
-SELECT f.f1, f.f1 / '-10' AS x FROM FLOAT4_TBL f
-   WHERE f.f1 > '0.0';
-      f1       |       x        
----------------+----------------
-        1004.3 |        -100.43
- 1.2345679e+20 | -1.2345679e+19
- 1.2345679e-20 | -1.2345679e-21
-(3 rows)
-
-SELECT f.f1, f.f1 - '-10' AS x FROM FLOAT4_TBL f
-   WHERE f.f1 > '0.0';
-      f1       |       x       
----------------+---------------
-        1004.3 |        1014.3
- 1.2345679e+20 | 1.2345679e+20
- 1.2345679e-20 |            10
-(3 rows)
-
--- test divide by zero
-SELECT f.f1 / '0.0' from FLOAT4_TBL f;
-ERROR:  division by zero
-SELECT * FROM FLOAT4_TBL;
-      f1       
----------------
-             0
-        1004.3
-        -34.84
- 1.2345679e+20
- 1.2345679e-20
-(5 rows)
-
--- test the unary float4abs operator
-SELECT f.f1, @f.f1 AS abs_f1 FROM FLOAT4_TBL f;
-      f1       |    abs_f1     
----------------+---------------
-             0 |             0
-        1004.3 |        1004.3
-        -34.84 |         34.84
- 1.2345679e+20 | 1.2345679e+20
- 1.2345679e-20 | 1.2345679e-20
-(5 rows)
-
-UPDATE FLOAT4_TBL
-   SET f1 = FLOAT4_TBL.f1 * '-1'
-   WHERE FLOAT4_TBL.f1 > '0.0';
-SELECT * FROM FLOAT4_TBL ORDER BY 1;
-       f1       
-----------------
- -1.2345679e+20
-        -1004.3
-         -34.84
- -1.2345679e-20
-              0
-(5 rows)
-
--- test edge-case coercions to integer
-SELECT '32767.4'::float4::int2;
- int2  
--------
- 32767
-(1 row)
-
-SELECT '32767.6'::float4::int2;
-ERROR:  smallint out of range
-SELECT '-32768.4'::float4::int2;
-  int2  
---------
- -32768
-(1 row)
-
-SELECT '-32768.6'::float4::int2;
-ERROR:  smallint out of range
-SELECT '2147483520'::float4::int4;
-    int4    
-------------
- 2147483520
-(1 row)
-
-SELECT '2147483647'::float4::int4;
-ERROR:  integer out of range
-SELECT '-2147483648.5'::float4::int4;
-    int4     
--------------
- -2147483648
-(1 row)
-
-SELECT '-2147483900'::float4::int4;
-ERROR:  integer out of range
-SELECT '9223369837831520256'::float4::int8;
-        int8         
----------------------
- 9223369837831520256
-(1 row)
-
-SELECT '9223372036854775807'::float4::int8;
-ERROR:  bigint out of range
-SELECT '-9223372036854775808.5'::float4::int8;
-         int8         
-----------------------
- -9223372036854775808
-(1 row)
-
-SELECT '-9223380000000000000'::float4::int8;
-ERROR:  bigint out of range
--- Test for correct input rounding in edge cases.
--- These lists are from Paxson 1991, excluding subnormals and
--- inputs of over 9 sig. digits.
-SELECT float4send('5e-20'::float4);
- float4send 
-------------
- \x1f6c1e4a
-(1 row)
-
-SELECT float4send('67e14'::float4);
- float4send 
-------------
- \x59be6cea
-(1 row)
-
-SELECT float4send('985e15'::float4);
- float4send 
-------------
- \x5d5ab6c4
-(1 row)
-
-SELECT float4send('55895e-16'::float4);
- float4send 
-------------
- \x2cc4a9bd
-(1 row)
-
-SELECT float4send('7038531e-32'::float4);
- float4send 
-------------
- \x15ae43fe
-(1 row)
-
-SELECT float4send('702990899e-20'::float4);
- float4send 
-------------
- \x2cf757ca
-(1 row)
-
-SELECT float4send('3e-23'::float4);
- float4send 
-------------
- \x1a111234
-(1 row)
-
-SELECT float4send('57e18'::float4);
- float4send 
-------------
- \x6045c22c
-(1 row)
-
-SELECT float4send('789e-35'::float4);
- float4send 
-------------
- \x0a23de70
-(1 row)
-
-SELECT float4send('2539e-18'::float4);
- float4send 
-------------
- \x2736f449
-(1 row)
-
-SELECT float4send('76173e28'::float4);
- float4send 
-------------
- \x7616398a
-(1 row)
-
-SELECT float4send('887745e-11'::float4);
- float4send 
-------------
- \x3714f05c
-(1 row)
-
-SELECT float4send('5382571e-37'::float4);
- float4send 
-------------
- \x0d2eaca7
-(1 row)
-
-SELECT float4send('82381273e-35'::float4);
- float4send 
-------------
- \x128289d0
-(1 row)
-
-SELECT float4send('750486563e-38'::float4);
- float4send 
-------------
- \x0f18377e
-(1 row)
-
--- Test that the smallest possible normalized input value inputs
--- correctly, either in 9-significant-digit or shortest-decimal
--- format.
---
--- exact val is             1.1754943508...
--- shortest val is          1.1754944000
--- midpoint to next val is  1.1754944208...
-SELECT float4send('1.17549435e-38'::float4);
- float4send 
-------------
- \x00800000
-(1 row)
-
-SELECT float4send('1.1754944e-38'::float4);
- float4send 
-------------
- \x00800000
-(1 row)
-
--- test output (and round-trip safety) of various values.
--- To ensure we're testing what we think we're testing, start with
--- float values specified by bit patterns (as a useful side effect,
--- this means we'll fail on non-IEEE platforms).
-create type xfloat4;
-create function xfloat4in(cstring) returns xfloat4 immutable strict
-  language internal as 'int4in';
-NOTICE:  return type xfloat4 is only a shell
-create function xfloat4out(xfloat4) returns cstring immutable strict
-  language internal as 'int4out';
-NOTICE:  argument type xfloat4 is only a shell
-LINE 1: create function xfloat4out(xfloat4) returns cstring immutabl...
-                                   ^
-create type xfloat4 (input = xfloat4in, output = xfloat4out, like = float4);
-create cast (xfloat4 as float4) without function;
-create cast (float4 as xfloat4) without function;
-create cast (xfloat4 as integer) without function;
-create cast (integer as xfloat4) without function;
--- float4: seeeeeee emmmmmmm mmmmmmmm mmmmmmmm
--- we don't care to assume the platform's strtod() handles subnormals
--- correctly; those are "use at your own risk". However we do test
--- subnormal outputs, since those are under our control.
-with testdata(bits) as (values
-  -- small subnormals
-  (x'00000001'),
-  (x'00000002'), (x'00000003'),
-  (x'00000010'), (x'00000011'), (x'00000100'), (x'00000101'),
-  (x'00004000'), (x'00004001'), (x'00080000'), (x'00080001'),
-  -- stress values
-  (x'0053c4f4'),  -- 7693e-42
-  (x'006c85c4'),  -- 996622e-44
-  (x'0041ca76'),  -- 60419369e-46
-  (x'004b7678'),  -- 6930161142e-48
-  -- taken from upstream testsuite
-  (x'00000007'),
-  (x'00424fe2'),
-  -- borderline between subnormal and normal
-  (x'007ffff0'), (x'007ffff1'), (x'007ffffe'), (x'007fffff'))
-select float4send(flt) as ibits,
-       flt
-  from (select bits::integer::xfloat4::float4 as flt
-          from testdata
-	offset 0) s;
-   ibits    |      flt      
-------------+---------------
- \x00000001 |         1e-45
- \x00000002 |         3e-45
- \x00000003 |         4e-45
- \x00000010 |       2.2e-44
- \x00000011 |       2.4e-44
- \x00000100 |      3.59e-43
- \x00000101 |       3.6e-43
- \x00004000 |    2.2959e-41
- \x00004001 |     2.296e-41
- \x00080000 |   7.34684e-40
- \x00080001 |   7.34685e-40
- \x0053c4f4 |     7.693e-39
- \x006c85c4 |   9.96622e-39
- \x0041ca76 |  6.041937e-39
- \x004b7678 |  6.930161e-39
- \x00000007 |         1e-44
- \x00424fe2 |    6.0898e-39
- \x007ffff0 | 1.1754921e-38
- \x007ffff1 | 1.1754922e-38
- \x007ffffe | 1.1754941e-38
- \x007fffff | 1.1754942e-38
-(21 rows)
-
-with testdata(bits) as (values
-  (x'00000000'),
-  -- smallest normal values
-  (x'00800000'), (x'00800001'), (x'00800004'), (x'00800005'),
-  (x'00800006'),
-  -- small normal values chosen for short vs. long output
-  (x'008002f1'), (x'008002f2'), (x'008002f3'),
-  (x'00800e17'), (x'00800e18'), (x'00800e19'),
-  -- assorted values (random mantissae)
-  (x'01000001'), (x'01102843'), (x'01a52c98'),
-  (x'0219c229'), (x'02e4464d'), (x'037343c1'), (x'03a91b36'),
-  (x'047ada65'), (x'0496fe87'), (x'0550844f'), (x'05999da3'),
-  (x'060ea5e2'), (x'06e63c45'), (x'07f1e548'), (x'0fc5282b'),
-  (x'1f850283'), (x'2874a9d6'),
-  -- values around 5e-08
-  (x'3356bf94'), (x'3356bf95'), (x'3356bf96'),
-  -- around 1e-07
-  (x'33d6bf94'), (x'33d6bf95'), (x'33d6bf96'),
-  -- around 3e-07 .. 1e-04
-  (x'34a10faf'), (x'34a10fb0'), (x'34a10fb1'),
-  (x'350637bc'), (x'350637bd'), (x'350637be'),
-  (x'35719786'), (x'35719787'), (x'35719788'),
-  (x'358637bc'), (x'358637bd'), (x'358637be'),
-  (x'36a7c5ab'), (x'36a7c5ac'), (x'36a7c5ad'),
-  (x'3727c5ab'), (x'3727c5ac'), (x'3727c5ad'),
-  -- format crossover at 1e-04
-  (x'38d1b714'), (x'38d1b715'), (x'38d1b716'),
-  (x'38d1b717'), (x'38d1b718'), (x'38d1b719'),
-  (x'38d1b71a'), (x'38d1b71b'), (x'38d1b71c'),
-  (x'38d1b71d'),
-  --
-  (x'38dffffe'), (x'38dfffff'), (x'38e00000'),
-  (x'38efffff'), (x'38f00000'), (x'38f00001'),
-  (x'3a83126e'), (x'3a83126f'), (x'3a831270'),
-  (x'3c23d709'), (x'3c23d70a'), (x'3c23d70b'),
-  (x'3dcccccc'), (x'3dcccccd'), (x'3dccccce'),
-  -- chosen to need 9 digits for 3dcccd70
-  (x'3dcccd6f'), (x'3dcccd70'), (x'3dcccd71'),
-  --
-  (x'3effffff'), (x'3f000000'), (x'3f000001'),
-  (x'3f333332'), (x'3f333333'), (x'3f333334'),
-  -- approach 1.0 with increasing numbers of 9s
-  (x'3f666665'), (x'3f666666'), (x'3f666667'),
-  (x'3f7d70a3'), (x'3f7d70a4'), (x'3f7d70a5'),
-  (x'3f7fbe76'), (x'3f7fbe77'), (x'3f7fbe78'),
-  (x'3f7ff971'), (x'3f7ff972'), (x'3f7ff973'),
-  (x'3f7fff57'), (x'3f7fff58'), (x'3f7fff59'),
-  (x'3f7fffee'), (x'3f7fffef'),
-  -- values very close to 1
-  (x'3f7ffff0'), (x'3f7ffff1'), (x'3f7ffff2'),
-  (x'3f7ffff3'), (x'3f7ffff4'), (x'3f7ffff5'),
-  (x'3f7ffff6'), (x'3f7ffff7'), (x'3f7ffff8'),
-  (x'3f7ffff9'), (x'3f7ffffa'), (x'3f7ffffb'),
-  (x'3f7ffffc'), (x'3f7ffffd'), (x'3f7ffffe'),
-  (x'3f7fffff'),
-  (x'3f800000'),
-  (x'3f800001'), (x'3f800002'), (x'3f800003'),
-  (x'3f800004'), (x'3f800005'), (x'3f800006'),
-  (x'3f800007'), (x'3f800008'), (x'3f800009'),
-  -- values 1 to 1.1
-  (x'3f80000f'), (x'3f800010'), (x'3f800011'),
-  (x'3f800012'), (x'3f800013'), (x'3f800014'),
-  (x'3f800017'), (x'3f800018'), (x'3f800019'),
-  (x'3f80001a'), (x'3f80001b'), (x'3f80001c'),
-  (x'3f800029'), (x'3f80002a'), (x'3f80002b'),
-  (x'3f800053'), (x'3f800054'), (x'3f800055'),
-  (x'3f800346'), (x'3f800347'), (x'3f800348'),
-  (x'3f8020c4'), (x'3f8020c5'), (x'3f8020c6'),
-  (x'3f8147ad'), (x'3f8147ae'), (x'3f8147af'),
-  (x'3f8ccccc'), (x'3f8ccccd'), (x'3f8cccce'),
-  --
-  (x'3fc90fdb'), -- pi/2
-  (x'402df854'), -- e
-  (x'40490fdb'), -- pi
-  --
-  (x'409fffff'), (x'40a00000'), (x'40a00001'),
-  (x'40afffff'), (x'40b00000'), (x'40b00001'),
-  (x'411fffff'), (x'41200000'), (x'41200001'),
-  (x'42c7ffff'), (x'42c80000'), (x'42c80001'),
-  (x'4479ffff'), (x'447a0000'), (x'447a0001'),
-  (x'461c3fff'), (x'461c4000'), (x'461c4001'),
-  (x'47c34fff'), (x'47c35000'), (x'47c35001'),
-  (x'497423ff'), (x'49742400'), (x'49742401'),
-  (x'4b18967f'), (x'4b189680'), (x'4b189681'),
-  (x'4cbebc1f'), (x'4cbebc20'), (x'4cbebc21'),
-  (x'4e6e6b27'), (x'4e6e6b28'), (x'4e6e6b29'),
-  (x'501502f8'), (x'501502f9'), (x'501502fa'),
-  (x'51ba43b6'), (x'51ba43b7'), (x'51ba43b8'),
-  -- stress values
-  (x'1f6c1e4a'),  -- 5e-20
-  (x'59be6cea'),  -- 67e14
-  (x'5d5ab6c4'),  -- 985e15
-  (x'2cc4a9bd'),  -- 55895e-16
-  (x'15ae43fd'),  -- 7038531e-32
-  (x'2cf757ca'),  -- 702990899e-20
-  (x'665ba998'),  -- 25933168707e13
-  (x'743c3324'),  -- 596428896559e20
-  -- exercise fixed-point memmoves
-  (x'47f1205a'),
-  (x'4640e6ae'),
-  (x'449a5225'),
-  (x'42f6e9d5'),
-  (x'414587dd'),
-  (x'3f9e064b'),
-  -- these cases come from the upstream's testsuite
-  -- BoundaryRoundEven
-  (x'4c000004'),
-  (x'50061c46'),
-  (x'510006a8'),
-  -- ExactValueRoundEven
-  (x'48951f84'),
-  (x'45fd1840'),
-  -- LotsOfTrailingZeros
-  (x'39800000'),
-  (x'3b200000'),
-  (x'3b900000'),
-  (x'3bd00000'),
-  -- Regression
-  (x'63800000'),
-  (x'4b000000'),
-  (x'4b800000'),
-  (x'4c000001'),
-  (x'4c800b0d'),
-  (x'00d24584'),
-  (x'00d90b88'),
-  (x'45803f34'),
-  (x'4f9f24f7'),
-  (x'3a8722c3'),
-  (x'5c800041'),
-  (x'15ae43fd'),
-  (x'5d4cccfb'),
-  (x'4c800001'),
-  (x'57800ed8'),
-  (x'5f000000'),
-  (x'700000f0'),
-  (x'5f23e9ac'),
-  (x'5e9502f9'),
-  (x'5e8012b1'),
-  (x'3c000028'),
-  (x'60cde861'),
-  (x'03aa2a50'),
-  (x'43480000'),
-  (x'4c000000'),
-  -- LooksLikePow5
-  (x'5D1502F9'),
-  (x'5D9502F9'),
-  (x'5E1502F9'),
-  -- OutputLength
-  (x'3f99999a'),
-  (x'3f9d70a4'),
-  (x'3f9df3b6'),
-  (x'3f9e0419'),
-  (x'3f9e0610'),
-  (x'3f9e064b'),
-  (x'3f9e0651'),
-  (x'03d20cfe')
-)
-select float4send(flt) as ibits,
-       flt,
-       flt::text::float4 as r_flt,
-       float4send(flt::text::float4) as obits,
-       float4send(flt::text::float4) = float4send(flt) as correct
-  from (select bits::integer::xfloat4::float4 as flt
-          from testdata
-	offset 0) s;
-   ibits    |      flt       |     r_flt      |   obits    | correct 
-------------+----------------+----------------+------------+---------
- \x00000000 |              0 |              0 | \x00000000 | t
- \x00800000 |  1.1754944e-38 |  1.1754944e-38 | \x00800000 | t
- \x00800001 |  1.1754945e-38 |  1.1754945e-38 | \x00800001 | t
- \x00800004 |  1.1754949e-38 |  1.1754949e-38 | \x00800004 | t
- \x00800005 |   1.175495e-38 |   1.175495e-38 | \x00800005 | t
- \x00800006 |  1.1754952e-38 |  1.1754952e-38 | \x00800006 | t
- \x008002f1 |  1.1755999e-38 |  1.1755999e-38 | \x008002f1 | t
- \x008002f2 |     1.1756e-38 |     1.1756e-38 | \x008002f2 | t
- \x008002f3 |  1.1756001e-38 |  1.1756001e-38 | \x008002f3 | t
- \x00800e17 |  1.1759998e-38 |  1.1759998e-38 | \x00800e17 | t
- \x00800e18 |      1.176e-38 |      1.176e-38 | \x00800e18 | t
- \x00800e19 |  1.1760001e-38 |  1.1760001e-38 | \x00800e19 | t
- \x01000001 |   2.350989e-38 |   2.350989e-38 | \x01000001 | t
- \x01102843 |   2.647751e-38 |   2.647751e-38 | \x01102843 | t
- \x01a52c98 |  6.0675416e-38 |  6.0675416e-38 | \x01a52c98 | t
- \x0219c229 |  1.1296386e-37 |  1.1296386e-37 | \x0219c229 | t
- \x02e4464d |   3.354194e-37 |   3.354194e-37 | \x02e4464d | t
- \x037343c1 |   7.148906e-37 |   7.148906e-37 | \x037343c1 | t
- \x03a91b36 |   9.939175e-37 |   9.939175e-37 | \x03a91b36 | t
- \x047ada65 |   2.948764e-36 |   2.948764e-36 | \x047ada65 | t
- \x0496fe87 |  3.5498577e-36 |  3.5498577e-36 | \x0496fe87 | t
- \x0550844f |   9.804414e-36 |   9.804414e-36 | \x0550844f | t
- \x05999da3 |  1.4445957e-35 |  1.4445957e-35 | \x05999da3 | t
- \x060ea5e2 |  2.6829103e-35 |  2.6829103e-35 | \x060ea5e2 | t
- \x06e63c45 |   8.660494e-35 |   8.660494e-35 | \x06e63c45 | t
- \x07f1e548 |   3.639641e-34 |   3.639641e-34 | \x07f1e548 | t
- \x0fc5282b |  1.9441172e-29 |  1.9441172e-29 | \x0fc5282b | t
- \x1f850283 |  5.6331846e-20 |  5.6331846e-20 | \x1f850283 | t
- \x2874a9d6 |  1.3581548e-14 |  1.3581548e-14 | \x2874a9d6 | t
- \x3356bf94 |  4.9999997e-08 |  4.9999997e-08 | \x3356bf94 | t
- \x3356bf95 |          5e-08 |          5e-08 | \x3356bf95 | t
- \x3356bf96 |  5.0000004e-08 |  5.0000004e-08 | \x3356bf96 | t
- \x33d6bf94 |  9.9999994e-08 |  9.9999994e-08 | \x33d6bf94 | t
- \x33d6bf95 |          1e-07 |          1e-07 | \x33d6bf95 | t
- \x33d6bf96 |  1.0000001e-07 |  1.0000001e-07 | \x33d6bf96 | t
- \x34a10faf |  2.9999998e-07 |  2.9999998e-07 | \x34a10faf | t
- \x34a10fb0 |          3e-07 |          3e-07 | \x34a10fb0 | t
- \x34a10fb1 |  3.0000004e-07 |  3.0000004e-07 | \x34a10fb1 | t
- \x350637bc |  4.9999994e-07 |  4.9999994e-07 | \x350637bc | t
- \x350637bd |          5e-07 |          5e-07 | \x350637bd | t
- \x350637be |  5.0000006e-07 |  5.0000006e-07 | \x350637be | t
- \x35719786 |   8.999999e-07 |   8.999999e-07 | \x35719786 | t
- \x35719787 |          9e-07 |          9e-07 | \x35719787 | t
- \x35719788 |  9.0000003e-07 |  9.0000003e-07 | \x35719788 | t
- \x358637bc |   9.999999e-07 |   9.999999e-07 | \x358637bc | t
- \x358637bd |          1e-06 |          1e-06 | \x358637bd | t
- \x358637be |  1.0000001e-06 |  1.0000001e-06 | \x358637be | t
- \x36a7c5ab |  4.9999994e-06 |  4.9999994e-06 | \x36a7c5ab | t
- \x36a7c5ac |          5e-06 |          5e-06 | \x36a7c5ac | t
- \x36a7c5ad |  5.0000003e-06 |  5.0000003e-06 | \x36a7c5ad | t
- \x3727c5ab |   9.999999e-06 |   9.999999e-06 | \x3727c5ab | t
- \x3727c5ac |          1e-05 |          1e-05 | \x3727c5ac | t
- \x3727c5ad |  1.0000001e-05 |  1.0000001e-05 | \x3727c5ad | t
- \x38d1b714 |  9.9999976e-05 |  9.9999976e-05 | \x38d1b714 | t
- \x38d1b715 |   9.999998e-05 |   9.999998e-05 | \x38d1b715 | t
- \x38d1b716 |   9.999999e-05 |   9.999999e-05 | \x38d1b716 | t
- \x38d1b717 |         0.0001 |         0.0001 | \x38d1b717 | t
- \x38d1b718 | 0.000100000005 | 0.000100000005 | \x38d1b718 | t
- \x38d1b719 |  0.00010000001 |  0.00010000001 | \x38d1b719 | t
- \x38d1b71a |  0.00010000002 |  0.00010000002 | \x38d1b71a | t
- \x38d1b71b |  0.00010000003 |  0.00010000003 | \x38d1b71b | t
- \x38d1b71c | 0.000100000034 | 0.000100000034 | \x38d1b71c | t
- \x38d1b71d |  0.00010000004 |  0.00010000004 | \x38d1b71d | t
- \x38dffffe |  0.00010681151 |  0.00010681151 | \x38dffffe | t
- \x38dfffff | 0.000106811516 | 0.000106811516 | \x38dfffff | t
- \x38e00000 |  0.00010681152 |  0.00010681152 | \x38e00000 | t
- \x38efffff |  0.00011444091 |  0.00011444091 | \x38efffff | t
- \x38f00000 |  0.00011444092 |  0.00011444092 | \x38f00000 | t
- \x38f00001 | 0.000114440925 | 0.000114440925 | \x38f00001 | t
- \x3a83126e |   0.0009999999 |   0.0009999999 | \x3a83126e | t
- \x3a83126f |          0.001 |          0.001 | \x3a83126f | t
- \x3a831270 |   0.0010000002 |   0.0010000002 | \x3a831270 | t
- \x3c23d709 |    0.009999999 |    0.009999999 | \x3c23d709 | t
- \x3c23d70a |           0.01 |           0.01 | \x3c23d70a | t
- \x3c23d70b |    0.010000001 |    0.010000001 | \x3c23d70b | t
- \x3dcccccc |    0.099999994 |    0.099999994 | \x3dcccccc | t
- \x3dcccccd |            0.1 |            0.1 | \x3dcccccd | t
- \x3dccccce |     0.10000001 |     0.10000001 | \x3dccccce | t
- \x3dcccd6f |     0.10000121 |     0.10000121 | \x3dcccd6f | t
- \x3dcccd70 |    0.100001216 |    0.100001216 | \x3dcccd70 | t
- \x3dcccd71 |     0.10000122 |     0.10000122 | \x3dcccd71 | t
- \x3effffff |     0.49999997 |     0.49999997 | \x3effffff | t
- \x3f000000 |            0.5 |            0.5 | \x3f000000 | t
- \x3f000001 |     0.50000006 |     0.50000006 | \x3f000001 | t
- \x3f333332 |      0.6999999 |      0.6999999 | \x3f333332 | t
- \x3f333333 |            0.7 |            0.7 | \x3f333333 | t
- \x3f333334 |     0.70000005 |     0.70000005 | \x3f333334 | t
- \x3f666665 |      0.8999999 |      0.8999999 | \x3f666665 | t
- \x3f666666 |            0.9 |            0.9 | \x3f666666 | t
- \x3f666667 |     0.90000004 |     0.90000004 | \x3f666667 | t
- \x3f7d70a3 |     0.98999995 |     0.98999995 | \x3f7d70a3 | t
- \x3f7d70a4 |           0.99 |           0.99 | \x3f7d70a4 | t
- \x3f7d70a5 |     0.99000007 |     0.99000007 | \x3f7d70a5 | t
- \x3f7fbe76 |     0.99899995 |     0.99899995 | \x3f7fbe76 | t
- \x3f7fbe77 |          0.999 |          0.999 | \x3f7fbe77 | t
- \x3f7fbe78 |      0.9990001 |      0.9990001 | \x3f7fbe78 | t
- \x3f7ff971 |      0.9998999 |      0.9998999 | \x3f7ff971 | t
- \x3f7ff972 |         0.9999 |         0.9999 | \x3f7ff972 | t
- \x3f7ff973 |     0.99990004 |     0.99990004 | \x3f7ff973 | t
- \x3f7fff57 |      0.9999899 |      0.9999899 | \x3f7fff57 | t
- \x3f7fff58 |        0.99999 |        0.99999 | \x3f7fff58 | t
- \x3f7fff59 |     0.99999005 |     0.99999005 | \x3f7fff59 | t
- \x3f7fffee |      0.9999989 |      0.9999989 | \x3f7fffee | t
- \x3f7fffef |       0.999999 |       0.999999 | \x3f7fffef | t
- \x3f7ffff0 |     0.99999905 |     0.99999905 | \x3f7ffff0 | t
- \x3f7ffff1 |      0.9999991 |      0.9999991 | \x3f7ffff1 | t
- \x3f7ffff2 |     0.99999917 |     0.99999917 | \x3f7ffff2 | t
- \x3f7ffff3 |      0.9999992 |      0.9999992 | \x3f7ffff3 | t
- \x3f7ffff4 |      0.9999993 |      0.9999993 | \x3f7ffff4 | t
- \x3f7ffff5 |     0.99999934 |     0.99999934 | \x3f7ffff5 | t
- \x3f7ffff6 |      0.9999994 |      0.9999994 | \x3f7ffff6 | t
- \x3f7ffff7 |     0.99999946 |     0.99999946 | \x3f7ffff7 | t
- \x3f7ffff8 |      0.9999995 |      0.9999995 | \x3f7ffff8 | t
- \x3f7ffff9 |      0.9999996 |      0.9999996 | \x3f7ffff9 | t
- \x3f7ffffa |     0.99999964 |     0.99999964 | \x3f7ffffa | t
- \x3f7ffffb |      0.9999997 |      0.9999997 | \x3f7ffffb | t
- \x3f7ffffc |     0.99999976 |     0.99999976 | \x3f7ffffc | t
- \x3f7ffffd |      0.9999998 |      0.9999998 | \x3f7ffffd | t
- \x3f7ffffe |      0.9999999 |      0.9999999 | \x3f7ffffe | t
- \x3f7fffff |     0.99999994 |     0.99999994 | \x3f7fffff | t
- \x3f800000 |              1 |              1 | \x3f800000 | t
- \x3f800001 |      1.0000001 |      1.0000001 | \x3f800001 | t
- \x3f800002 |      1.0000002 |      1.0000002 | \x3f800002 | t
- \x3f800003 |      1.0000004 |      1.0000004 | \x3f800003 | t
- \x3f800004 |      1.0000005 |      1.0000005 | \x3f800004 | t
- \x3f800005 |      1.0000006 |      1.0000006 | \x3f800005 | t
- \x3f800006 |      1.0000007 |      1.0000007 | \x3f800006 | t
- \x3f800007 |      1.0000008 |      1.0000008 | \x3f800007 | t
- \x3f800008 |       1.000001 |       1.000001 | \x3f800008 | t
- \x3f800009 |      1.0000011 |      1.0000011 | \x3f800009 | t
- \x3f80000f |      1.0000018 |      1.0000018 | \x3f80000f | t
- \x3f800010 |      1.0000019 |      1.0000019 | \x3f800010 | t
- \x3f800011 |       1.000002 |       1.000002 | \x3f800011 | t
- \x3f800012 |      1.0000021 |      1.0000021 | \x3f800012 | t
- \x3f800013 |      1.0000023 |      1.0000023 | \x3f800013 | t
- \x3f800014 |      1.0000024 |      1.0000024 | \x3f800014 | t
- \x3f800017 |      1.0000027 |      1.0000027 | \x3f800017 | t
- \x3f800018 |      1.0000029 |      1.0000029 | \x3f800018 | t
- \x3f800019 |       1.000003 |       1.000003 | \x3f800019 | t
- \x3f80001a |      1.0000031 |      1.0000031 | \x3f80001a | t
- \x3f80001b |      1.0000032 |      1.0000032 | \x3f80001b | t
- \x3f80001c |      1.0000033 |      1.0000033 | \x3f80001c | t
- \x3f800029 |      1.0000049 |      1.0000049 | \x3f800029 | t
- \x3f80002a |       1.000005 |       1.000005 | \x3f80002a | t
- \x3f80002b |      1.0000051 |      1.0000051 | \x3f80002b | t
- \x3f800053 |      1.0000099 |      1.0000099 | \x3f800053 | t
- \x3f800054 |        1.00001 |        1.00001 | \x3f800054 | t
- \x3f800055 |      1.0000101 |      1.0000101 | \x3f800055 | t
- \x3f800346 |      1.0000999 |      1.0000999 | \x3f800346 | t
- \x3f800347 |         1.0001 |         1.0001 | \x3f800347 | t
- \x3f800348 |      1.0001001 |      1.0001001 | \x3f800348 | t
- \x3f8020c4 |      1.0009999 |      1.0009999 | \x3f8020c4 | t
- \x3f8020c5 |          1.001 |          1.001 | \x3f8020c5 | t
- \x3f8020c6 |      1.0010002 |      1.0010002 | \x3f8020c6 | t
- \x3f8147ad |      1.0099999 |      1.0099999 | \x3f8147ad | t
- \x3f8147ae |           1.01 |           1.01 | \x3f8147ae | t
- \x3f8147af |      1.0100001 |      1.0100001 | \x3f8147af | t
- \x3f8ccccc |      1.0999999 |      1.0999999 | \x3f8ccccc | t
- \x3f8ccccd |            1.1 |            1.1 | \x3f8ccccd | t
- \x3f8cccce |      1.1000001 |      1.1000001 | \x3f8cccce | t
- \x3fc90fdb |      1.5707964 |      1.5707964 | \x3fc90fdb | t
- \x402df854 |      2.7182817 |      2.7182817 | \x402df854 | t
- \x40490fdb |      3.1415927 |      3.1415927 | \x40490fdb | t
- \x409fffff |      4.9999995 |      4.9999995 | \x409fffff | t
- \x40a00000 |              5 |              5 | \x40a00000 | t
- \x40a00001 |      5.0000005 |      5.0000005 | \x40a00001 | t
- \x40afffff |      5.4999995 |      5.4999995 | \x40afffff | t
- \x40b00000 |            5.5 |            5.5 | \x40b00000 | t
- \x40b00001 |      5.5000005 |      5.5000005 | \x40b00001 | t
- \x411fffff |       9.999999 |       9.999999 | \x411fffff | t
- \x41200000 |             10 |             10 | \x41200000 | t
- \x41200001 |      10.000001 |      10.000001 | \x41200001 | t
- \x42c7ffff |       99.99999 |       99.99999 | \x42c7ffff | t
- \x42c80000 |            100 |            100 | \x42c80000 | t
- \x42c80001 |      100.00001 |      100.00001 | \x42c80001 | t
- \x4479ffff |      999.99994 |      999.99994 | \x4479ffff | t
- \x447a0000 |           1000 |           1000 | \x447a0000 | t
- \x447a0001 |     1000.00006 |     1000.00006 | \x447a0001 | t
- \x461c3fff |       9999.999 |       9999.999 | \x461c3fff | t
- \x461c4000 |          10000 |          10000 | \x461c4000 | t
- \x461c4001 |      10000.001 |      10000.001 | \x461c4001 | t
- \x47c34fff |       99999.99 |       99999.99 | \x47c34fff | t
- \x47c35000 |         100000 |         100000 | \x47c35000 | t
- \x47c35001 |      100000.01 |      100000.01 | \x47c35001 | t
- \x497423ff |      999999.94 |      999999.94 | \x497423ff | t
- \x49742400 |          1e+06 |          1e+06 | \x49742400 | t
- \x49742401 | 1.00000006e+06 | 1.00000006e+06 | \x49742401 | t
- \x4b18967f |   9.999999e+06 |   9.999999e+06 | \x4b18967f | t
- \x4b189680 |          1e+07 |          1e+07 | \x4b189680 | t
- \x4b189681 |  1.0000001e+07 |  1.0000001e+07 | \x4b189681 | t
- \x4cbebc1f |   9.999999e+07 |   9.999999e+07 | \x4cbebc1f | t
- \x4cbebc20 |          1e+08 |          1e+08 | \x4cbebc20 | t
- \x4cbebc21 |  1.0000001e+08 |  1.0000001e+08 | \x4cbebc21 | t
- \x4e6e6b27 |  9.9999994e+08 |  9.9999994e+08 | \x4e6e6b27 | t
- \x4e6e6b28 |          1e+09 |          1e+09 | \x4e6e6b28 | t
- \x4e6e6b29 | 1.00000006e+09 | 1.00000006e+09 | \x4e6e6b29 | t
- \x501502f8 |   9.999999e+09 |   9.999999e+09 | \x501502f8 | t
- \x501502f9 |          1e+10 |          1e+10 | \x501502f9 | t
- \x501502fa |  1.0000001e+10 |  1.0000001e+10 | \x501502fa | t
- \x51ba43b6 |   9.999999e+10 |   9.999999e+10 | \x51ba43b6 | t
- \x51ba43b7 |          1e+11 |          1e+11 | \x51ba43b7 | t
- \x51ba43b8 |  1.0000001e+11 |  1.0000001e+11 | \x51ba43b8 | t
- \x1f6c1e4a |          5e-20 |          5e-20 | \x1f6c1e4a | t
- \x59be6cea |        6.7e+15 |        6.7e+15 | \x59be6cea | t
- \x5d5ab6c4 |       9.85e+17 |       9.85e+17 | \x5d5ab6c4 | t
- \x2cc4a9bd |     5.5895e-12 |     5.5895e-12 | \x2cc4a9bd | t
- \x15ae43fd |   7.038531e-26 |  7.0385313e-26 | \x15ae43fe | f
- \x2cf757ca |  7.0299088e-12 |  7.0299088e-12 | \x2cf757ca | t
- \x665ba998 |  2.5933168e+23 |  2.5933168e+23 | \x665ba998 | t
- \x743c3324 |  5.9642887e+31 |  5.9642887e+31 | \x743c3324 | t
- \x47f1205a |       123456.7 |       123456.7 | \x47f1205a | t
- \x4640e6ae |       12345.67 |       12345.67 | \x4640e6ae | t
- \x449a5225 |       1234.567 |       1234.567 | \x449a5225 | t
- \x42f6e9d5 |       123.4567 |       123.4567 | \x42f6e9d5 | t
- \x414587dd |       12.34567 |       12.34567 | \x414587dd | t
- \x3f9e064b |       1.234567 |       1.234567 | \x3f9e064b | t
- \x4c000004 |  3.3554448e+07 |  3.3554448e+07 | \x4c000004 | t
- \x50061c46 |   8.999999e+09 |   8.999999e+09 | \x50061c46 | t
- \x510006a8 |  3.4366718e+10 |  3.4366718e+10 | \x510006a8 | t
- \x48951f84 |      305404.12 |      305404.12 | \x48951f84 | t
- \x45fd1840 |      8099.0312 |      8099.0312 | \x45fd1840 | t
- \x39800000 |  0.00024414062 |  0.00024414062 | \x39800000 | t
- \x3b200000 |   0.0024414062 |   0.0024414062 | \x3b200000 | t
- \x3b900000 |   0.0043945312 |   0.0043945312 | \x3b900000 | t
- \x3bd00000 |   0.0063476562 |   0.0063476562 | \x3bd00000 | t
- \x63800000 |  4.7223665e+21 |  4.7223665e+21 | \x63800000 | t
- \x4b000000 |   8.388608e+06 |   8.388608e+06 | \x4b000000 | t
- \x4b800000 |  1.6777216e+07 |  1.6777216e+07 | \x4b800000 | t
- \x4c000001 |  3.3554436e+07 |  3.3554436e+07 | \x4c000001 | t
- \x4c800b0d |  6.7131496e+07 |  6.7131496e+07 | \x4c800b0d | t
- \x00d24584 |  1.9310392e-38 |  1.9310392e-38 | \x00d24584 | t
- \x00d90b88 |   1.993244e-38 |   1.993244e-38 | \x00d90b88 | t
- \x45803f34 |      4103.9004 |      4103.9004 | \x45803f34 | t
- \x4f9f24f7 |  5.3399997e+09 |  5.3399997e+09 | \x4f9f24f7 | t
- \x3a8722c3 |   0.0010310042 |   0.0010310042 | \x3a8722c3 | t
- \x5c800041 |   2.882326e+17 |   2.882326e+17 | \x5c800041 | t
- \x15ae43fd |   7.038531e-26 |  7.0385313e-26 | \x15ae43fe | f
- \x5d4cccfb |   9.223404e+17 |   9.223404e+17 | \x5d4cccfb | t
- \x4c800001 |   6.710887e+07 |   6.710887e+07 | \x4c800001 | t
- \x57800ed8 |   2.816025e+14 |   2.816025e+14 | \x57800ed8 | t
- \x5f000000 |   9.223372e+18 |   9.223372e+18 | \x5f000000 | t
- \x700000f0 |  1.5846086e+29 |  1.5846086e+29 | \x700000f0 | t
- \x5f23e9ac |  1.1811161e+19 |  1.1811161e+19 | \x5f23e9ac | t
- \x5e9502f9 |   5.368709e+18 |   5.368709e+18 | \x5e9502f9 | t
- \x5e8012b1 |  4.6143166e+18 |  4.6143166e+18 | \x5e8012b1 | t
- \x3c000028 |    0.007812537 |    0.007812537 | \x3c000028 | t
- \x60cde861 | 1.18697725e+20 | 1.18697725e+20 | \x60cde861 | t
- \x03aa2a50 | 1.00014165e-36 | 1.00014165e-36 | \x03aa2a50 | t
- \x43480000 |            200 |            200 | \x43480000 | t
- \x4c000000 |  3.3554432e+07 |  3.3554432e+07 | \x4c000000 | t
- \x5d1502f9 |  6.7108864e+17 |  6.7108864e+17 | \x5d1502f9 | t
- \x5d9502f9 |  1.3421773e+18 |  1.3421773e+18 | \x5d9502f9 | t
- \x5e1502f9 |  2.6843546e+18 |  2.6843546e+18 | \x5e1502f9 | t
- \x3f99999a |            1.2 |            1.2 | \x3f99999a | t
- \x3f9d70a4 |           1.23 |           1.23 | \x3f9d70a4 | t
- \x3f9df3b6 |          1.234 |          1.234 | \x3f9df3b6 | t
- \x3f9e0419 |         1.2345 |         1.2345 | \x3f9e0419 | t
- \x3f9e0610 |        1.23456 |        1.23456 | \x3f9e0610 | t
- \x3f9e064b |       1.234567 |       1.234567 | \x3f9e064b | t
- \x3f9e0651 |      1.2345678 |      1.2345678 | \x3f9e0651 | t
- \x03d20cfe | 1.23456735e-36 | 1.23456735e-36 | \x03d20cfe | t
-(261 rows)
-
--- clean up, lest opr_sanity complain
-drop type xfloat4 cascade;
-NOTICE:  drop cascades to 6 other objects
-DETAIL:  drop cascades to function xfloat4in(cstring)
-drop cascades to function xfloat4out(xfloat4)
-drop cascades to cast from xfloat4 to real
-drop cascades to cast from real to xfloat4
-drop cascades to cast from xfloat4 to integer
-drop cascades to cast from integer to xfloat4
diff --git a/src/test/regress/resultmap b/src/test/regress/resultmap
index 9ccc08c7cf3..e69de29bb2d 100644
--- a/src/test/regress/resultmap
+++ b/src/test/regress/resultmap
@@ -1 +0,0 @@
-float4:out:.*-.*-cygwin.*=float4-misrounded-input.out
-- 
2.51.2

v2-0003-Drop-resultmap-mechanism-from-pg_regress.patchtext/x-patch; charset=US-ASCII; name=v2-0003-Drop-resultmap-mechanism-from-pg_regress.patchDownload
From c2d1b3056d20d3878cbec04b52c48f8cc376e801 Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@gmail.com>
Date: Mon, 24 Nov 2025 07:35:02 +1300
Subject: [PATCH v2 3/3] Drop resultmap mechanism from pg_regress.

This was used to tolerate historical per-platform broken strtof()
implementations, but those are now gone.  Retain only the "automatic"
variation mechanism for alternative expected files.

Discussion: https://postgr.es/m/CA%2BhUKGJ0J-H8C51HK8pEGdbD7tVuut5igkRhFt0byWm_CezeoQ%40mail.gmail.com
---
 doc/src/sgml/regress.sgml        |  41 +-----
 src/test/regress/GNUmakefile     |   3 +-
 src/test/regress/meson.build     |   4 +-
 src/test/regress/pg_regress.c    | 244 -------------------------------
 src/tools/pgindent/typedefs.list |   1 -
 5 files changed, 6 insertions(+), 287 deletions(-)

diff --git a/doc/src/sgml/regress.sgml b/doc/src/sgml/regress.sgml
index 160f38bef9e..5ae7f4b01e2 100644
--- a/doc/src/sgml/regress.sgml
+++ b/doc/src/sgml/regress.sgml
@@ -750,43 +750,13 @@ diff results/random.out expected/random.out
 
    <para>
     Since some of the tests inherently produce environment-dependent
-    results, we have provided ways to specify alternate <quote>expected</quote>
+    results, we have provided a way to specify alternate <quote>expected</quote>
     result files.  Each regression test can have several comparison files
-    showing possible results on different platforms.  There are two
-    independent mechanisms for determining which comparison file is used
-    for each test.
+    showing possible results on different platforms.
    </para>
 
    <para>
-    The first mechanism allows comparison files to be selected for
-    specific platforms.  There is a mapping file,
-    <filename>src/test/regress/resultmap</filename>, that defines
-    which comparison file to use for each platform.
-    To eliminate bogus test <quote>failures</quote> for a particular platform,
-    you first choose or make a variant result file, and then add a line to the
-    <filename>resultmap</filename> file.
-   </para>
-
-   <para>
-    Each line in the mapping file is of the form
-<synopsis>
-testname:output:platformpattern=comparisonfilename
-</synopsis>
-    The test name is just the name of the particular regression test
-    module. The output value indicates which output file to check. For the
-    standard regression tests, this is always <literal>out</literal>. The
-    value corresponds to the file extension of the output file.
-    The platform pattern is a pattern in the style of the Unix
-    tool <command>expr</command> (that is, a regular expression with an implicit
-    <literal>^</literal> anchor at the start).  It is matched against the
-    platform name as printed by <command>config.guess</command>.
-    The comparison file name is the base name of the substitute result
-    comparison file.
-   </para>
-
-   <para>
-    The second selection mechanism for variant comparison files is
-    much more automatic: it simply uses the <quote>best match</quote> among
+    The selection mechanism uses the <quote>best match</quote> among
     several supplied comparison files.  The regression test driver
     script considers both the standard comparison file for a test,
     <literal><replaceable>testname</replaceable>.out</literal>, and variant files named
@@ -794,10 +764,7 @@ testname:output:platformpattern=comparisonfilename
     (where the <replaceable>digit</replaceable> is any single digit
     <literal>0</literal>-<literal>9</literal>).  If any such file is an exact match,
     the test is considered to pass; otherwise, the one that generates
-    the shortest diff is used to create the failure report.  (If
-    <filename>resultmap</filename> includes an entry for the particular
-    test, then the base <replaceable>testname</replaceable> is the substitute
-    name given in <filename>resultmap</filename>.)
+    the shortest diff is used to create the failure report.
    </para>
 
    <para>
diff --git a/src/test/regress/GNUmakefile b/src/test/regress/GNUmakefile
index ef2bddf42ca..f718c8030e5 100644
--- a/src/test/regress/GNUmakefile
+++ b/src/test/regress/GNUmakefile
@@ -74,8 +74,7 @@ $(OBJS): | submake-libpgport submake-generated-headers
 regress_data_files = \
 	$(wildcard $(srcdir)/sql/*.sql) \
 	$(wildcard $(srcdir)/expected/*.out) \
-	$(wildcard $(srcdir)/data/*.data) \
-	$(srcdir)/parallel_schedule $(srcdir)/resultmap
+	$(wildcard $(srcdir)/data/*.data)
 
 install-tests: all install install-lib installdirs-tests
 	$(MAKE) -C $(top_builddir)/contrib/spi install
diff --git a/src/test/regress/meson.build b/src/test/regress/meson.build
index 1da9e9462a9..651556c8d57 100644
--- a/src/test/regress/meson.build
+++ b/src/test/regress/meson.build
@@ -8,9 +8,7 @@ regress_sources = pg_regress_c + files(
   'pg_regress_main.c'
 )
 
-# Need make up something roughly like x86_64-pc-mingw64. resultmap matches on
-# patterns like ".*-.*-mingw.*". We probably can do better, but for now just
-# replace 'gcc' with 'mingw' on windows.
+# Need make up something roughly like x86_64-pc-mingw64.
 host_tuple_cc = cc.get_id()
 if host_system == 'windows' and host_tuple_cc == 'gcc'
   host_tuple_cc = 'mingw'
diff --git a/src/test/regress/pg_regress.c b/src/test/regress/pg_regress.c
index efc41fca2ba..4e447d4867a 100644
--- a/src/test/regress/pg_regress.c
+++ b/src/test/regress/pg_regress.c
@@ -37,15 +37,6 @@
 #include "pg_regress.h"
 #include "portability/instr_time.h"
 
-/* for resultmap we need a list of pairs of strings */
-typedef struct _resultmap
-{
-	char	   *test;
-	char	   *type;
-	char	   *resultfile;
-	struct _resultmap *next;
-} _resultmap;
-
 /*
  * Values obtained from Makefile.
  */
@@ -132,8 +123,6 @@ static char socklock[MAXPGPATH];
 static StringInfo failed_tests = NULL;
 static bool in_note = false;
 
-static _resultmap *resultmap = NULL;
-
 static PID_TYPE postmaster_pid = INVALID_PID;
 static bool postmaster_running = false;
 
@@ -530,192 +519,6 @@ make_temp_sockdir(void)
 	return temp_sockdir;
 }
 
-/*
- * Check whether string matches pattern
- *
- * In the original shell script, this function was implemented using expr(1),
- * which provides basic regular expressions restricted to match starting at
- * the string start (in conventional regex terms, there's an implicit "^"
- * at the start of the pattern --- but no implicit "$" at the end).
- *
- * For now, we only support "." and ".*" as non-literal metacharacters,
- * because that's all that anyone has found use for in resultmap.  This
- * code could be extended if more functionality is needed.
- */
-static bool
-string_matches_pattern(const char *str, const char *pattern)
-{
-	while (*str && *pattern)
-	{
-		if (*pattern == '.' && pattern[1] == '*')
-		{
-			pattern += 2;
-			/* Trailing .* matches everything. */
-			if (*pattern == '\0')
-				return true;
-
-			/*
-			 * Otherwise, scan for a text position at which we can match the
-			 * rest of the pattern.
-			 */
-			while (*str)
-			{
-				/*
-				 * Optimization to prevent most recursion: don't recurse
-				 * unless first pattern char might match this text char.
-				 */
-				if (*str == *pattern || *pattern == '.')
-				{
-					if (string_matches_pattern(str, pattern))
-						return true;
-				}
-
-				str++;
-			}
-
-			/*
-			 * End of text with no match.
-			 */
-			return false;
-		}
-		else if (*pattern != '.' && *str != *pattern)
-		{
-			/*
-			 * Not the single-character wildcard and no explicit match? Then
-			 * time to quit...
-			 */
-			return false;
-		}
-
-		str++;
-		pattern++;
-	}
-
-	if (*pattern == '\0')
-		return true;			/* end of pattern, so declare match */
-
-	/* End of input string.  Do we have matching pattern remaining? */
-	while (*pattern == '.' && pattern[1] == '*')
-		pattern += 2;
-	if (*pattern == '\0')
-		return true;			/* end of pattern, so declare match */
-
-	return false;
-}
-
-/*
- * Scan resultmap file to find which platform-specific expected files to use.
- *
- * The format of each line of the file is
- *		   testname/hostplatformpattern=substitutefile
- * where the hostplatformpattern is evaluated per the rules of expr(1),
- * namely, it is a standard regular expression with an implicit ^ at the start.
- * (We currently support only a very limited subset of regular expressions,
- * see string_matches_pattern() above.)  What hostplatformpattern will be
- * matched against is the config.guess output.  (In the shell-script version,
- * we also provided an indication of whether gcc or another compiler was in
- * use, but that facility isn't used anymore.)
- */
-static void
-load_resultmap(void)
-{
-	char		buf[MAXPGPATH];
-	FILE	   *f;
-
-	/* scan the file ... */
-	snprintf(buf, sizeof(buf), "%s/resultmap", inputdir);
-	f = fopen(buf, "r");
-	if (!f)
-	{
-		/* OK if it doesn't exist, else complain */
-		if (errno == ENOENT)
-			return;
-		bail("could not open file \"%s\" for reading: %m", buf);
-	}
-
-	while (fgets(buf, sizeof(buf), f))
-	{
-		char	   *platform;
-		char	   *file_type;
-		char	   *expected;
-		int			i;
-
-		/* strip trailing whitespace, especially the newline */
-		i = strlen(buf);
-		while (i > 0 && isspace((unsigned char) buf[i - 1]))
-			buf[--i] = '\0';
-
-		/* parse out the line fields */
-		file_type = strchr(buf, ':');
-		if (!file_type)
-		{
-			bail("incorrectly formatted resultmap entry: %s", buf);
-		}
-		*file_type++ = '\0';
-
-		platform = strchr(file_type, ':');
-		if (!platform)
-		{
-			bail("incorrectly formatted resultmap entry: %s", buf);
-		}
-		*platform++ = '\0';
-		expected = strchr(platform, '=');
-		if (!expected)
-		{
-			bail("incorrectly formatted resultmap entry: %s", buf);
-		}
-		*expected++ = '\0';
-
-		/*
-		 * if it's for current platform, save it in resultmap list. Note: by
-		 * adding at the front of the list, we ensure that in ambiguous cases,
-		 * the last match in the resultmap file is used. This mimics the
-		 * behavior of the old shell script.
-		 */
-		if (string_matches_pattern(host_platform, platform))
-		{
-			_resultmap *entry = pg_malloc(sizeof(_resultmap));
-
-			entry->test = pg_strdup(buf);
-			entry->type = pg_strdup(file_type);
-			entry->resultfile = pg_strdup(expected);
-			entry->next = resultmap;
-			resultmap = entry;
-		}
-	}
-	fclose(f);
-}
-
-/*
- * Check in resultmap if we should be looking at a different file
- */
-static
-const char *
-get_expectfile(const char *testname, const char *file)
-{
-	char	   *file_type;
-	_resultmap *rm;
-
-	/*
-	 * Determine the file type from the file name. This is just what is
-	 * following the last dot in the file name.
-	 */
-	if (!file || !(file_type = strrchr(file, '.')))
-		return NULL;
-
-	file_type++;
-
-	for (rm = resultmap; rm != NULL; rm = rm->next)
-	{
-		if (strcmp(testname, rm->test) == 0 && strcmp(file_type, rm->type) == 0)
-		{
-			return rm->resultfile;
-		}
-	}
-
-	return NULL;
-}
-
 /*
  * Prepare environment variables for running regression tests
  */
@@ -917,8 +720,6 @@ initialize_environment(void)
 		if (!pghost && !pgport)
 			note("using postmaster on Unix socket, default port");
 	}
-
-	load_resultmap();
 }
 
 #ifdef ENABLE_SSPI
@@ -1414,26 +1215,8 @@ results_differ(const char *testname, const char *resultsfile, const char *defaul
 	int			best_line_count;
 	int			i;
 	int			l;
-	const char *platform_expectfile;
-
-	/*
-	 * We can pass either the resultsfile or the expectfile, they should have
-	 * the same type (filename.type) anyway.
-	 */
-	platform_expectfile = get_expectfile(testname, resultsfile);
 
 	strlcpy(expectfile, default_expectfile, sizeof(expectfile));
-	if (platform_expectfile)
-	{
-		/*
-		 * Replace everything after the last slash in expectfile with what the
-		 * platform_expectfile contains.
-		 */
-		char	   *p = strrchr(expectfile, '/');
-
-		if (p)
-			strcpy(++p, platform_expectfile);
-	}
 
 	/* Name to use for temporary diff file */
 	snprintf(diff, sizeof(diff), "%s.diff", resultsfile);
@@ -1489,33 +1272,6 @@ results_differ(const char *testname, const char *resultsfile, const char *defaul
 		free(alt_expectfile);
 	}
 
-	/*
-	 * fall back on the canonical results file if we haven't tried it yet and
-	 * haven't found a complete match yet.
-	 */
-
-	if (platform_expectfile)
-	{
-		snprintf(cmd, sizeof(cmd),
-				 "diff %s \"%s\" \"%s\" > \"%s\"",
-				 basic_diff_opts, default_expectfile, resultsfile, diff);
-
-		if (run_diff(cmd, diff) == 0)
-		{
-			/* No diff = no changes = good */
-			unlink(diff);
-			return false;
-		}
-
-		l = file_line_count(diff);
-		if (l < best_line_count)
-		{
-			/* This diff was a better match than the last one */
-			best_line_count = l;
-			strlcpy(best_expect_file, default_expectfile, sizeof(best_expect_file));
-		}
-	}
-
 	/*
 	 * Use the best comparison file to generate the "pretty" diff, which we
 	 * append to the diffs summary file.
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 27a4d131897..013018b6435 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -3416,7 +3416,6 @@ __time64_t
 _dev_t
 _ino_t
 _locale_t
-_resultmap
 _stringlist
 access_vector_t
 acquireLocksOnSubLinks_context
-- 
2.51.2

#22Peter Eisentraut
peter@eisentraut.org
In reply to: Thomas Munro (#21)
Re: PRI?64 vs Visual Studio (2022)

On 24.11.25 00:03, Thomas Munro wrote:

On Sun, Nov 23, 2025 at 4:25 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:

Thomas Munro <thomas.munro@gmail.com> writes:

That'd leave only Cygwin with HAVE BUGGY_STRTOF. Perhaps they have
fixed their implementation[1]? Here's an experimental patch to drop
all remnants, which could be used to find out. No Windows/Cygwin
here. Hmm, what if we just commit it anyway? If their strtof() is
still broken and someone out there is running the tests and sees this
test fail, why shouldn't they take that up with libc at this stage?

Hmm, we could get rid of the whole resultmap mechanism ...

Yeah. I thought I'd see what blowback my
if-Cygwin-strtof()-really-is-still-broken-they-should-fix-it argument
attracted before spending the time to nuke all those lines too.
Here's that patch. We could always revert resultmap we found a new
reason to need it, but I hope we wouldn't.

These patches look sensible to me.

Maybe wait a bit to see if Andrew can manually reproduce the issue one
way or the other on Cygwin.

Otherwise, I'd say go for it.

#23Tom Lane
tgl@sss.pgh.pa.us
In reply to: Thomas Munro (#12)
Re: PRI?64 vs Visual Studio (2022)

Thomas Munro <thomas.munro@gmail.com> writes:

The reason I thought about a contrived message with lots of macros is
that I'd stumbled across a partial implementation[1] in Alpine's
alternative non-GNU msgfmt program, which appears to have PRIu64 but
not PRIx64 and others. It also has some other way of encoding this
stuff in the .mo that musl's alternative built-in libintl
implementation can understand (it looks like they have arranged to be
able to mmap the .mo and use it directly as shared read-only memory,
while GNU's implementation has to allocate memory to translate them to
%lld etc in every process, clever but (I assume) broken if
msgfmt/libintl implementations are mixed), so I figured it'd be a good
idea to make sure that we test that all the macros actually work. I
didn't try to understand the implications of Wolfgang's reply, but I
guess that to have any chance of Alpine's libintl pickle being
straightened out, we'd ideally want a test case that someone
interested in that could use to validate the whole localisation
pipeline conclusively.

So now we have that, and sure enough our two Alpine buildfarm members
are failing like this [1]https://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=basilisk&amp;dt=2025-12-15%2004%3A35%3A44[2]https://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=dogfish&amp;dt=2025-12-15%2005%3A19%3A50:

diff -U3 /mnt/build/HEAD/pgsql/src/test/regress/expected/nls_1.out /mnt/build/HEAD/pgsql.build/testrun/regress/regress/results/nls.out
--- /mnt/build/HEAD/pgsql/src/test/regress/expected/nls_1.out
+++ /mnt/build/HEAD/pgsql.build/testrun/regress/regress/results/nls.out
@@ -34,7 +34,22 @@
 \\quit
 \\endif
 SELECT test_translation();
-NOTICE:  NLS is not enabled
+NOTICE:  translated PRId64 = 424242424242
+NOTICE:  translated PRId32 = -1234
+NOTICE:  translated PRIdMAX = -5678
+NOTICE:  translated PRIdPTR = 9999
+NOTICE:  traducido PRIu64 = 424242424242
+NOTICE:  traducido PRIu32 = 1234
+NOTICE:  translated PRIuMAX = 5678
+NOTICE:  translated PRIuPTR = 9999
+NOTICE:  translated PRIx64 = 62c6d1a9b2
+NOTICE:  translated PRIx32 = 4d2
+NOTICE:  translated PRIxMAX = 162e
+NOTICE:  translated PRIxPTR = 270f
+NOTICE:  translated PRIX64 = 62C6D1A9B2
+NOTICE:  translated PRIX32 = 4D2
+NOTICE:  translated PRIXMAX = 162E
+NOTICE:  translated PRIXPTR = 270F
  test_translation 
 ------------------

So their gettext handles PRIu64 and PRIu32 and nothing else.

What to do now? I could revert 8c498479d and followups, but
I sure don't want to. A stopgap measure to make the farm look
green would be to add a variant expected-file that accepts
this output, but yech. Thoughts?

regards, tom lane

[1]: https://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=basilisk&amp;dt=2025-12-15%2004%3A35%3A44
[2]: https://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=dogfish&amp;dt=2025-12-15%2005%3A19%3A50

#24Thomas Munro
thomas.munro@gmail.com
In reply to: Tom Lane (#23)
Re: PRI?64 vs Visual Studio (2022)

On Mon, Dec 15, 2025 at 8:01 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:

So their gettext handles PRIu64 and PRIu32 and nothing else.

Hah, I had predicted that three would work. Off by one.

What to do now? I could revert 8c498479d and followups, but
I sure don't want to. A stopgap measure to make the farm look
green would be to add a variant expected-file that accepts
this output, but yech. Thoughts?

So close yet so far... I tried asking if it's easy to fix:

https://github.com/sabotage-linux/gettext-tiny/issues/76

#25Tom Lane
tgl@sss.pgh.pa.us
In reply to: Thomas Munro (#24)
Re: PRI?64 vs Visual Studio (2022)

Thomas Munro <thomas.munro@gmail.com> writes:

On Mon, Dec 15, 2025 at 8:01 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:

What to do now? I could revert 8c498479d and followups, but
I sure don't want to. A stopgap measure to make the farm look
green would be to add a variant expected-file that accepts
this output, but yech. Thoughts?

So close yet so far... I tried asking if it's easy to fix:

https://github.com/sabotage-linux/gettext-tiny/issues/76

Hmm, not sure if you found the live upstream for that project, but if
you did, this code hasn't been touched since 2019. Think we shouldn't
hold our breath for a fix :-(. I will go add another expected-file.

I'm also thinking that maybe we should expand the ambition of that
test script a little. Instead of only checking the behavior of PRI*
when we can test translation, why not run the ereport's all the time?
This would at least test that <inttypes.h> is sane and snprintf.c
agrees with it, which we now know is something worth checking. That's
colored by seeing that less than half of the buildfarm is finding any
variant of es_ES to test in. That's not great, but I'm not seeing
anything to be done about it. The only locale names we can be sure
will be accepted are C/POSIX, and I'd expect gettext() to
short-circuit that case and not look for a translation. I'm thinking
though that it's still worth checking that the untranslated string is
processed correctly.

regards, tom lane

#26Bryan Green
dbryan.green@gmail.com
In reply to: Tom Lane (#25)
Re: PRI?64 vs Visual Studio (2022)

On 12/15/2025 11:05 AM, Tom Lane wrote:

Thomas Munro <thomas.munro@gmail.com> writes:

On Mon, Dec 15, 2025 at 8:01 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:

What to do now? I could revert 8c498479d and followups, but
I sure don't want to. A stopgap measure to make the farm look
green would be to add a variant expected-file that accepts
this output, but yech. Thoughts?

So close yet so far... I tried asking if it's easy to fix:

https://github.com/sabotage-linux/gettext-tiny/issues/76

Hmm, not sure if you found the live upstream for that project, but if
you did, this code hasn't been touched since 2019. Think we shouldn't
hold our breath for a fix :-(. I will go add another expected-file.

I'm also thinking that maybe we should expand the ambition of that
test script a little. Instead of only checking the behavior of PRI*
when we can test translation, why not run the ereport's all the time?
This would at least test that <inttypes.h> is sane and snprintf.c
agrees with it, which we now know is something worth checking. That's
colored by seeing that less than half of the buildfarm is finding any
variant of es_ES to test in. That's not great, but I'm not seeing
anything to be done about it. The only locale names we can be sure
will be accepted are C/POSIX, and I'd expect gettext() to
short-circuit that case and not look for a translation. I'm thinking
though that it's still worth checking that the untranslated string is
processed correctly.

regards, tom lane

The GNU gettext implementation does not short-circuit that. It still
goes through the path of trying to find the message catalogue, it fails,
there is no fallback, messages are untranslated. This is true on Windows
as well as Linux. Windows just has the curse of an expensive call to
enumerate the locales to find the passed in locale every single time
because of the failure to cache the unfound case.

--
Bryan Green
EDB: https://www.enterprisedb.com

#27Tom Lane
tgl@sss.pgh.pa.us
In reply to: Bryan Green (#26)
Re: PRI?64 vs Visual Studio (2022)

Bryan Green <dbryan.green@gmail.com> writes:

On 12/15/2025 11:05 AM, Tom Lane wrote:

... That's
colored by seeing that less than half of the buildfarm is finding any
variant of es_ES to test in. That's not great, but I'm not seeing
anything to be done about it. The only locale names we can be sure
will be accepted are C/POSIX, and I'd expect gettext() to
short-circuit that case and not look for a translation. I'm thinking
though that it's still worth checking that the untranslated string is
processed correctly.

The GNU gettext implementation does not short-circuit that. It still
goes through the path of trying to find the message catalogue, it fails,
there is no fallback, messages are untranslated. This is true on Windows
as well as Linux.

It'd be great to not need the assumption of es_ES being installed.
However, I tried making a POSIX.po file and setting lc_messages to
POSIX, and it didn't work. The msgfmt infrastructure seemed unfazed
and installed a .mo file under $sharedir/locale/POSIX/LC_MESSAGES as
I'd expect, but no translation happened (this on a Linux box). Same
with 'C'. It did work if I set lc_messages to 'C.utf8', which is a
known name according to this box's "locale -a", but this doesn't give
me a warm feeling about this approach being a lot more portable than
what we have. Any ideas?

regards, tom lane

#28Bryan Green
dbryan.green@gmail.com
In reply to: Tom Lane (#27)
Re: PRI?64 vs Visual Studio (2022)

On 12/15/2025 12:28 PM, Tom Lane wrote:

It'd be great to not need the assumption of es_ES being installed.
However, I tried making a POSIX.po file and setting lc_messages to
POSIX, and it didn't work. The msgfmt infrastructure seemed unfazed
and installed a .mo file under $sharedir/locale/POSIX/LC_MESSAGES as
I'd expect, but no translation happened (this on a Linux box). Same
with 'C'. It did work if I set lc_messages to 'C.utf8', which is a
known name according to this box's "locale -a", but this doesn't give
me a warm feeling about this approach being a lot more portable than
what we have. Any ideas?

My answer did not feel like it was right, so I checked multiple versions
and realized there is a check.

char *
DCIGETTEXT (const char *domainname, const char *msgid, ...)
{
// Get the locale name
categoryvalue = guess_category_value (category, categoryname);

if (categoryvalue != NULL
&& !(categoryvalue[0] == 'C' && categoryvalue[1] == '\0')
&& strcmp (categoryvalue, "POSIX") != 0)
{
// Only do translation if NOT "C" and NOT "POSIX"
retval = _nl_find_msg (...);
}

// For "C" and "POSIX", skip directly to returning msgid
return (char *) msgid;
}

C.utf8 works because it is not "C" so is treated as a real locale. Now
that I'm back into that code...looking it over in more detail to see
what might work...

--
Bryan Green
EDB: https://www.enterprisedb.com

#29Tom Lane
tgl@sss.pgh.pa.us
In reply to: Bryan Green (#28)
Re: PRI?64 vs Visual Studio (2022)

Bryan Green <dbryan.green@gmail.com> writes:

On 12/15/2025 12:28 PM, Tom Lane wrote:

... It did work if I set lc_messages to 'C.utf8', which is a
known name according to this box's "locale -a", but this doesn't give
me a warm feeling about this approach being a lot more portable than
what we have. Any ideas?

My answer did not feel like it was right, so I checked multiple versions
and realized there is a check.
...
C.utf8 works because it is not "C" so is treated as a real locale.

Ah-hah. I didn't think they hadn't optimized the case at all.

Experimenting here, it looks like 'C.UTF-8' might be accepted
everywhere. I even got it to pass on Solaris's not-GNU gettext,
which I thought for sure would be the weak spot in the idea.
I'll press forward with that.

regards, tom lane

#30Peter Eisentraut
peter@eisentraut.org
In reply to: Tom Lane (#23)
Re: PRI?64 vs Visual Studio (2022)

On 15.12.25 08:01, Tom Lane wrote:

So their gettext handles PRIu64 and PRIu32 and nothing else.

What to do now? I could revert 8c498479d and followups, but
I sure don't want to. A stopgap measure to make the farm look
green would be to add a variant expected-file that accepts
this output, but yech. Thoughts?

I think that means that that gettext implementation is not currently
supportable. So either we revert our PRI* use except those two
(unlikely), or those buildfarm members should disable NLS.

#31Thomas Munro
thomas.munro@gmail.com
In reply to: Peter Eisentraut (#30)
Re: PRI?64 vs Visual Studio (2022)

On Tue, Dec 16, 2025 at 8:29 AM Peter Eisentraut <peter@eisentraut.org> wrote:

On 15.12.25 08:01, Tom Lane wrote:

So their gettext handles PRIu64 and PRIu32 and nothing else.

What to do now? I could revert 8c498479d and followups, but
I sure don't want to. A stopgap measure to make the farm look
green would be to add a variant expected-file that accepts
this output, but yech. Thoughts?

I think that means that that gettext implementation is not currently
supportable. So either we revert our PRI* use except those two
(unlikely), or those buildfarm members should disable NLS.

Yeah. My goal in mentioning the problem back when it was just a
problem in theory (we had no test, the Alpine packages disable nls
(perhaps it used to be *more* broken, if they did that before we used
PRI?)) was to try to see if someone closer to these musl distros
wanted to have a crack at fixing it, since it looks pretty close to
being usable. But now that it's a problem in practice, it's hard to
disagree with Peter's take. It could be reenabled any time it works
enough to pass the test.

#32Tom Lane
tgl@sss.pgh.pa.us
In reply to: Thomas Munro (#31)
Re: PRI?64 vs Visual Studio (2022)

Thomas Munro <thomas.munro@gmail.com> writes:

On Tue, Dec 16, 2025 at 8:29 AM Peter Eisentraut <peter@eisentraut.org> wrote:

I think that means that that gettext implementation is not currently
supportable. So either we revert our PRI* use except those two
(unlikely), or those buildfarm members should disable NLS.

Yeah. My goal in mentioning the problem back when it was just a
problem in theory (we had no test, the Alpine packages disable nls
(perhaps it used to be *more* broken, if they did that before we used
PRI?)) was to try to see if someone closer to these musl distros
wanted to have a crack at fixing it, since it looks pretty close to
being usable. But now that it's a problem in practice, it's hard to
disagree with Peter's take. It could be reenabled any time it works
enough to pass the test.

Fair enough. I've revised the test mechanism per discussion with
Bryan Green, in hopes of being able to test on more BF animals than
we could yesterday. But I won't put in an expected-file for this
Alpine misbehavior.

regards, tom lane

#33Tom Lane
tgl@sss.pgh.pa.us
In reply to: Tom Lane (#29)
Re: PRI?64 vs Visual Studio (2022)

I wrote:

Experimenting here, it looks like 'C.UTF-8' might be accepted
everywhere. I even got it to pass on Solaris's not-GNU gettext,
which I thought for sure would be the weak spot in the idea.
I'll press forward with that.

Hmmm ... the first batch of BF reports show that on some Linux
machines, it works to set lc_messages to 'C.UTF-8', but nonetheless
no translation happens. Did you notice any other gating factors?

regards, tom lane

#34Wolfgang Walther
walther@technowledgy.de
In reply to: Kyotaro Horiguchi (#1)
Re: PRI?64 vs Visual Studio (2022)

Tom Lane:

Thomas Munro <thomas.munro@gmail.com> writes:

On Tue, Dec 16, 2025 at 8:29 AM Peter Eisentraut <peter@eisentraut.org> wrote:

I think that means that that gettext implementation is not currently
supportable. So either we revert our PRI* use except those two
(unlikely), or those buildfarm members should disable NLS.

Yeah. My goal in mentioning the problem back when it was just a
problem in theory (we had no test, the Alpine packages disable nls
(perhaps it used to be *more* broken, if they did that before we used
PRI?)) was to try to see if someone closer to these musl distros
wanted to have a crack at fixing it, since it looks pretty close to
being usable. But now that it's a problem in practice, it's hard to
disagree with Peter's take. It could be reenabled any time it works
enough to pass the test.

Fair enough. I've revised the test mechanism per discussion with
Bryan Green, in hopes of being able to test on more BF animals than
we could yesterday. But I won't put in an expected-file for this
Alpine misbehavior.

Both alpine animals now have NLS disabled.

Best,

Wolfgang

#35Bryan Green
dbryan.green@gmail.com
In reply to: Tom Lane (#33)
Re: PRI?64 vs Visual Studio (2022)

On 12/15/2025 2:39 PM, Tom Lane wrote:

I wrote:

Experimenting here, it looks like 'C.UTF-8' might be accepted
everywhere. I even got it to pass on Solaris's not-GNU gettext,
which I thought for sure would be the weak spot in the idea.
I'll press forward with that.

Hmmm ... the first batch of BF reports show that on some Linux
machines, it works to set lc_messages to 'C.UTF-8', but nonetheless
no translation happens. Did you notice any other gating factors?

regards, tom lane

Yes - the LANGUAGE environment variable.

gettext has a priority order for locale selection that's different from
what most people expect. Here's what guess_category_value() does:
Environment Variable Priority (from dcigettext.c):

1. LANGUAGE - GNU extension, colon-separated list (e.g., "en_US:en:C")
2. setlocale(category, NULL) result - the actual locale set
3. LC_ALL - POSIX override for all categories
4. LC_MESSAGES (or other LC_* for that category)
5. LANG - fallback default

LANGUAGE has the highest priority and will override LC_MESSAGES completely.

I am not sure this is the problem, but you probably should unset
LANGUAGE before doing almost anything else in the test script. I
wouldn't be surprised if the CI/BF environments have it set.

Do we know what version of libintl is being used on those BF machines?
There are some marked differences between some versions, which makes
this a little more guesswork than it should be.

---------------------------------------------------------------------

What follows is a walkthrough that just shows that language overrides
lc_messages and how that can impact things. No need to read this unless
you just want more detail.

Assume,
export LANGUAGE=en_US:en
export LC_MESSAGES=C.UTF-8

System has catalogs for C.UTF-8 and es.

#postgres.conf
lc_messages = 'C.UTF-8'

InitPostgres calls pg_perm_setlocale with C.UTF-8.

pg_perm_setlocale calls setlocale(LC_MESSAGES, "C.UTF-8") and succeeds.

setlocale uses setenv to set LC_MESSAGES=C.UTF_8

Now assume an error occurs and gettext is called. A couple of wrappers
down we get to DCIGETTEXT() with a category of LC_MESSAGES. We call
guess_category_value with LC_MESSAGES.

guess_category_value implements the priorty as discussed above. The
very first thing it checks is getenv("LANGUAGE"). If that is not NULL
or an empty string it returns whatever is in LANGUAUGE, which in this
case is en_US:en.

Then back in DCIGETTEXT() we will loop through en_US:en. We try to find
the message catalog with 'en_US' first...and fail because we don't have
that catalog. Then we loop back and try 'en'...and fail again because
we don't have that catalog. One more time through the loop where we
don't have anything left in our list of languages, so we set the locale
to 'C'. Then we check that we don't translate if the locale is a single
C. and we break. Nothing translated.

--
Bryan Green
EDB: https://www.enterprisedb.com

#36Bryan Green
dbryan.green@gmail.com
In reply to: Tom Lane (#33)
Re: PRI?64 vs Visual Studio (2022)

On 12/15/2025 2:39 PM, Tom Lane wrote:

I wrote:

Experimenting here, it looks like 'C.UTF-8' might be accepted
everywhere. I even got it to pass on Solaris's not-GNU gettext,
which I thought for sure would be the weak spot in the idea.
I'll press forward with that.

Hmmm ... the first batch of BF reports show that on some Linux
machines, it works to set lc_messages to 'C.UTF-8', but nonetheless
no translation happens. Did you notice any other gating factors?

regards, tom lane

I should have asked you which version of libintl is being used. I went
ahead and jumped to 0.26 and they now gate like this:

/* If the current locale value is "C" or "C.<encoding>" or "POSIX",
we don't load a domain. Return the MSGID. */
if ((single_locale[0] == 'C'
&& (single_locale[1] == '\0' || single_locale[1] == '.'))
|| strcmp (single_locale, "POSIX") == 0)
break;

--
Bryan Green
EDB: https://www.enterprisedb.com

#37Tom Lane
tgl@sss.pgh.pa.us
In reply to: Bryan Green (#35)
Re: PRI?64 vs Visual Studio (2022)

Bryan Green <dbryan.green@gmail.com> writes:

On 12/15/2025 2:39 PM, Tom Lane wrote:

Hmmm ... the first batch of BF reports show that on some Linux
machines, it works to set lc_messages to 'C.UTF-8', but nonetheless
no translation happens. Did you notice any other gating factors?

Yes - the LANGUAGE environment variable.

Not it, I think. pg_regress unsets that. Also, I've been able to
reproduce the failure here using a Fedora 42 image, and LANGUAGE
is definitely not set in that environment.

Do we know what version of libintl is being used on those BF machines?
There are some marked differences between some versions, which makes
this a little more guesswork than it should be.

On my Fedora image, there seems to be no libintl.so anywhere; it's
certainly not getting linked into Postgres. The routines must be
built into libc. rpm says the glibc version is
glibc-2.41-11.fc42.x86_64. Judging by buildfarm reports, the
behavior changed sometime between Fedora 39 and Fedora 42.

strace'ing shows that during "SET lc_messages = 'C.UTF-8'",
it successfully finds system locale data about C.utf8:

recvfrom(10, "Q\0\0\0!SET lc_messages = 'C.UTF-8'"..., 8192, 0, NULL, NULL) = 34
openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 21
fstat(21, {st_mode=S_IFREG|0644, st_size=217804320, ...}) = 0
mmap(NULL, 217804320, PROT_READ, MAP_PRIVATE, 21, 0) = 0x7f935c5f6000
close(21) = 0
openat(AT_FDCWD, "/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 21
fstat(21, {st_mode=S_IFREG|0644, st_size=2997, ...}) = 0
read(21, "# Locale name alias data base.\n#"..., 4096) = 2997
read(21, "", 4096) = 0
close(21) = 0
openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_MESSAGES", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_MESSAGES", O_RDONLY|O_CLOEXEC) = 21
fstat(21, {st_mode=S_IFDIR|0755, st_size=29, ...}) = 0
close(21) = 0
openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_MESSAGES/SYS_LC_MESSAGES", O_RDONLY|O_CLOEXEC) = 21
fstat(21, {st_mode=S_IFREG|0644, st_size=53, ...}) = 0
mmap(NULL, 53, PROT_READ, MAP_PRIVATE, 21, 0) = 0x7f937690a000
close(21) = 0
openat(AT_FDCWD, "/usr/lib64/gconv/gconv-modules.cache", O_RDONLY) = 21
fstat(21, {st_mode=S_IFREG|0644, st_size=26998, ...}) = 0
mmap(NULL, 26998, PROT_READ, MAP_SHARED, 21, 0) = 0x7f9376903000
close(21) = 0
futex(0x7f93752999a8, FUTEX_WAKE_PRIVATE, 2147483647) = 0
sendto(10, "C\0\0\0\10SET\0Z\0\0\0\5I", 15, 0, NULL, 0) = 15

This part of the trace seems indistinguishable between an older
RHEL system and Fedora 42. But on the older system, when we
invoke pg_bindtextdomain, it does open the regress-19.mo file:

recvfrom(10, "Q\0\0\0\37SELECT test_translation();\0", 8192, 0, NULL, NULL) = 32
stat("/home/postgres/pgsql/src/test/regress/regress.so", {st_mode=S_IFREG|0775, st_size=264904, ...}) = 0
openat(AT_FDCWD, "/home/postgres/testversion/share/locale/C.UTF-8/LC_MESSAGES/regress-19.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/home/postgres/testversion/share/locale/C.utf8/LC_MESSAGES/regress-19.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/home/postgres/testversion/share/locale/C/LC_MESSAGES/regress-19.mo", O_RDONLY) = 21
fstat(21, {st_mode=S_IFREG|0644, st_size=2316, ...}) = 0
mmap(NULL, 2316, PROT_READ, MAP_PRIVATE, 21, 0) = 0x7f9376902000
close(21) = 0
brk(NULL) = 0x1a52000
brk(0x1a75000) = 0x1a75000
openat(AT_FDCWD, "/home/postgres/testversion/share/locale/C.UTF-8/LC_MESSAGES/postgres-19.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/home/postgres/testversion/share/locale/C.utf8/LC_MESSAGES/postgres-19.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/home/postgres/testversion/share/locale/C/LC_MESSAGES/postgres-19.mo", O_RDONLY) = -1 ENOENT (No such file or directory)

and away we go. On the newer system, there is no attempt to access
the .mo file at all. It looks like it's decided that C.UTF-8 isn't
really a valid locale and it's just going to ignore everything.

regards, tom lane

#38Tom Lane
tgl@sss.pgh.pa.us
In reply to: Bryan Green (#36)
Re: PRI?64 vs Visual Studio (2022)

Bryan Green <dbryan.green@gmail.com> writes:

I should have asked you which version of libintl is being used. I went
ahead and jumped to 0.26 and they now gate like this:

/* If the current locale value is "C" or "C.<encoding>" or "POSIX",
we don't load a domain. Return the MSGID. */
if ((single_locale[0] == 'C'
&& (single_locale[1] == '\0' || single_locale[1] == '.'))
|| strcmp (single_locale, "POSIX") == 0)
break;

Bleah. I wonder if "POSIX.UTF-8" would work?

regression=# set lc_messages TO 'POSIX.UTF-8';
ERROR: invalid value for parameter "lc_messages": "POSIX.UTF-8"

... nope. Back to the drawing board I guess.

I've reverted the latest patch for now.

regards, tom lane

#39Thomas Munro
thomas.munro@gmail.com
In reply to: Thomas Munro (#24)
Re: PRI?64 vs Visual Studio (2022)

On Tue, Dec 16, 2025 at 12:15 AM Thomas Munro <thomas.munro@gmail.com> wrote:

On Mon, Dec 15, 2025 at 8:01 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:

So their gettext handles PRIu64 and PRIu32 and nothing else.

Hah, I had predicted that three would work. Off by one.

What to do now? I could revert 8c498479d and followups, but
I sure don't want to. A stopgap measure to make the farm look
green would be to add a variant expected-file that accepts
this output, but yech. Thoughts?

So close yet so far... I tried asking if it's easy to fix:

https://github.com/sabotage-linux/gettext-tiny/issues/76

Problem ack'd. It looks like they want to fix it. Fingers crossed.

#40Thomas Munro
thomas.munro@gmail.com
In reply to: Thomas Munro (#39)
Re: PRI?64 vs Visual Studio (2022)

On Thu, Dec 18, 2025 at 12:56 PM Thomas Munro <thomas.munro@gmail.com> wrote:

On Tue, Dec 16, 2025 at 12:15 AM Thomas Munro <thomas.munro@gmail.com> wrote:

https://github.com/sabotage-linux/gettext-tiny/issues/76

Problem ack'd. It looks like they want to fix it. Fingers crossed.

FYI this has been fixed and our test passes with their msgfmt compiled
from source, so it could be reenabled on those animals once that has
flowed into the right places. No idea when that'll be though.