pgsql-hackers
❮
Decoupling our alignment assumptions about int64 and double
- Jump to comment-1Tom Lane<tgl@sss.pgh.pa.us>Jan 29, 2026, 1:20 AM UTCOver in the long-running thread about resurrecting AIX support,
one salient concern is that AIX has alignof(int64) = 8 but
alignof(double) = 4. This breaks all our code that supposes
that ALIGNOF_DOUBLE is the platform's maximum alignment spec.
We had coped with this via various unspeakable klugery back
when AIX was considered supported, but nobody wants to put
back those restrictions if we re-support AIX. (See my gripe
at [1], but I believe Heikki and Andres complained of this
in more detail long ago.)
Here is a modest proposal for fixing that in a clean way.
Let's break TYPALIGNDOUBLE into three values, TYPALIGNDOUBLE
for float8 only, TYPALIGN_INT64 for 64-bit integral types
including pointers, and TYPALIGN_MAX to represent MAXALIGN
alignment regardless of which of the first two determine it.
We need TYPALIGN_MAX because that's the value composite
types should use, so that their alignment doesn't change
if somebody adds or deletes a column of a relevant type.
Given that design, the patch is pretty straightforward,
and smaller than I feared it might be. (Though I might
have missed a spot or two.)
I think this is good cleanup and deserves consideration
whether we accept the AIX patch soon or not.
A loose end that deserves mention is that I noticed we
are very inconsistent about the length/alignment
attributed to polymorphic types:
select typname, typlen, typalign from pg_type where typname like 'any%';(12 rows)typname typlen typalign any 4 i anyarray -1 m anycompatible 4 i anycompatiblearray -1 m anycompatiblemultirange -1 m anycompatiblenonarray 4 i anycompatiblerange -1 m anyelement 4 i anyenum 4 i anymultirange -1 m anynonarray 4 i anyrange -1 m
(Previous to this patch, the 'm' entries were 'd'.)
In one sense this doesn't really matter, since no actual
value should have any of these types attributed to it;
but it annoys me that they're not all alike. I'm tempted to
make them all 4/'i' which seems to be the older convention.
A more aggressive answer would be to change these to some
actually-illegal values, in hopes of catching anyplace where
we did try to rely on the values. But that seems like
material for a different patch.
[1] https://www.postgresql.org/message-id/581905.1769550155%40sss.pgh.pa.usregards, tom lane- Jump to comment-1Andres Freund<andres@anarazel.de>Jan 29, 2026, 4:13 PM UTCHi,
Thanks for the patch. Looks like a decent improvement.
On 2026-01-28 20:20:24 -0500, Tom Lane wrote:One of the concerns that prevented this from being done long
Yea, it shouldn't matter too much these days. We might want to verify that
ago was not wanting to add overhead to tuple forming/deforming.
However that concern seems gone now, because we map TYPALIGN_xxx
values to numeric alignments in populatecompactattribute()
which is not so performance-critical. It might be worth
worrying about the increased cost of attalignnominal(),
but that macro is not that heavily used IMO.
the array code isn't overly affected, e.g. arrayiternext() was deemed perf
critical enough by someone to make it an inline function. I don't know if the
compiler is somehow smart enough to move the conditionals outside of a loop
over arrayiternext().
Perhaps we should make attalignnominal() first determine the numerical
alignment value and then have it use TYPEALIGN()? I think that'd be more
likely to be pulled out of loops by the compile.
Perhaps it's time to reformat attalignnominal() into an static inline? It's
pretty hard to read.
I don't love the 'l' for TYPALIGN_INT64, but I guess I don't really have a
better suggestion.
It wouldn't hurt to have a short SQL level test for creating a type with int8
& max alignments.
Greetings,
Andres Freund- Jump to comment-1Tom Lane<tgl@sss.pgh.pa.us>Jan 29, 2026, 4:33 PM UTCAndres Freund <andres@anarazel.de> writes:
Thanks for the patch. Looks like a decent improvement.
Thanks for looking!On 2026-01-28 20:20:24 -0500, Tom Lane wrote:
... It might be worth
worrying about the increased cost of attalignnominal(),
but that macro is not that heavily used IMO.Perhaps we should make attalignnominal() first determine the numerical
Yeah, I was thinking about actually breaking that into two source-code
alignment value and then have it use TYPEALIGN()? I think that'd be more
likely to be pulled out of loops by the compile.
steps, a function to map TYPALIGN_xxx to numeric alignment and then a
replacement for attalignnominal that takes a numeric alignment.
If you think it's worth worrying about I'm happy to do that.Perhaps it's time to reformat attalignnominal() into an static inline? It's
+1, I was not revisiting any of that for this draft, but if we're going
pretty hard to read.
to refactor it then an inline function seems good.I don't love the 'l' for TYPALIGN_INT64, but I guess I don't really have a
Of course I was thinking 'l' for "long", but I agree it's not great
better suggestion.
typographically. One idea is 'L' not 'l', but that gives up
consistency for visual separation. Any other ideas out there?It wouldn't hurt to have a short SQL level test for creating a type with int8
hmm ... yeah, I guess those code paths might not be covered already.
& max alignments.regards, tom lane- Jump to comment-1Tom Lane<tgl@sss.pgh.pa.us>Jan 30, 2026, 1:22 AM UTCHere's a v2 responding to your suggestions. 0001 refactors
attalignnominal(), and then 0002 is nearly the same as the
prior patch except for rebasing over that change. I added
a test case for alignment = max too (the other cases seem
covered already, somewhat indirectly via pg_upgrade testing).
I think this might be about ready to go, unless somebody has
a better idea than 'l' for the catalog representation of
TYPALIGN_INT64.regards, tom lane- Jump to comment-1Tom Lane<tgl@sss.pgh.pa.us>Jan 31, 2026, 4:46 AM UTCI wrote:
I think this might be about ready to go, unless somebody has
I realized that there is more to consider here than we'd thought.
a better idea than 'l' for the catalog representation of
TYPALIGN_INT64.
In particular, while we've mainly worried about what happens with
system catalog row layout, the change I've proposed here very
likely changes row layout in user tables, if we are on a platform
where TYPALIGNINT64 != TYPALIGNDOUBLE. So this is a pg_upgrade
breaking change for such platforms.
Maybe this is another reason to decide that AIX isn't worth
re-supporting: if there are any AIX users out there who still care,
the prospect of a forced dump-and-reload might be enough to convince
them that they might as well migrate to a more modern platform while
they are at it. Not sure.
If we do want to go forward with this, it would make sense to
adjust pgcontrol to store MAXALIGN, TYPALIGNDOUBLE, and
TYPALIGN_INT64 separately, instead of
#define FLOATFORMAT_VALUE 1234567.0/* * This data is used to check for hardware-architecture compatibility of * the database and the backend executable. We need not check endianness * explicitly, since the pg_control version will surely look wrong to a * machine of different endianness, but we do need to worry about MAXALIGN * and floating-point format. (Note: storage layout nominally also * depends on SHORTALIGN and INTALIGN, but in practice these are the same * on all architectures of interest.) * * Testing just one double value is not a very bulletproof test for * floating-point compatibility, but it will catch most cases. */ uint32 maxAlign; /* alignment requirement for tuples */ double floatFormat; /* constant 1234567.0 */
(Given that we've now pretty much locked in on IEEE float format,
I suspect floatFormat isn't pulling its weight anymore, but
perhaps that's a separate discussion.)regards, tom lane