summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane2025-12-09 16:43:25 +0000
committerTom Lane2025-12-09 16:43:25 +0000
commitf8715ec86608fc5f6c80f5dec3369b4cc56481a8 (patch)
tree9836026a66cc3bf9a591ddb17da3973b7760eeb0 /src
parent3cb5808bd11c5a7ef697922335f7642f643a4e7f (diff)
Support "j" length modifier in snprintf.c.
POSIX has for a long time defined the "j" length modifier for printf conversions as meaning the size of intmax_t or uintmax_t. We got away without supporting that so far, because we were not using intmax_t anywhere. However, commit e6be84356 re-introduced upstream's use of intmax_t and PRIdMAX into zic.c. It emerges that on some platforms (at least FreeBSD and macOS), <inttypes.h> defines PRIdMAX as "jd", so that snprintf.c falls over if that is used. (We hadn't noticed yet because it would only be apparent if bad data is fed to zic, resulting in an error report, and even then the only visible symptom is a missing line number in the error message.) We could revert that decision from our copy of zic.c, but on the whole it seems better to update snprintf.c to support this standard modifier. There might well be extensions, now or in future, that expect it to work. I did this in the lazy man's way of translating "j" to either "l" or "ll" depending on a compile-time sizeof() check, just as was done long ago to support "z" for size_t. One could imagine promoting intmax_t to have full support in snprintf.c, for example converting fmtint()'s value argument and internal arithmetic to use [u]intmax_t not [unsigned] long long. But that'd be more work and I'm hesitant to do it anyway: if there are any platforms out there where intmax_t is actually wider than "long long", this would doubtless result in a noticeable speed penalty to snprintf(). Let's not go there until we have positive evidence that there's a reason to, and some way to measure what size of penalty we're taking. Author: Tom Lane <tgl@sss.pgh.pa.us> Discussion: https://postgr.es/m/3210703.1765236740@sss.pgh.pa.us
Diffstat (limited to 'src')
-rw-r--r--src/include/pg_config.h.in3
-rw-r--r--src/port/snprintf.c18
2 files changed, 21 insertions, 0 deletions
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index b0b0cfdaf79..72434ce957e 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -645,6 +645,9 @@
RELSEG_SIZE requires an initdb. */
#undef RELSEG_SIZE
+/* The size of `intmax_t', as computed by sizeof. */
+#undef SIZEOF_INTMAX_T
+
/* The size of `long', as computed by sizeof. */
#undef SIZEOF_LONG
diff --git a/src/port/snprintf.c b/src/port/snprintf.c
index 6541182df6d..d914547fae2 100644
--- a/src/port/snprintf.c
+++ b/src/port/snprintf.c
@@ -563,6 +563,15 @@ nextch2:
else
longflag = 1;
goto nextch2;
+ case 'j':
+#if SIZEOF_INTMAX_T == SIZEOF_LONG
+ longflag = 1;
+#elif SIZEOF_INTMAX_T == SIZEOF_LONG_LONG
+ longlongflag = 1;
+#else
+#error "cannot find integer type of the same size as intmax_t"
+#endif
+ goto nextch2;
case 'z':
#if SIZEOF_SIZE_T == SIZEOF_LONG
longflag = 1;
@@ -826,6 +835,15 @@ nextch1:
else
longflag = 1;
goto nextch1;
+ case 'j':
+#if SIZEOF_INTMAX_T == SIZEOF_LONG
+ longflag = 1;
+#elif SIZEOF_INTMAX_T == SIZEOF_LONG_LONG
+ longlongflag = 1;
+#else
+#error "cannot find integer type of the same size as intmax_t"
+#endif
+ goto nextch1;
case 'z':
#if SIZEOF_SIZE_T == SIZEOF_LONG
longflag = 1;