Here's a v2 responding to your suggestions. 0001 refactors
att_align_nominal(), 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
From 7b2949390ab32ec4d3c77dc1c1e239325bd3ec58 Mon Sep 17 00:00:00 2001
From: Tom Lane <[email protected]>
Date: Thu, 29 Jan 2026 18:34:26 -0500
Subject: [PATCH v2 1/2] Refactor att_align_nominal() to improve performance.
Separate att_align_nominal() into two macros, similarly to what
was already done with att_align_datum() and att_align_pointer().
The inner macro att_nominal_alignby() is really just TYPEALIGN(),
while att_align_nominal() retains its previous API by mapping
TYPALIGN_xxx values to numbers of bytes to align to and then
calling att_nominal_alignby(). In support of this, split out
tupdesc.c's logic to do that mapping into a publicly visible
function typalign_to_alignby().
Having done that, we can replace performance-critical uses of
att_align_nominal() with att_nominal_alignby(), where the
typalign_to_alignby() mapping is done just once outside the loop.
In most places I settled for doing typalign_to_alignby() once
per function. We could in many places pass the alignby value
in from the caller if we wanted to change function APIs for this
purpose; but I'm a bit loath to do that, especially for exported
APIs that extensions might call. Replacing a char typalign
argument by a uint8 typalignby argument would be an API change
that compilers would fail to warn about, thus silently breaking
code in hard-to-debug ways. I did revise the APIs of array_iter_setup
and array_iter_next, moving the element type attribute arguments to
the former; if any external code uses those, the argument-count
change will cause visible compile failures.
I've not bothered to try to measure the actual performance benefit
from doing this; it may not be measurable on normal workloads.
The main point is to make sure that an upcoming patch that will
complicate the typalign_to_alignby mapping will not cause any
performance decrease.
Discussion: https://postgr.es/m/[email protected]
---
contrib/dblink/dblink.c | 4 +-
src/backend/access/common/tupdesc.c | 21 +---
src/backend/executor/execExprInterp.c | 8 +-
src/backend/utils/adt/array_expanded.c | 4 +-
src/backend/utils/adt/arrayfuncs.c | 149 +++++++++++++-----------
src/backend/utils/adt/multirangetypes.c | 16 +--
src/backend/utils/adt/varlena.c | 4 +-
src/include/access/tupmacs.h | 51 ++++++--
src/include/utils/arrayaccess.h | 25 ++--
src/pl/plpython/plpy_typeio.c | 3 +-
10 files changed, 166 insertions(+), 119 deletions(-)
diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 8cb3166495c..2498d80c8e7 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -2069,6 +2069,7 @@ get_text_array_contents(ArrayType *array, int *numitems)
int16 typlen;
bool typbyval;
char typalign;
+ uint8 typalignby;
char **values;
char *ptr;
bits8 *bitmap;
@@ -2081,6 +2082,7 @@ get_text_array_contents(ArrayType *array, int *numitems)
get_typlenbyvalalign(ARR_ELEMTYPE(array),
&typlen, &typbyval, &typalign);
+ typalignby = typalign_to_alignby(typalign);
values = palloc_array(char *, nitems);
@@ -2098,7 +2100,7 @@ get_text_array_contents(ArrayType *array, int *numitems)
{
values[i] = TextDatumGetCString(PointerGetDatum(ptr));
ptr = att_addlength_pointer(ptr, typlen, ptr);
- ptr = (char *) att_align_nominal(ptr, typalign);
+ ptr = (char *) att_nominal_alignby(ptr, typalignby);
}
/* advance bitmap pointer if any */
diff --git a/src/backend/access/common/tupdesc.c b/src/backend/access/common/tupdesc.c
index 94b4f1f9975..b69d10f0a45 100644
--- a/src/backend/access/common/tupdesc.c
+++ b/src/backend/access/common/tupdesc.c
@@ -86,25 +86,8 @@ populate_compact_attribute_internal(Form_pg_attribute src,
IsCatalogRelationOid(src->attrelid) ? ATTNULLABLE_VALID :
ATTNULLABLE_UNKNOWN;
- switch (src->attalign)
- {
- case TYPALIGN_INT:
- dst->attalignby = ALIGNOF_INT;
- break;
- case TYPALIGN_CHAR:
- dst->attalignby = sizeof(char);
- break;
- case TYPALIGN_DOUBLE:
- dst->attalignby = ALIGNOF_DOUBLE;
- break;
- case TYPALIGN_SHORT:
- dst->attalignby = ALIGNOF_SHORT;
- break;
- default:
- dst->attalignby = 0;
- elog(ERROR, "invalid attalign value: %c", src->attalign);
- break;
- }
+ /* Compute numeric alignment requirement, too */
+ dst->attalignby = typalign_to_alignby(src->attalign);
}
/*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index a7a5ac1e83b..61ff5ddc74c 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -4032,6 +4032,7 @@ ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op)
int16 typlen;
bool typbyval;
char typalign;
+ uint8 typalignby;
char *s;
bits8 *bitmap;
int bitmask;
@@ -4086,6 +4087,7 @@ ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op)
typlen = op->d.scalararrayop.typlen;
typbyval = op->d.scalararrayop.typbyval;
typalign = op->d.scalararrayop.typalign;
+ typalignby = typalign_to_alignby(typalign);
/* Initialize result appropriately depending on useOr */
result = BoolGetDatum(!useOr);
@@ -4111,7 +4113,7 @@ ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op)
{
elt = fetch_att(s, typbyval, typlen);
s = att_addlength_pointer(s, typlen, s);
- s = (char *) att_align_nominal(s, typalign);
+ s = (char *) att_nominal_alignby(s, typalignby);
fcinfo->args[1].value = elt;
fcinfo->args[1].isnull = false;
}
@@ -4255,6 +4257,7 @@ ExecEvalHashedScalarArrayOp(ExprState *state, ExprEvalStep *op, ExprContext *eco
int16 typlen;
bool typbyval;
char typalign;
+ uint8 typalignby;
int nitems;
bool has_nulls = false;
char *s;
@@ -4272,6 +4275,7 @@ ExecEvalHashedScalarArrayOp(ExprState *state, ExprEvalStep *op, ExprContext *eco
&typlen,
&typbyval,
&typalign);
+ typalignby = typalign_to_alignby(typalign);
oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
@@ -4318,7 +4322,7 @@ ExecEvalHashedScalarArrayOp(ExprState *state, ExprEvalStep *op, ExprContext *eco
element = fetch_att(s, typbyval, typlen);
s = att_addlength_pointer(s, typlen, s);
- s = (char *) att_align_nominal(s, typalign);
+ s = (char *) att_nominal_alignby(s, typalignby);
saophash_insert(elements_tab->hashtab, element, &hashfound);
}
diff --git a/src/backend/utils/adt/array_expanded.c b/src/backend/utils/adt/array_expanded.c
index 01e3dddcbbb..7e8352af52b 100644
--- a/src/backend/utils/adt/array_expanded.c
+++ b/src/backend/utils/adt/array_expanded.c
@@ -238,6 +238,7 @@ EA_get_flat_size(ExpandedObjectHeader *eohptr)
Datum *dvalues;
bool *dnulls;
Size nbytes;
+ uint8 typalignby;
int i;
Assert(eah->ea_magic == EA_MAGIC);
@@ -261,12 +262,13 @@ EA_get_flat_size(ExpandedObjectHeader *eohptr)
dvalues = eah->dvalues;
dnulls = eah->dnulls;
nbytes = 0;
+ typalignby = typalign_to_alignby(eah->typalign);
for (i = 0; i < nelems; i++)
{
if (dnulls && dnulls[i])
continue;
nbytes = att_addlength_datum(nbytes, eah->typlen, dvalues[i]);
- nbytes = att_align_nominal(nbytes, eah->typalign);
+ nbytes = att_nominal_alignby(nbytes, typalignby);
/* check for overflow of total request */
if (!AllocSizeIsValid(nbytes))
ereport(ERROR,
diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c
index e71d32773b5..da68915ee20 100644
--- a/src/backend/utils/adt/arrayfuncs.c
+++ b/src/backend/utils/adt/arrayfuncs.c
@@ -75,6 +75,7 @@ typedef struct ArrayIteratorData
int16 typlen; /* element type's length */
bool typbyval; /* element type's byval property */
char typalign; /* element type's align property */
+ uint8 typalignby; /* typalign mapped to numeric alignment */
/* information about the requested slice size */
int slice_ndim; /* slice dimension, or 0 if not slicing */
@@ -123,7 +124,7 @@ static bool array_get_isnull(const bits8 *nullbitmap, int offset);
static void array_set_isnull(bits8 *nullbitmap, int offset, bool isNull);
static Datum ArrayCast(char *value, bool byval, int len);
static int ArrayCastAndSet(Datum src,
- int typlen, bool typbyval, char typalign,
+ int typlen, bool typbyval, uint8 typalignby,
char *dest);
static char *array_seek(char *ptr, int offset, bits8 *nullbitmap, int nitems,
int typlen, bool typbyval, char typalign);
@@ -187,6 +188,7 @@ array_in(PG_FUNCTION_ARGS)
int typlen;
bool typbyval;
char typalign;
+ uint8 typalignby;
char typdelim;
Oid typioparam;
char *p;
@@ -232,6 +234,7 @@ array_in(PG_FUNCTION_ARGS)
typlen = my_extra->typlen;
typbyval = my_extra->typbyval;
typalign = my_extra->typalign;
+ typalignby = typalign_to_alignby(typalign);
typdelim = my_extra->typdelim;
typioparam = my_extra->typioparam;
@@ -328,7 +331,7 @@ array_in(PG_FUNCTION_ARGS)
if (typlen == -1)
values[i] = PointerGetDatum(PG_DETOAST_DATUM(values[i]));
nbytes = att_addlength_datum(nbytes, typlen, values[i]);
- nbytes = att_align_nominal(nbytes, typalign);
+ nbytes = att_nominal_alignby(nbytes, typalignby);
/* check for overflow of total request */
if (!AllocSizeIsValid(nbytes))
ereturn(escontext, (Datum) 0,
@@ -972,6 +975,7 @@ CopyArrayEls(ArrayType *array,
bits8 *bitmap = ARR_NULLBITMAP(array);
int bitval = 0;
int bitmask = 1;
+ uint8 typalignby = typalign_to_alignby(typalign);
int i;
if (typbyval)
@@ -988,7 +992,7 @@ CopyArrayEls(ArrayType *array,
else
{
bitval |= bitmask;
- p += ArrayCastAndSet(values[i], typlen, typbyval, typalign, p);
+ p += ArrayCastAndSet(values[i], typlen, typbyval, typalignby, p);
if (freedata)
pfree(DatumGetPointer(values[i]));
}
@@ -1112,7 +1116,7 @@ array_out(PG_FUNCTION_ARGS)
needquotes = (bool *) palloc(nitems * sizeof(bool));
overall_length = 0;
- array_iter_setup(&iter, v);
+ array_iter_setup(&iter, v, typlen, typbyval, typalign);
for (i = 0; i < nitems; i++)
{
@@ -1121,8 +1125,7 @@ array_out(PG_FUNCTION_ARGS)
bool needquote;
/* Get source element, checking for NULL */
- itemvalue = array_iter_next(&iter, &isnull, i,
- typlen, typbyval, typalign);
+ itemvalue = array_iter_next(&iter, &isnull, i);
if (isnull)
{
@@ -1468,6 +1471,7 @@ ReadArrayBinary(StringInfo buf,
int i;
bool hasnull;
int32 totbytes;
+ uint8 typalignby = typalign_to_alignby(typalign);
for (i = 0; i < nitems; i++)
{
@@ -1526,7 +1530,7 @@ ReadArrayBinary(StringInfo buf,
if (typlen == -1)
values[i] = PointerGetDatum(PG_DETOAST_DATUM(values[i]));
totbytes = att_addlength_datum(totbytes, typlen, values[i]);
- totbytes = att_align_nominal(totbytes, typalign);
+ totbytes = att_nominal_alignby(totbytes, typalignby);
/* check for overflow of total request */
if (!AllocSizeIsValid(totbytes))
ereport(ERROR,
@@ -1614,7 +1618,7 @@ array_send(PG_FUNCTION_ARGS)
}
/* Send the array elements using the element's own sendproc */
- array_iter_setup(&iter, v);
+ array_iter_setup(&iter, v, typlen, typbyval, typalign);
for (i = 0; i < nitems; i++)
{
@@ -1622,8 +1626,7 @@ array_send(PG_FUNCTION_ARGS)
bool isnull;
/* Get source element, checking for NULL */
- itemvalue = array_iter_next(&iter, &isnull, i,
- typlen, typbyval, typalign);
+ itemvalue = array_iter_next(&iter, &isnull, i);
if (isnull)
{
@@ -2231,6 +2234,7 @@ array_set_element(Datum arraydatum,
addedafter,
lenbefore,
lenafter;
+ uint8 elmalignby = typalign_to_alignby(elmalign);
if (arraytyplen > 0)
{
@@ -2258,7 +2262,7 @@ array_set_element(Datum arraydatum,
resultarray = (char *) palloc(arraytyplen);
memcpy(resultarray, DatumGetPointer(arraydatum), arraytyplen);
elt_ptr = resultarray + indx[0] * elmlen;
- ArrayCastAndSet(dataValue, elmlen, elmbyval, elmalign, elt_ptr);
+ ArrayCastAndSet(dataValue, elmlen, elmbyval, elmalignby, elt_ptr);
return PointerGetDatum(resultarray);
}
@@ -2416,7 +2420,7 @@ array_set_element(Datum arraydatum,
else
{
olditemlen = att_addlength_pointer(0, elmlen, elt_ptr);
- olditemlen = att_align_nominal(olditemlen, elmalign);
+ olditemlen = att_nominal_alignby(olditemlen, elmalignby);
}
lenafter = olddatasize - lenbefore - olditemlen;
}
@@ -2426,7 +2430,7 @@ array_set_element(Datum arraydatum,
else
{
newitemlen = att_addlength_datum(0, elmlen, dataValue);
- newitemlen = att_align_nominal(newitemlen, elmalign);
+ newitemlen = att_nominal_alignby(newitemlen, elmalignby);
}
newsize = overheadlen + lenbefore + newitemlen + lenafter;
@@ -2449,7 +2453,7 @@ array_set_element(Datum arraydatum,
(char *) array + oldoverheadlen,
lenbefore);
if (!isNull)
- ArrayCastAndSet(dataValue, elmlen, elmbyval, elmalign,
+ ArrayCastAndSet(dataValue, elmlen, elmbyval, elmalignby,
(char *) newarray + overheadlen + lenbefore);
memcpy((char *) newarray + overheadlen + lenbefore + newitemlen,
(char *) array + oldoverheadlen + lenbefore + olditemlen,
@@ -3221,6 +3225,7 @@ array_map(Datum arrayd,
int typlen;
bool typbyval;
char typalign;
+ uint8 typalignby;
array_iter iter;
ArrayMetaState *inp_extra;
ArrayMetaState *ret_extra;
@@ -3270,21 +3275,21 @@ array_map(Datum arrayd,
typlen = ret_extra->typlen;
typbyval = ret_extra->typbyval;
typalign = ret_extra->typalign;
+ typalignby = typalign_to_alignby(typalign);
/* Allocate temporary arrays for new values */
values = (Datum *) palloc(nitems * sizeof(Datum));
nulls = (bool *) palloc(nitems * sizeof(bool));
/* Loop over source data */
- array_iter_setup(&iter, v);
+ array_iter_setup(&iter, v, inp_typlen, inp_typbyval, inp_typalign);
hasnulls = false;
for (i = 0; i < nitems; i++)
{
/* Get source element, checking for NULL */
*transform_source =
- array_iter_next(&iter, transform_source_isnull, i,
- inp_typlen, inp_typbyval, inp_typalign);
+ array_iter_next(&iter, transform_source_isnull, i);
/* Apply the given expression to source element */
values[i] = ExecEvalExpr(exprstate, econtext, &nulls[i]);
@@ -3298,7 +3303,7 @@ array_map(Datum arrayd,
values[i] = PointerGetDatum(PG_DETOAST_DATUM(values[i]));
/* Update total result size */
nbytes = att_addlength_datum(nbytes, typlen, values[i]);
- nbytes = att_align_nominal(nbytes, typalign);
+ nbytes = att_nominal_alignby(nbytes, typalignby);
/* check for overflow of total request */
if (!AllocSizeIsValid(nbytes))
ereport(ERROR,
@@ -3505,6 +3510,7 @@ construct_md_array(Datum *elems,
int32 dataoffset;
int i;
int nelems;
+ uint8 elmalignby = typalign_to_alignby(elmalign);
if (ndims < 0) /* we do allow zero-dimension arrays */
ereport(ERROR,
@@ -3538,7 +3544,7 @@ construct_md_array(Datum *elems,
if (elmlen == -1)
elems[i] = PointerGetDatum(PG_DETOAST_DATUM(elems[i]));
nbytes = att_addlength_datum(nbytes, elmlen, elems[i]);
- nbytes = att_align_nominal(nbytes, elmalign);
+ nbytes = att_nominal_alignby(nbytes, elmalignby);
/* check for overflow of total request */
if (!AllocSizeIsValid(nbytes))
ereport(ERROR,
@@ -3641,6 +3647,7 @@ deconstruct_array(const ArrayType *array,
bits8 *bitmap;
int bitmask;
int i;
+ uint8 elmalignby = typalign_to_alignby(elmalign);
Assert(ARR_ELEMTYPE(array) == elmtype);
@@ -3673,7 +3680,7 @@ deconstruct_array(const ArrayType *array,
{
elems[i] = fetch_att(p, elmbyval, elmlen);
p = att_addlength_pointer(p, elmlen, p);
- p = (char *) att_align_nominal(p, elmalign);
+ p = (char *) att_nominal_alignby(p, elmalignby);
}
/* advance bitmap pointer if any */
@@ -3878,8 +3885,8 @@ array_eq(PG_FUNCTION_ARGS)
/* Loop over source data */
nitems = ArrayGetNItems(ndims1, dims1);
- array_iter_setup(&it1, array1);
- array_iter_setup(&it2, array2);
+ array_iter_setup(&it1, array1, typlen, typbyval, typalign);
+ array_iter_setup(&it2, array2, typlen, typbyval, typalign);
for (i = 0; i < nitems; i++)
{
@@ -3890,10 +3897,8 @@ array_eq(PG_FUNCTION_ARGS)
bool oprresult;
/* Get elements, checking for NULL */
- elt1 = array_iter_next(&it1, &isnull1, i,
- typlen, typbyval, typalign);
- elt2 = array_iter_next(&it2, &isnull2, i,
- typlen, typbyval, typalign);
+ elt1 = array_iter_next(&it1, &isnull1, i);
+ elt2 = array_iter_next(&it2, &isnull2, i);
/*
* We consider two NULLs equal; NULL and not-NULL are unequal.
@@ -4042,8 +4047,8 @@ array_cmp(FunctionCallInfo fcinfo)
/* Loop over source data */
min_nitems = Min(nitems1, nitems2);
- array_iter_setup(&it1, array1);
- array_iter_setup(&it2, array2);
+ array_iter_setup(&it1, array1, typlen, typbyval, typalign);
+ array_iter_setup(&it2, array2, typlen, typbyval, typalign);
for (i = 0; i < min_nitems; i++)
{
@@ -4054,8 +4059,8 @@ array_cmp(FunctionCallInfo fcinfo)
int32 cmpresult;
/* Get elements, checking for NULL */
- elt1 = array_iter_next(&it1, &isnull1, i, typlen, typbyval, typalign);
- elt2 = array_iter_next(&it2, &isnull2, i, typlen, typbyval, typalign);
+ elt1 = array_iter_next(&it1, &isnull1, i);
+ elt2 = array_iter_next(&it2, &isnull2, i);
/*
* We consider two NULLs equal; NULL > not-NULL.
@@ -4238,7 +4243,7 @@ hash_array(PG_FUNCTION_ARGS)
/* Loop over source data */
nitems = ArrayGetNItems(ndims, dims);
- array_iter_setup(&iter, array);
+ array_iter_setup(&iter, array, typlen, typbyval, typalign);
for (i = 0; i < nitems; i++)
{
@@ -4247,7 +4252,7 @@ hash_array(PG_FUNCTION_ARGS)
uint32 elthash;
/* Get element, checking for NULL */
- elt = array_iter_next(&iter, &isnull, i, typlen, typbyval, typalign);
+ elt = array_iter_next(&iter, &isnull, i);
if (isnull)
{
@@ -4328,7 +4333,7 @@ hash_array_extended(PG_FUNCTION_ARGS)
/* Loop over source data */
nitems = ArrayGetNItems(ndims, dims);
- array_iter_setup(&iter, array);
+ array_iter_setup(&iter, array, typlen, typbyval, typalign);
for (i = 0; i < nitems; i++)
{
@@ -4337,7 +4342,7 @@ hash_array_extended(PG_FUNCTION_ARGS)
uint64 elthash;
/* Get element, checking for NULL */
- elt = array_iter_next(&iter, &isnull, i, typlen, typbyval, typalign);
+ elt = array_iter_next(&iter, &isnull, i);
if (isnull)
{
@@ -4451,7 +4456,7 @@ array_contain_compare(AnyArrayType *array1, AnyArrayType *array2, Oid collation,
/* Loop over source data */
nelems1 = ArrayGetNItems(AARR_NDIM(array1), AARR_DIMS(array1));
- array_iter_setup(&it1, array1);
+ array_iter_setup(&it1, array1, typlen, typbyval, typalign);
for (i = 0; i < nelems1; i++)
{
@@ -4459,7 +4464,7 @@ array_contain_compare(AnyArrayType *array1, AnyArrayType *array2, Oid collation,
bool isnull1;
/* Get element, checking for NULL */
- elt1 = array_iter_next(&it1, &isnull1, i, typlen, typbyval, typalign);
+ elt1 = array_iter_next(&it1, &isnull1, i);
/*
* We assume that the comparison operator is strict, so a NULL can't
@@ -4626,6 +4631,7 @@ array_create_iterator(ArrayType *arr, int slice_ndim, ArrayMetaState *mstate)
&iterator->typlen,
&iterator->typbyval,
&iterator->typalign);
+ iterator->typalignby = typalign_to_alignby(iterator->typalign);
/*
* Remember the slicing parameters.
@@ -4700,7 +4706,7 @@ array_iterate(ArrayIterator iterator, Datum *value, bool *isnull)
/* Move our data pointer forward to the next element */
p = att_addlength_pointer(p, iterator->typlen, p);
- p = (char *) att_align_nominal(p, iterator->typalign);
+ p = (char *) att_nominal_alignby(p, iterator->typalignby);
iterator->data_ptr = p;
}
}
@@ -4730,7 +4736,7 @@ array_iterate(ArrayIterator iterator, Datum *value, bool *isnull)
/* Move our data pointer forward to the next element */
p = att_addlength_pointer(p, iterator->typlen, p);
- p = (char *) att_align_nominal(p, iterator->typalign);
+ p = (char *) att_nominal_alignby(p, iterator->typalignby);
}
}
@@ -4828,7 +4834,7 @@ static int
ArrayCastAndSet(Datum src,
int typlen,
bool typbyval,
- char typalign,
+ uint8 typalignby,
char *dest)
{
int inc;
@@ -4839,14 +4845,14 @@ ArrayCastAndSet(Datum src,
store_att_byval(dest, src, typlen);
else
memmove(dest, DatumGetPointer(src), typlen);
- inc = att_align_nominal(typlen, typalign);
+ inc = att_nominal_alignby(typlen, typalignby);
}
else
{
Assert(!typbyval);
inc = att_addlength_datum(0, typlen, src);
memmove(dest, DatumGetPointer(src), inc);
- inc = att_align_nominal(inc, typalign);
+ inc = att_nominal_alignby(inc, typalignby);
}
return inc;
@@ -4867,12 +4873,13 @@ static char *
array_seek(char *ptr, int offset, bits8 *nullbitmap, int nitems,
int typlen, bool typbyval, char typalign)
{
+ uint8 typalignby = typalign_to_alignby(typalign);
int bitmask;
int i;
/* easy if fixed-size elements and no NULLs */
if (typlen > 0 && !nullbitmap)
- return ptr + nitems * ((Size) att_align_nominal(typlen, typalign));
+ return ptr + nitems * ((Size) att_nominal_alignby(typlen, typalignby));
/* seems worth having separate loops for NULL and no-NULLs cases */
if (nullbitmap)
@@ -4885,7 +4892,7 @@ array_seek(char *ptr, int offset, bits8 *nullbitmap, int nitems,
if (*nullbitmap & bitmask)
{
ptr = att_addlength_pointer(ptr, typlen, ptr);
- ptr = (char *) att_align_nominal(ptr, typalign);
+ ptr = (char *) att_nominal_alignby(ptr, typalignby);
}
bitmask <<= 1;
if (bitmask == 0x100)
@@ -4900,7 +4907,7 @@ array_seek(char *ptr, int offset, bits8 *nullbitmap, int nitems,
for (i = 0; i < nitems; i++)
{
ptr = att_addlength_pointer(ptr, typlen, ptr);
- ptr = (char *) att_align_nominal(ptr, typalign);
+ ptr = (char *) att_nominal_alignby(ptr, typalignby);
}
}
return ptr;
@@ -5050,12 +5057,13 @@ array_slice_size(char *arraydataptr, bits8 *arraynullsptr,
j,
inc;
int count = 0;
+ uint8 typalignby = typalign_to_alignby(typalign);
mda_get_range(ndim, span, st, endp);
/* Pretty easy for fixed element length without nulls ... */
if (typlen > 0 && !arraynullsptr)
- return ArrayGetNItems(ndim, span) * att_align_nominal(typlen, typalign);
+ return ArrayGetNItems(ndim, span) * att_nominal_alignby(typlen, typalignby);
/* Else gotta do it the hard way */
src_offset = ArrayGetOffset(ndim, dim, lb, st);
@@ -5077,7 +5085,7 @@ array_slice_size(char *arraydataptr, bits8 *arraynullsptr,
if (!array_get_isnull(arraynullsptr, src_offset))
{
inc = att_addlength_pointer(0, typlen, ptr);
- inc = att_align_nominal(inc, typalign);
+ inc = att_nominal_alignby(inc, typalignby);
ptr += inc;
count += inc;
}
@@ -6096,6 +6104,7 @@ array_fill_internal(ArrayType *dims, ArrayType *lbs,
int16 elmlen;
bool elmbyval;
char elmalign;
+ uint8 elmalignby;
ArrayMetaState *my_extra;
/*
@@ -6190,6 +6199,7 @@ array_fill_internal(ArrayType *dims, ArrayType *lbs,
elmlen = my_extra->typlen;
elmbyval = my_extra->typbyval;
elmalign = my_extra->typalign;
+ elmalignby = typalign_to_alignby(elmalign);
/* compute required space */
if (!isnull)
@@ -6204,7 +6214,7 @@ array_fill_internal(ArrayType *dims, ArrayType *lbs,
value = PointerGetDatum(PG_DETOAST_DATUM(value));
nbytes = att_addlength_datum(0, elmlen, value);
- nbytes = att_align_nominal(nbytes, elmalign);
+ nbytes = att_nominal_alignby(nbytes, elmalignby);
Assert(nbytes > 0);
totbytes = nbytes * nitems;
@@ -6228,7 +6238,7 @@ array_fill_internal(ArrayType *dims, ArrayType *lbs,
p = ARR_DATA_PTR(result);
for (i = 0; i < nitems; i++)
- p += ArrayCastAndSet(value, elmlen, elmbyval, elmalign, p);
+ p += ArrayCastAndSet(value, elmlen, elmbyval, elmalignby, p);
}
else
{
@@ -6259,9 +6269,6 @@ array_unnest(PG_FUNCTION_ARGS)
array_iter iter;
int nextelem;
int numelems;
- int16 elmlen;
- bool elmbyval;
- char elmalign;
} array_unnest_fctx;
FuncCallContext *funcctx;
@@ -6272,6 +6279,9 @@ array_unnest(PG_FUNCTION_ARGS)
if (SRF_IS_FIRSTCALL())
{
AnyArrayType *arr;
+ int16 elmlen;
+ bool elmbyval;
+ char elmalign;
/* create a function context for cross-call persistence */
funcctx = SRF_FIRSTCALL_INIT();
@@ -6293,23 +6303,24 @@ array_unnest(PG_FUNCTION_ARGS)
/* allocate memory for user context */
fctx = palloc_object(array_unnest_fctx);
- /* initialize state */
- array_iter_setup(&fctx->iter, arr);
- fctx->nextelem = 0;
- fctx->numelems = ArrayGetNItems(AARR_NDIM(arr), AARR_DIMS(arr));
-
+ /* get element-type data */
if (VARATT_IS_EXPANDED_HEADER(arr))
{
/* we can just grab the type data from expanded array */
- fctx->elmlen = arr->xpn.typlen;
- fctx->elmbyval = arr->xpn.typbyval;
- fctx->elmalign = arr->xpn.typalign;
+ elmlen = arr->xpn.typlen;
+ elmbyval = arr->xpn.typbyval;
+ elmalign = arr->xpn.typalign;
}
else
get_typlenbyvalalign(AARR_ELEMTYPE(arr),
- &fctx->elmlen,
- &fctx->elmbyval,
- &fctx->elmalign);
+ &elmlen,
+ &elmbyval,
+ &elmalign);
+
+ /* initialize state */
+ array_iter_setup(&fctx->iter, arr, elmlen, elmbyval, elmalign);
+ fctx->nextelem = 0;
+ fctx->numelems = ArrayGetNItems(AARR_NDIM(arr), AARR_DIMS(arr));
funcctx->user_fctx = fctx;
MemoryContextSwitchTo(oldcontext);
@@ -6324,8 +6335,7 @@ array_unnest(PG_FUNCTION_ARGS)
int offset = fctx->nextelem++;
Datum elem;
- elem = array_iter_next(&fctx->iter, &fcinfo->isnull, offset,
- fctx->elmlen, fctx->elmbyval, fctx->elmalign);
+ elem = array_iter_next(&fctx->iter, &fcinfo->isnull, offset);
SRF_RETURN_NEXT(funcctx, elem);
}
@@ -6401,6 +6411,7 @@ array_replace_internal(ArrayType *array,
int typlen;
bool typbyval;
char typalign;
+ uint8 typalignby;
char *arraydataptr;
bits8 *bitmap;
int bitmask;
@@ -6445,6 +6456,7 @@ array_replace_internal(ArrayType *array,
typlen = typentry->typlen;
typbyval = typentry->typbyval;
typalign = typentry->typalign;
+ typalignby = typalign_to_alignby(typalign);
/*
* Detoast values if they are toasted. The replacement value must be
@@ -6506,7 +6518,7 @@ array_replace_internal(ArrayType *array,
isNull = false;
elt = fetch_att(arraydataptr, typbyval, typlen);
arraydataptr = att_addlength_datum(arraydataptr, typlen, elt);
- arraydataptr = (char *) att_align_nominal(arraydataptr, typalign);
+ arraydataptr = (char *) att_nominal_alignby(arraydataptr, typalignby);
if (search_isnull)
{
@@ -6553,7 +6565,7 @@ array_replace_internal(ArrayType *array,
{
/* Update total result size */
nbytes = att_addlength_datum(nbytes, typlen, values[nresult]);
- nbytes = att_align_nominal(nbytes, typalign);
+ nbytes = att_nominal_alignby(nbytes, typalignby);
/* check for overflow of total request */
if (!AllocSizeIsValid(nbytes))
ereport(ERROR,
@@ -6860,6 +6872,7 @@ width_bucket_array_variable(Datum operand,
int typlen = typentry->typlen;
bool typbyval = typentry->typbyval;
char typalign = typentry->typalign;
+ uint8 typalignby = typalign_to_alignby(typalign);
int left;
int right;
@@ -6883,7 +6896,7 @@ width_bucket_array_variable(Datum operand,
for (i = left; i < mid; i++)
{
ptr = att_addlength_pointer(ptr, typlen, ptr);
- ptr = (char *) att_align_nominal(ptr, typalign);
+ ptr = (char *) att_nominal_alignby(ptr, typalignby);
}
locfcinfo->args[0].value = operand;
@@ -6908,7 +6921,7 @@ width_bucket_array_variable(Datum operand,
* ensures we do only O(N) array indexing work, not O(N^2).
*/
ptr = att_addlength_pointer(ptr, typlen, ptr);
- thresholds_data = (char *) att_align_nominal(ptr, typalign);
+ thresholds_data = (char *) att_nominal_alignby(ptr, typalignby);
}
}
diff --git a/src/backend/utils/adt/multirangetypes.c b/src/backend/utils/adt/multirangetypes.c
index 07e2a81d46a..b1942387dc5 100644
--- a/src/backend/utils/adt/multirangetypes.c
+++ b/src/backend/utils/adt/multirangetypes.c
@@ -572,21 +572,22 @@ multirange_size_estimate(TypeCacheEntry *rangetyp, int32 range_count,
RangeType **ranges)
{
char elemalign = rangetyp->rngelemtype->typalign;
+ uint8 elemalignby = typalign_to_alignby(elemalign);
Size size;
int32 i;
/*
* Count space for MultirangeType struct, items and flags.
*/
- size = att_align_nominal(sizeof(MultirangeType) +
- Max(range_count - 1, 0) * sizeof(uint32) +
- range_count * sizeof(uint8), elemalign);
+ size = att_nominal_alignby(sizeof(MultirangeType) +
+ Max(range_count - 1, 0) * sizeof(uint32) +
+ range_count * sizeof(uint8), elemalignby);
/* Count space for range bounds */
for (i = 0; i < range_count; i++)
- size += att_align_nominal(VARSIZE(ranges[i]) -
- sizeof(RangeType) -
- sizeof(char), elemalign);
+ size += att_nominal_alignby(VARSIZE(ranges[i]) -
+ sizeof(RangeType) -
+ sizeof(char), elemalignby);
return size;
}
@@ -605,6 +606,7 @@ write_multirange_data(MultirangeType *multirange, TypeCacheEntry *rangetyp,
const char *begin;
char *ptr;
char elemalign = rangetyp->rngelemtype->typalign;
+ uint8 elemalignby = typalign_to_alignby(elemalign);
items = MultirangeGetItemsPtr(multirange);
flags = MultirangeGetFlagsPtr(multirange);
@@ -630,7 +632,7 @@ write_multirange_data(MultirangeType *multirange, TypeCacheEntry *rangetyp,
flags[i] = *((char *) ranges[i] + VARSIZE(ranges[i]) - sizeof(char));
len = VARSIZE(ranges[i]) - sizeof(RangeType) - sizeof(char);
memcpy(ptr, ranges[i] + 1, len);
- ptr += att_align_nominal(len, elemalign);
+ ptr += att_nominal_alignby(len, elemalignby);
}
}
diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c
index 6c1ebb0866d..552ac0c61d3 100644
--- a/src/backend/utils/adt/varlena.c
+++ b/src/backend/utils/adt/varlena.c
@@ -3898,6 +3898,7 @@ array_to_text_internal(FunctionCallInfo fcinfo, ArrayType *v,
int typlen;
bool typbyval;
char typalign;
+ uint8 typalignby;
StringInfoData buf;
bool printed = false;
char *p;
@@ -3947,6 +3948,7 @@ array_to_text_internal(FunctionCallInfo fcinfo, ArrayType *v,
typlen = my_extra->typlen;
typbyval = my_extra->typbyval;
typalign = my_extra->typalign;
+ typalignby = typalign_to_alignby(typalign);
p = ARR_DATA_PTR(v);
bitmap = ARR_NULLBITMAP(v);
@@ -3983,7 +3985,7 @@ array_to_text_internal(FunctionCallInfo fcinfo, ArrayType *v,
printed = true;
p = att_addlength_pointer(p, typlen, p);
- p = (char *) att_align_nominal(p, typalign);
+ p = (char *) att_nominal_alignby(p, typalignby);
}
/* advance bitmap pointer if any */
diff --git a/src/include/access/tupmacs.h b/src/include/access/tupmacs.h
index 3e5530658c9..d64c18b950b 100644
--- a/src/include/access/tupmacs.h
+++ b/src/include/access/tupmacs.h
@@ -71,6 +71,43 @@ fetch_att(const void *T, bool attbyval, int attlen)
}
#endif /* FRONTEND */
+/*
+ * typalign_to_alignby: map a TYPALIGN_xxx value to the numeric alignment
+ * value it represents. (We store TYPALIGN_xxx codes not the real alignment
+ * values mainly so that initial catalog contents can be machine-independent.)
+ */
+static inline uint8
+typalign_to_alignby(char typalign)
+{
+ uint8 alignby;
+
+ switch (typalign)
+ {
+ case TYPALIGN_CHAR:
+ alignby = sizeof(char);
+ break;
+ case TYPALIGN_SHORT:
+ alignby = ALIGNOF_SHORT;
+ break;
+ case TYPALIGN_INT:
+ alignby = ALIGNOF_INT;
+ break;
+ case TYPALIGN_DOUBLE:
+ alignby = ALIGNOF_DOUBLE;
+ break;
+ default:
+#ifndef FRONTEND
+ elog(ERROR, "invalid typalign value: %c", typalign);
+#else
+ fprintf(stderr, "invalid typalign value: %c\n", typalign);
+ exit(1);
+#endif
+ alignby = 0;
+ break;
+ }
+ return alignby;
+}
+
/*
* att_align_datum aligns the given offset as needed for a datum of alignment
* requirement attalign and typlen attlen. attdatum is the Datum variable
@@ -139,19 +176,11 @@ fetch_att(const void *T, bool attbyval, int attlen)
* * within arrays and multiranges, we unconditionally align varlenas (XXX this
* should be revisited, probably).
*
- * The attalign cases are tested in what is hopefully something like their
- * frequency of occurrence.
+ * In performance-critical loops, avoid using this macro; instead use
+ * att_nominal_alignby with a pre-computed alignby value.
*/
#define att_align_nominal(cur_offset, attalign) \
-( \
- ((attalign) == TYPALIGN_INT) ? INTALIGN(cur_offset) : \
- (((attalign) == TYPALIGN_CHAR) ? (uintptr_t) (cur_offset) : \
- (((attalign) == TYPALIGN_DOUBLE) ? DOUBLEALIGN(cur_offset) : \
- ( \
- AssertMacro((attalign) == TYPALIGN_SHORT), \
- SHORTALIGN(cur_offset) \
- ))) \
-)
+ att_nominal_alignby(cur_offset, typalign_to_alignby(attalign))
/*
* Similar to att_align_nominal, but accepts a number of bytes, typically from
diff --git a/src/include/utils/arrayaccess.h b/src/include/utils/arrayaccess.h
index abb8659de02..a325ae52574 100644
--- a/src/include/utils/arrayaccess.h
+++ b/src/include/utils/arrayaccess.h
@@ -22,8 +22,8 @@
* Functions for iterating through elements of a flat or expanded array.
* These require a state struct "array_iter iter".
*
- * Use "array_iter_setup(&iter, arrayptr);" to prepare to iterate, and
- * "datumvar = array_iter_next(&iter, &isnullvar, index, ...);" to fetch
+ * Use "array_iter_setup(&iter, arrayptr, ...);" to prepare to iterate,
+ * and "datumvar = array_iter_next(&iter, &isnullvar, index);" to fetch
* the next element into datumvar/isnullvar.
* "index" must be the zero-origin element number; we make caller provide
* this since caller is generally counting the elements anyway. Despite
@@ -42,11 +42,17 @@ typedef struct array_iter
char *dataptr; /* Current spot in the data area */
bits8 *bitmapptr; /* Current byte of the nulls bitmap, or NULL */
int bitmask; /* mask for current bit in nulls bitmap */
+
+ /* Fields used in both cases: data about array's element type */
+ int elmlen;
+ bool elmbyval;
+ uint8 elmalignby;
} array_iter;
static inline void
-array_iter_setup(array_iter *it, AnyArrayType *a)
+array_iter_setup(array_iter *it, AnyArrayType *a,
+ int elmlen, bool elmbyval, char elmalign)
{
if (VARATT_IS_EXPANDED_HEADER(a))
{
@@ -75,11 +81,13 @@ array_iter_setup(array_iter *it, AnyArrayType *a)
it->bitmapptr = ARR_NULLBITMAP((ArrayType *) a);
}
it->bitmask = 1;
+ it->elmlen = elmlen;
+ it->elmbyval = elmbyval;
+ it->elmalignby = typalign_to_alignby(elmalign);
}
static inline Datum
-array_iter_next(array_iter *it, bool *isnull, int i,
- int elmlen, bool elmbyval, char elmalign)
+array_iter_next(array_iter *it, bool *isnull, int i)
{
Datum ret;
@@ -98,10 +106,11 @@ array_iter_next(array_iter *it, bool *isnull, int i,
else
{
*isnull = false;
- ret = fetch_att(it->dataptr, elmbyval, elmlen);
- it->dataptr = att_addlength_pointer(it->dataptr, elmlen,
+ ret = fetch_att(it->dataptr, it->elmbyval, it->elmlen);
+ it->dataptr = att_addlength_pointer(it->dataptr, it->elmlen,
it->dataptr);
- it->dataptr = (char *) att_align_nominal(it->dataptr, elmalign);
+ it->dataptr = (char *) att_nominal_alignby(it->dataptr,
+ it->elmalignby);
}
it->bitmask <<= 1;
if (it->bitmask == 0x100)
diff --git a/src/pl/plpython/plpy_typeio.c b/src/pl/plpython/plpy_typeio.c
index 1f69109b081..44055de6aeb 100644
--- a/src/pl/plpython/plpy_typeio.c
+++ b/src/pl/plpython/plpy_typeio.c
@@ -735,6 +735,7 @@ PLyList_FromArray_recurse(PLyDatumToOb *elm, int *dims, int ndim, int dim,
char *dataptr = *dataptr_p;
bits8 *bitmap = *bitmap_p;
int bitmask = *bitmask_p;
+ uint8 typalignby = typalign_to_alignby(elm->typalign);
for (i = 0; i < dims[dim]; i++)
{
@@ -751,7 +752,7 @@ PLyList_FromArray_recurse(PLyDatumToOb *elm, int *dims, int ndim, int dim,
itemvalue = fetch_att(dataptr, elm->typbyval, elm->typlen);
PyList_SetItem(list, i, elm->func(elm, itemvalue));
dataptr = att_addlength_pointer(dataptr, elm->typlen, dataptr);
- dataptr = (char *) att_align_nominal(dataptr, elm->typalign);
+ dataptr = (char *) att_nominal_alignby(dataptr, typalignby);
}
/* advance bitmap pointer if any */
--
2.43.7
From 9a98723f4ba74543e304c5b76213c05cde809df6 Mon Sep 17 00:00:00 2001
From: Tom Lane <[email protected]>
Date: Thu, 29 Jan 2026 20:11:28 -0500
Subject: [PATCH v2 2/2] Decouple our alignment assumptions about int64 and
double.
Up to now we have assumed that int64 and double have the same
alignment requirement, but there are platforms on which that's
not true (notably AIX). This assumption is a bit of a wart anyway,
since it leads to confusion about which alignment setting to use.
Let's break that apart.
We actually need to split TYPALIGN_DOUBLE into three values not
two, because we need a representation for "the maximum alignment
on this platform"; composite types need to use that setting.
So this patch invents TYPALIGN_INT64 and TYPALIGN_MAX, and
propagates those into all the necessary places. It's pretty
straightforward really, though it's certainly possible I missed
a few places to change.
One of the concerns that prevented this from being done long
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 typalign_to_alignby() which
we can usually avoid using within performance-critical loops.
An issue not resolved here is that we are not consistent
about the pg_type typlen/typalign values for polymorphic
types (the "any*" types). Those shouldn't actually matter,
but why aren't they all alike?
Side notes:
I got rid of LONGALIGN[_DOWN] along with the configure probes
for ALIGNOF_LONG. We were not using those anywhere and it
seems highly unlikely that we'd do so in future.
bootstrap.c turns out to have had the wrong alignment value
for _aclitem; seems that was missed when we widened AclMode
to 64 bits. AFAICT the value wasn't used so there were no
ill effects.
I fixed a couple of places that were using hard-coded values
when they could have used TYPALIGN_xxx macros.
This will require a catversion bump.
Author: Tom Lane <[email protected]>
Reviewed-by: Andres Freund <[email protected]>
Discussion: https://postgr.es/m/[email protected]
---
configure | 64 +++----------------
configure.ac | 30 +++------
doc/src/sgml/catalogs.sgml | 8 ++-
doc/src/sgml/ref/create_type.sgml | 9 ++-
meson.build | 31 ++++-----
src/backend/access/common/tupdesc.c | 2 +-
src/backend/bootstrap/bootstrap.c | 4 +-
src/backend/catalog/Catalog.pm | 10 ++-
src/backend/catalog/heap.c | 4 +-
src/backend/catalog/pg_type.c | 9 ++-
src/backend/commands/typecmds.c | 38 +++++++++--
src/backend/tsearch/ts_typanalyze.c | 2 +-
src/backend/utils/adt/arrayfuncs.c | 2 +-
src/backend/utils/adt/orderedsetaggs.c | 2 +-
src/backend/utils/adt/rangetypes_typanalyze.c | 2 +-
src/bin/initdb/initdb.c | 2 +-
src/bin/pg_dump/pg_dump.c | 4 ++
src/include/access/tupmacs.h | 6 ++
src/include/c.h | 4 +-
src/include/catalog/pg_type.dat | 62 +++++++++---------
src/include/catalog/pg_type.h | 2 +
src/include/pg_config.h.in | 3 -
src/pl/plpython/plpy_typeio.c | 4 +-
src/test/regress/expected/create_type.out | 1 +
src/test/regress/expected/float8.out | 8 ++-
src/test/regress/expected/type_sanity.out | 8 ++-
src/test/regress/sql/create_type.sql | 1 +
src/test/regress/sql/float8.sql | 6 +-
src/test/regress/sql/type_sanity.sql | 8 ++-
29 files changed, 172 insertions(+), 164 deletions(-)
diff --git a/configure b/configure
index a10a2c85c6a..5adfb3eba45 100755
--- a/configure
+++ b/configure
@@ -17095,41 +17095,6 @@ cat >>confdefs.h <<_ACEOF
_ACEOF
-# The cast to long int works around a bug in the HP C Compiler,
-# see AC_CHECK_SIZEOF for more information.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking alignment of long" >&5
-$as_echo_n "checking alignment of long... " >&6; }
-if ${ac_cv_alignof_long+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if ac_fn_c_compute_int "$LINENO" "(long int) offsetof (ac__type_alignof_, y)" "ac_cv_alignof_long" "$ac_includes_default
-#ifndef offsetof
-# define offsetof(type, member) ((char *) &((type *) 0)->member - (char *) 0)
-#endif
-typedef struct { char x; long y; } ac__type_alignof_;"; then :
-
-else
- if test "$ac_cv_type_long" = yes; then
- { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error 77 "cannot compute alignment of long
-See \`config.log' for more details" "$LINENO" 5; }
- else
- ac_cv_alignof_long=0
- fi
-fi
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_alignof_long" >&5
-$as_echo "$ac_cv_alignof_long" >&6; }
-
-
-
-cat >>confdefs.h <<_ACEOF
-#define ALIGNOF_LONG $ac_cv_alignof_long
-_ACEOF
-
-
# The cast to long int works around a bug in the HP C Compiler,
# see AC_CHECK_SIZEOF for more information.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking alignment of int64_t" >&5
@@ -17203,27 +17168,16 @@ _ACEOF
# Compute maximum alignment of any basic type.
#
-# We require 'double' to have the strictest alignment among the basic types,
-# because otherwise the C ABI might impose 8-byte alignment on some of the
-# other C types that correspond to TYPALIGN_DOUBLE SQL types. That could
-# cause a mismatch between the tuple layout and the C struct layout of a
-# catalog tuple. We used to carefully order catalog columns such that any
-# fixed-width, attalign=4 columns were at offsets divisible by 8 regardless
-# of MAXIMUM_ALIGNOF to avoid that, but we no longer support any platforms
-# where TYPALIGN_DOUBLE != MAXIMUM_ALIGNOF.
-#
-# We assume without checking that long's alignment is at least as strong as
-# char, short, or int. Note that we intentionally do not consider any types
-# wider than 64 bits, as allowing MAXIMUM_ALIGNOF to exceed 8 would be too
-# much of a penalty for disk and memory space.
+# We assume without checking that the maximum alignment requirement is that
+# of int64_t and/or double. (On most platforms those are the same, but not
+# everywhere.) Note that we intentionally do not consider any types wider
+# than 64 bits, as allowing MAXIMUM_ALIGNOF to exceed 8 would be too much
+# of a penalty for disk and memory space.
-MAX_ALIGNOF=$ac_cv_alignof_double
-
-if test $ac_cv_alignof_long -gt $MAX_ALIGNOF ; then
- as_fn_error $? "alignment of 'long' is greater than the alignment of 'double'" "$LINENO" 5
-fi
-if test $ac_cv_alignof_int64_t -gt $MAX_ALIGNOF ; then
- as_fn_error $? "alignment of 'int64_t' is greater than the alignment of 'double'" "$LINENO" 5
+if test $ac_cv_alignof_int64_t -gt $ac_cv_alignof_double ; then
+ MAX_ALIGNOF=$ac_cv_alignof_int64_t
+else
+ MAX_ALIGNOF=$ac_cv_alignof_double
fi
cat >>confdefs.h <<_ACEOF
diff --git a/configure.ac b/configure.ac
index 814e64a967e..a5eab2e5fff 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2031,33 +2031,21 @@ AC_CHECK_SIZEOF([intmax_t])
AC_CHECK_ALIGNOF(short)
AC_CHECK_ALIGNOF(int)
-AC_CHECK_ALIGNOF(long)
AC_CHECK_ALIGNOF(int64_t)
AC_CHECK_ALIGNOF(double)
# Compute maximum alignment of any basic type.
#
-# We require 'double' to have the strictest alignment among the basic types,
-# because otherwise the C ABI might impose 8-byte alignment on some of the
-# other C types that correspond to TYPALIGN_DOUBLE SQL types. That could
-# cause a mismatch between the tuple layout and the C struct layout of a
-# catalog tuple. We used to carefully order catalog columns such that any
-# fixed-width, attalign=4 columns were at offsets divisible by 8 regardless
-# of MAXIMUM_ALIGNOF to avoid that, but we no longer support any platforms
-# where TYPALIGN_DOUBLE != MAXIMUM_ALIGNOF.
-#
-# We assume without checking that long's alignment is at least as strong as
-# char, short, or int. Note that we intentionally do not consider any types
-# wider than 64 bits, as allowing MAXIMUM_ALIGNOF to exceed 8 would be too
-# much of a penalty for disk and memory space.
-
-MAX_ALIGNOF=$ac_cv_alignof_double
+# We assume without checking that the maximum alignment requirement is that
+# of int64_t and/or double. (On most platforms those are the same, but not
+# everywhere.) Note that we intentionally do not consider any types wider
+# than 64 bits, as allowing MAXIMUM_ALIGNOF to exceed 8 would be too much
+# of a penalty for disk and memory space.
-if test $ac_cv_alignof_long -gt $MAX_ALIGNOF ; then
- AC_MSG_ERROR([alignment of 'long' is greater than the alignment of 'double'])
-fi
-if test $ac_cv_alignof_int64_t -gt $MAX_ALIGNOF ; then
- AC_MSG_ERROR([alignment of 'int64_t' is greater than the alignment of 'double'])
+if test $ac_cv_alignof_int64_t -gt $ac_cv_alignof_double ; then
+ MAX_ALIGNOF=$ac_cv_alignof_int64_t
+else
+ MAX_ALIGNOF=$ac_cv_alignof_double
fi
AC_DEFINE_UNQUOTED(MAXIMUM_ALIGNOF, $MAX_ALIGNOF, [Define as the maximum alignment requirement of any C data type.])
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 332193565e2..12608d00a18 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -9567,7 +9567,13 @@ SCRAM-SHA-256$<replaceable><iteration count></replaceable>:<replaceable>&l
<para><literal>i</literal> = <type>int</type> alignment (4 bytes on most machines).</para>
</listitem>
<listitem>
- <para><literal>d</literal> = <type>double</type> alignment (8 bytes on many machines, but by no means all).</para>
+ <para><literal>l</literal> = <type>int64</type> alignment (8 bytes on most machines, but by no means all).</para>
+ </listitem>
+ <listitem>
+ <para><literal>d</literal> = <type>double</type> alignment (8 bytes on most machines, but by no means all).</para>
+ </listitem>
+ <listitem>
+ <para><literal>m</literal> = maximum alignment (8 bytes on most machines).</para>
</listitem>
</itemizedlist>
</para></entry>
diff --git a/doc/src/sgml/ref/create_type.sgml b/doc/src/sgml/ref/create_type.sgml
index 994dfc65268..006db624094 100644
--- a/doc/src/sgml/ref/create_type.sgml
+++ b/doc/src/sgml/ref/create_type.sgml
@@ -748,8 +748,15 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
<para>
The storage alignment requirement of the data type. If specified,
it must be <literal>char</literal>, <literal>int2</literal>,
- <literal>int4</literal>, or <literal>double</literal>; the
+ <literal>int4</literal>, <literal>int8</literal>,
+ <literal>double</literal>, or <literal>max</literal>; the
default is <literal>int4</literal>.
+ <literal>int8</literal> and <literal>double</literal> usually
+ have the same behavior, but there are platforms on which they are
+ different because integer and floating-point values have different
+ requirements. <literal>max</literal> means the maximum alignment
+ requirement for any of these types; it is often used for container
+ types such as records.
</para>
</listitem>
</varlistentry>
diff --git a/meson.build b/meson.build
index df907b62da3..bb17859fee4 100644
--- a/meson.build
+++ b/meson.build
@@ -1798,32 +1798,27 @@ endif
# Determine memory alignment requirements for the basic C data types.
-alignof_types = ['short', 'int', 'long', 'double']
+alignof_types = ['short', 'int', 'int64_t', 'double']
foreach t : alignof_types
- align = cc.alignment(t, args: test_c_args)
+ align = cc.alignment(t, args: test_c_args, prefix: '#include <stdint.h>')
cdata.set('ALIGNOF_@0@'.format(t.to_upper()), align)
endforeach
# Compute maximum alignment of any basic type.
#
-# We require 'double' to have the strictest alignment among the basic types,
-# because otherwise the C ABI might impose 8-byte alignment on some of the
-# other C types that correspond to TYPALIGN_DOUBLE SQL types. That could
-# cause a mismatch between the tuple layout and the C struct layout of a
-# catalog tuple. We used to carefully order catalog columns such that any
-# fixed-width, attalign=4 columns were at offsets divisible by 8 regardless
-# of MAXIMUM_ALIGNOF to avoid that, but we no longer support any platforms
-# where TYPALIGN_DOUBLE != MAXIMUM_ALIGNOF.
-#
-# We assume without checking that int64_t's alignment is at least as strong
-# as long, char, short, or int. Note that we intentionally do not consider
-# any types wider than 64 bits, as allowing MAXIMUM_ALIGNOF to exceed 8
-# would be too much of a penalty for disk and memory space.
+# We assume without checking that the maximum alignment requirement is that
+# of int64_t and/or double. (On most platforms those are the same, but not
+# everywhere.) Note that we intentionally do not consider any types wider
+# than 64 bits, as allowing MAXIMUM_ALIGNOF to exceed 8 would be too much
+# of a penalty for disk and memory space.
+
+alignof_int64_t = cdata.get('ALIGNOF_INT64_T')
alignof_double = cdata.get('ALIGNOF_DOUBLE')
-if cc.alignment('int64_t', args: test_c_args, prefix: '#include <stdint.h>') > alignof_double
- error('alignment of int64_t is greater than the alignment of double')
+if alignof_int64_t > alignof_double
+ cdata.set('MAXIMUM_ALIGNOF', alignof_int64_t)
+else
+ cdata.set('MAXIMUM_ALIGNOF', alignof_double)
endif
-cdata.set('MAXIMUM_ALIGNOF', alignof_double)
cdata.set('SIZEOF_LONG', cc.sizeof('long', args: test_c_args))
cdata.set('SIZEOF_LONG_LONG', cc.sizeof('long long', args: test_c_args))
diff --git a/src/backend/access/common/tupdesc.c b/src/backend/access/common/tupdesc.c
index b69d10f0a45..47b9f8b5459 100644
--- a/src/backend/access/common/tupdesc.c
+++ b/src/backend/access/common/tupdesc.c
@@ -977,7 +977,7 @@ TupleDescInitBuiltinEntry(TupleDesc desc,
case INT8OID:
att->attlen = 8;
att->attbyval = true;
- att->attalign = TYPALIGN_DOUBLE;
+ att->attalign = TYPALIGN_INT64;
att->attstorage = TYPSTORAGE_PLAIN;
att->attcompression = InvalidCompressionMethod;
att->attcollation = InvalidOid;
diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index dd57624b4f9..7a3a13a6ec7 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -115,7 +115,7 @@ static const struct typinfo TypInfo[] = {
F_TEXTIN, F_TEXTOUT},
{"oid", OIDOID, 0, 4, true, TYPALIGN_INT, TYPSTORAGE_PLAIN, InvalidOid,
F_OIDIN, F_OIDOUT},
- {"oid8", OID8OID, 0, 8, true, TYPALIGN_DOUBLE, TYPSTORAGE_PLAIN, InvalidOid,
+ {"oid8", OID8OID, 0, 8, true, TYPALIGN_INT64, TYPSTORAGE_PLAIN, InvalidOid,
F_OID8IN, F_OID8OUT},
{"tid", TIDOID, 0, 6, false, TYPALIGN_SHORT, TYPSTORAGE_PLAIN, InvalidOid,
F_TIDIN, F_TIDOUT},
@@ -137,7 +137,7 @@ static const struct typinfo TypInfo[] = {
F_ARRAY_IN, F_ARRAY_OUT},
{"_char", 1002, CHAROID, -1, false, TYPALIGN_INT, TYPSTORAGE_EXTENDED, InvalidOid,
F_ARRAY_IN, F_ARRAY_OUT},
- {"_aclitem", 1034, ACLITEMOID, -1, false, TYPALIGN_INT, TYPSTORAGE_EXTENDED, InvalidOid,
+ {"_aclitem", 1034, ACLITEMOID, -1, false, TYPALIGN_INT64, TYPSTORAGE_EXTENDED, InvalidOid,
F_ARRAY_IN, F_ARRAY_OUT}
};
diff --git a/src/backend/catalog/Catalog.pm b/src/backend/catalog/Catalog.pm
index 219af5884d9..20884f45bd8 100644
--- a/src/backend/catalog/Catalog.pm
+++ b/src/backend/catalog/Catalog.pm
@@ -464,9 +464,13 @@ sub GenerateArrayTypes
$array_type{typname} = '_' . $elem_type->{typname};
$array_type{typelem} = $elem_type->{typname};
- # Arrays require INT alignment, unless the element type requires
- # DOUBLE alignment.
- $array_type{typalign} = $elem_type->{typalign} eq 'd' ? 'd' : 'i';
+ # Arrays require INT alignment, unless the element type requires more.
+ $array_type{typalign} =
+ $elem_type->{typalign} eq 'l' ? 'l'
+ : (
+ $elem_type->{typalign} eq 'd' ? 'd'
+ : ( $elem_type->{typalign} eq 'm' ? 'm'
+ : 'i'));
# Fill in the rest of the array entry's fields.
foreach my $column (@$pgtype_schema)
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 606434823cf..27cc09a7680 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -1075,7 +1075,7 @@ AddNewRelationType(const char *typeName,
NULL, /* default value - none */
NULL, /* default binary representation */
false, /* passed by reference */
- TYPALIGN_DOUBLE, /* alignment - must be the largest! */
+ TYPALIGN_MAX, /* alignment - must be the largest! */
TYPSTORAGE_EXTENDED, /* fully TOASTable */
-1, /* typmod */
0, /* array dimensions for typBaseType */
@@ -1399,7 +1399,7 @@ heap_create_with_catalog(const char *relname,
NULL, /* default value - none */
NULL, /* default binary representation */
false, /* passed by reference */
- TYPALIGN_DOUBLE, /* alignment - must be the largest! */
+ TYPALIGN_MAX, /* alignment - must be the largest! */
TYPSTORAGE_EXTENDED, /* fully TOASTable */
-1, /* typmod */
0, /* array dimensions for typBaseType */
diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c
index fc369c35aa6..f079fa32b40 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -287,7 +287,9 @@ TypeCreate(Oid newTypeOid,
}
else if (internalSize == (int16) sizeof(int64))
{
- if (alignment != TYPALIGN_DOUBLE)
+ /* We have to trust the user to get this distinction right ... */
+ if (!(alignment == TYPALIGN_INT64 ||
+ alignment == TYPALIGN_DOUBLE))
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
@@ -303,7 +305,10 @@ TypeCreate(Oid newTypeOid,
{
/* varlena types must have int align or better */
if (internalSize == -1 &&
- !(alignment == TYPALIGN_INT || alignment == TYPALIGN_DOUBLE))
+ !(alignment == TYPALIGN_INT ||
+ alignment == TYPALIGN_INT64 ||
+ alignment == TYPALIGN_DOUBLE ||
+ alignment == TYPALIGN_MAX))
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("alignment \"%c\" is invalid for variable-length type",
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 288edb25f2f..2f919f764aa 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -117,6 +117,7 @@ static void makeMultirangeConstructors(const char *name, Oid namespace,
Oid multirangeOid, Oid rangeOid,
Oid rangeArrayOid,
Oid *mltrngConstruct0_p, Oid *mltrngConstruct1_p, Oid *mltrngConstruct2_p);
+static char containerAlignment(char elemalign);
static Oid findTypeInputFunction(List *procname, Oid typeOid);
static Oid findTypeOutputFunction(List *procname, Oid typeOid);
static Oid findTypeReceiveFunction(List *procname, Oid typeOid);
@@ -424,6 +425,9 @@ DefineType(ParseState *pstate, List *names, List *parameters)
pg_strcasecmp(a, "float8") == 0 ||
pg_strcasecmp(a, "pg_catalog.float8") == 0)
alignment = TYPALIGN_DOUBLE;
+ else if (pg_strcasecmp(a, "int8") == 0 ||
+ pg_strcasecmp(a, "pg_catalog.int8") == 0)
+ alignment = TYPALIGN_INT64;
else if (pg_strcasecmp(a, "int4") == 0 ||
pg_strcasecmp(a, "pg_catalog.int4") == 0)
alignment = TYPALIGN_INT;
@@ -433,6 +437,9 @@ DefineType(ParseState *pstate, List *names, List *parameters)
else if (pg_strcasecmp(a, "char") == 0 ||
pg_strcasecmp(a, "pg_catalog.bpchar") == 0)
alignment = TYPALIGN_CHAR;
+ else if (pg_strcasecmp(a, "max") == 0 ||
+ pg_strcasecmp(a, "pg_catalog.max") == 0)
+ alignment = TYPALIGN_MAX;
else
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
@@ -611,8 +618,8 @@ DefineType(ParseState *pstate, List *names, List *parameters)
*/
array_type = makeArrayTypeName(typeName, typeNamespace);
- /* alignment must be TYPALIGN_INT or TYPALIGN_DOUBLE for arrays */
- alignment = (alignment == TYPALIGN_DOUBLE) ? TYPALIGN_DOUBLE : TYPALIGN_INT;
+ /* alignment must be TYPALIGN_INT or more for arrays */
+ alignment = containerAlignment(alignment);
TypeCreate(array_oid, /* force assignment of this type OID */
array_type, /* type name */
@@ -1095,8 +1102,8 @@ DefineDomain(ParseState *pstate, CreateDomainStmt *stmt)
*/
domainArrayName = makeArrayTypeName(domainName, domainNamespace);
- /* alignment must be TYPALIGN_INT or TYPALIGN_DOUBLE for arrays */
- alignment = (alignment == TYPALIGN_DOUBLE) ? TYPALIGN_DOUBLE : TYPALIGN_INT;
+ /* alignment must be TYPALIGN_INT or more for arrays */
+ alignment = containerAlignment(alignment);
TypeCreate(domainArrayOid, /* force assignment of this type OID */
domainArrayName, /* type name */
@@ -1557,8 +1564,8 @@ DefineRange(ParseState *pstate, CreateRangeStmt *stmt)
get_typlenbyvalalign(rangeSubtype,
&subtyplen, &subtypbyval, &subtypalign);
- /* alignment must be TYPALIGN_INT or TYPALIGN_DOUBLE for ranges */
- alignment = (subtypalign == TYPALIGN_DOUBLE) ? TYPALIGN_DOUBLE : TYPALIGN_INT;
+ /* alignment must be TYPALIGN_INT or more for ranges */
+ alignment = containerAlignment(subtypalign);
/* Allocate OID for array type, its multirange, and its multirange array */
rangeArrayOid = AssignTypeArrayOid();
@@ -2005,6 +2012,25 @@ makeMultirangeConstructors(const char *name, Oid namespace,
pfree(parameterModes);
}
+/*
+ * Compute the appropriate typalign for a container (array or range)
+ * given the typalign of its members. The container type requires at
+ * least int alignment, but more if the members need more.
+ */
+static char
+containerAlignment(char elemalign)
+{
+ switch (elemalign)
+ {
+ case TYPALIGN_INT64:
+ case TYPALIGN_DOUBLE:
+ case TYPALIGN_MAX:
+ return elemalign;
+ default:
+ return TYPALIGN_INT;
+ }
+}
+
/*
* Find suitable I/O and other support functions for a type.
*
diff --git a/src/backend/tsearch/ts_typanalyze.c b/src/backend/tsearch/ts_typanalyze.c
index 0c513d694e7..48ee050e37f 100644
--- a/src/backend/tsearch/ts_typanalyze.c
+++ b/src/backend/tsearch/ts_typanalyze.c
@@ -444,7 +444,7 @@ compute_tsvector_stats(VacAttrStats *stats,
stats->statypid[0] = TEXTOID;
stats->statyplen[0] = -1; /* typlen, -1 for varlena */
stats->statypbyval[0] = false;
- stats->statypalign[0] = 'i';
+ stats->statypalign[0] = TYPALIGN_INT;
}
}
else
diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c
index da68915ee20..08e26335a95 100644
--- a/src/backend/utils/adt/arrayfuncs.c
+++ b/src/backend/utils/adt/arrayfuncs.c
@@ -3431,7 +3431,7 @@ construct_array_builtin(Datum *elems, int nelems, Oid elmtype)
case INT8OID:
elmlen = sizeof(int64);
elmbyval = true;
- elmalign = TYPALIGN_DOUBLE;
+ elmalign = TYPALIGN_INT64;
break;
case NAMEOID:
diff --git a/src/backend/utils/adt/orderedsetaggs.c b/src/backend/utils/adt/orderedsetaggs.c
index 3b6da8e36ac..27b8cfa7064 100644
--- a/src/backend/utils/adt/orderedsetaggs.c
+++ b/src/backend/utils/adt/orderedsetaggs.c
@@ -1021,7 +1021,7 @@ percentile_cont_interval_multi_final(PG_FUNCTION_ARGS)
return percentile_cont_multi_final_common(fcinfo,
INTERVALOID,
/* hard-wired info on type interval */
- 16, false, TYPALIGN_DOUBLE,
+ 16, false, TYPALIGN_INT64,
interval_lerp);
}
diff --git a/src/backend/utils/adt/rangetypes_typanalyze.c b/src/backend/utils/adt/rangetypes_typanalyze.c
index 38d12dedbc5..278d4e6941a 100644
--- a/src/backend/utils/adt/rangetypes_typanalyze.c
+++ b/src/backend/utils/adt/rangetypes_typanalyze.c
@@ -398,7 +398,7 @@ compute_range_stats(VacAttrStats *stats, AnalyzeAttrFetchFunc fetchfunc,
stats->statypid[slot_idx] = FLOAT8OID;
stats->statyplen[slot_idx] = sizeof(float8);
stats->statypbyval[slot_idx] = true;
- stats->statypalign[slot_idx] = 'd';
+ stats->statypalign[slot_idx] = TYPALIGN_DOUBLE;
/* Store the fraction of empty ranges */
emptyfrac = palloc_object(float4);
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index a3980e5535f..e550e9cf0a3 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -1580,7 +1580,7 @@ bootstrap_template1(void)
bki_lines = replace_token(bki_lines, "SIZEOF_POINTER", buf);
bki_lines = replace_token(bki_lines, "ALIGNOF_POINTER",
- (sizeof(Pointer) == 4) ? "i" : "d");
+ (sizeof(Pointer) == 4) ? "i" : "l");
bki_lines = replace_token(bki_lines, "POSTGRES",
escape_quotes_bki(username));
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 2bebefd0ba2..1b44c03170f 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -12652,8 +12652,12 @@ dumpBaseType(Archive *fout, const TypeInfo *tyinfo)
appendPQExpBufferStr(q, ",\n ALIGNMENT = int2");
else if (*typalign == TYPALIGN_INT)
appendPQExpBufferStr(q, ",\n ALIGNMENT = int4");
+ else if (*typalign == TYPALIGN_INT64)
+ appendPQExpBufferStr(q, ",\n ALIGNMENT = int8");
else if (*typalign == TYPALIGN_DOUBLE)
appendPQExpBufferStr(q, ",\n ALIGNMENT = double");
+ else if (*typalign == TYPALIGN_MAX)
+ appendPQExpBufferStr(q, ",\n ALIGNMENT = max");
if (*typstorage == TYPSTORAGE_PLAIN)
appendPQExpBufferStr(q, ",\n STORAGE = plain");
diff --git a/src/include/access/tupmacs.h b/src/include/access/tupmacs.h
index d64c18b950b..e7db125f627 100644
--- a/src/include/access/tupmacs.h
+++ b/src/include/access/tupmacs.h
@@ -92,9 +92,15 @@ typalign_to_alignby(char typalign)
case TYPALIGN_INT:
alignby = ALIGNOF_INT;
break;
+ case TYPALIGN_INT64:
+ alignby = ALIGNOF_INT64_T;
+ break;
case TYPALIGN_DOUBLE:
alignby = ALIGNOF_DOUBLE;
break;
+ case TYPALIGN_MAX:
+ alignby = MAXIMUM_ALIGNOF;
+ break;
default:
#ifndef FRONTEND
elog(ERROR, "invalid typalign value: %c", typalign);
diff --git a/src/include/c.h b/src/include/c.h
index c443e75b89f..c7956ce91bc 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -821,7 +821,7 @@ typedef NameData *Name;
#define SHORTALIGN(LEN) TYPEALIGN(ALIGNOF_SHORT, (LEN))
#define INTALIGN(LEN) TYPEALIGN(ALIGNOF_INT, (LEN))
-#define LONGALIGN(LEN) TYPEALIGN(ALIGNOF_LONG, (LEN))
+#define INT64ALIGN(LEN) TYPEALIGN(ALIGNOF_INT64_T, (LEN))
#define DOUBLEALIGN(LEN) TYPEALIGN(ALIGNOF_DOUBLE, (LEN))
#define MAXALIGN(LEN) TYPEALIGN(MAXIMUM_ALIGNOF, (LEN))
/* MAXALIGN covers only built-in types, not buffers */
@@ -833,7 +833,7 @@ typedef NameData *Name;
#define SHORTALIGN_DOWN(LEN) TYPEALIGN_DOWN(ALIGNOF_SHORT, (LEN))
#define INTALIGN_DOWN(LEN) TYPEALIGN_DOWN(ALIGNOF_INT, (LEN))
-#define LONGALIGN_DOWN(LEN) TYPEALIGN_DOWN(ALIGNOF_LONG, (LEN))
+#define INT64ALIGN_DOWN(LEN) TYPEALIGN_DOWN(ALIGNOF_INT64_T, (LEN))
#define DOUBLEALIGN_DOWN(LEN) TYPEALIGN_DOWN(ALIGNOF_DOUBLE, (LEN))
#define MAXALIGN_DOWN(LEN) TYPEALIGN_DOWN(MAXIMUM_ALIGNOF, (LEN))
#define BUFFERALIGN_DOWN(LEN) TYPEALIGN_DOWN(ALIGNOF_BUFFER, (LEN))
diff --git a/src/include/catalog/pg_type.dat b/src/include/catalog/pg_type.dat
index a1a753d1797..d511493f761 100644
--- a/src/include/catalog/pg_type.dat
+++ b/src/include/catalog/pg_type.dat
@@ -56,7 +56,7 @@
descr => '~18 digit integer, 8-byte storage',
typname => 'int8', typlen => '8', typbyval => 't',
typcategory => 'N', typinput => 'int8in', typoutput => 'int8out',
- typreceive => 'int8recv', typsend => 'int8send', typalign => 'd' },
+ typreceive => 'int8recv', typsend => 'int8send', typalign => 'l' },
{ oid => '21', array_type_oid => '1005',
descr => '-32 thousand to 32 thousand, 2-byte storage',
typname => 'int2', typlen => '2', typbyval => 't', typcategory => 'N',
@@ -116,22 +116,22 @@
typname => 'pg_type', typlen => '-1', typbyval => 'f', typtype => 'c',
typcategory => 'C', typrelid => 'pg_type', typinput => 'record_in',
typoutput => 'record_out', typreceive => 'record_recv',
- typsend => 'record_send', typalign => 'd', typstorage => 'x' },
+ typsend => 'record_send', typalign => 'm', typstorage => 'x' },
{ oid => '75', array_type_oid => '270',
typname => 'pg_attribute', typlen => '-1', typbyval => 'f', typtype => 'c',
typcategory => 'C', typrelid => 'pg_attribute', typinput => 'record_in',
typoutput => 'record_out', typreceive => 'record_recv',
- typsend => 'record_send', typalign => 'd', typstorage => 'x' },
+ typsend => 'record_send', typalign => 'm', typstorage => 'x' },
{ oid => '81', array_type_oid => '272',
typname => 'pg_proc', typlen => '-1', typbyval => 'f', typtype => 'c',
typcategory => 'C', typrelid => 'pg_proc', typinput => 'record_in',
typoutput => 'record_out', typreceive => 'record_recv',
- typsend => 'record_send', typalign => 'd', typstorage => 'x' },
+ typsend => 'record_send', typalign => 'm', typstorage => 'x' },
{ oid => '83', array_type_oid => '273',
typname => 'pg_class', typlen => '-1', typbyval => 'f', typtype => 'c',
typcategory => 'C', typrelid => 'pg_class', typinput => 'record_in',
typoutput => 'record_out', typreceive => 'record_recv',
- typsend => 'record_send', typalign => 'd', typstorage => 'x' },
+ typsend => 'record_send', typalign => 'm', typstorage => 'x' },
# OIDS 100 - 199
@@ -174,7 +174,7 @@
{ oid => '5069', array_type_oid => '271', descr => 'full transaction id',
typname => 'xid8', typlen => '8', typbyval => 't',
typcategory => 'U', typinput => 'xid8in', typoutput => 'xid8out',
- typreceive => 'xid8recv', typsend => 'xid8send', typalign => 'd' },
+ typreceive => 'xid8recv', typsend => 'xid8send', typalign => 'l' },
# OIDS 600 - 699
@@ -239,7 +239,7 @@
descr => 'monetary amounts, $d,ddd.cc',
typname => 'money', typlen => '8', typbyval => 't',
typcategory => 'N', typinput => 'cash_in', typoutput => 'cash_out',
- typreceive => 'cash_recv', typsend => 'cash_send', typalign => 'd' },
+ typreceive => 'cash_recv', typsend => 'cash_send', typalign => 'l' },
# OIDS 800 - 899
@@ -270,7 +270,7 @@
{ oid => '1033', array_type_oid => '1034', descr => 'access control list',
typname => 'aclitem', typlen => '16', typbyval => 'f', typcategory => 'U',
typinput => 'aclitemin', typoutput => 'aclitemout', typreceive => '-',
- typsend => '-', typalign => 'd' },
+ typsend => '-', typalign => 'l' },
{ oid => '1042', array_type_oid => '1014',
descr => '\'char(length)\' blank-padded string, fixed storage length',
typname => 'bpchar', typlen => '-1', typbyval => 'f', typcategory => 'S',
@@ -293,7 +293,7 @@
typname => 'time', typlen => '8', typbyval => 't',
typcategory => 'D', typinput => 'time_in', typoutput => 'time_out',
typreceive => 'time_recv', typsend => 'time_send', typmodin => 'timetypmodin',
- typmodout => 'timetypmodout', typalign => 'd' },
+ typmodout => 'timetypmodout', typalign => 'l' },
# OIDS 1100 - 1199
@@ -302,21 +302,21 @@
typcategory => 'D', typinput => 'timestamp_in', typoutput => 'timestamp_out',
typreceive => 'timestamp_recv', typsend => 'timestamp_send',
typmodin => 'timestamptypmodin', typmodout => 'timestamptypmodout',
- typalign => 'd' },
+ typalign => 'l' },
{ oid => '1184', array_type_oid => '1185',
descr => 'date and time with time zone',
typname => 'timestamptz', typlen => '8', typbyval => 't',
typcategory => 'D', typispreferred => 't', typinput => 'timestamptz_in',
typoutput => 'timestamptz_out', typreceive => 'timestamptz_recv',
typsend => 'timestamptz_send', typmodin => 'timestamptztypmodin',
- typmodout => 'timestamptztypmodout', typalign => 'd' },
+ typmodout => 'timestamptztypmodout', typalign => 'l' },
{ oid => '1186', array_type_oid => '1187',
descr => 'time interval, format \'number units ...\'',
typname => 'interval', typlen => '16', typbyval => 'f', typcategory => 'T',
typispreferred => 't', typinput => 'interval_in', typoutput => 'interval_out',
typreceive => 'interval_recv', typsend => 'interval_send',
typmodin => 'intervaltypmodin', typmodout => 'intervaltypmodout',
- typalign => 'd' },
+ typalign => 'l' },
# OIDS 1200 - 1299
@@ -326,7 +326,7 @@
typinput => 'timetz_in', typoutput => 'timetz_out',
typreceive => 'timetz_recv', typsend => 'timetz_send',
typmodin => 'timetztypmodin', typmodout => 'timetztypmodout',
- typalign => 'd' },
+ typalign => 'l' },
# OIDS 1500 - 1599
@@ -415,7 +415,7 @@
{ oid => '3220', array_type_oid => '3221', descr => 'PostgreSQL LSN',
typname => 'pg_lsn', typlen => '8', typbyval => 't',
typcategory => 'U', typinput => 'pg_lsn_in', typoutput => 'pg_lsn_out',
- typreceive => 'pg_lsn_recv', typsend => 'pg_lsn_send', typalign => 'd' },
+ typreceive => 'pg_lsn_recv', typsend => 'pg_lsn_send', typalign => 'l' },
# text search
{ oid => '3614', array_type_oid => '3643',
@@ -462,12 +462,12 @@
typname => 'txid_snapshot', typlen => '-1', typbyval => 'f',
typcategory => 'U', typinput => 'txid_snapshot_in',
typoutput => 'txid_snapshot_out', typreceive => 'txid_snapshot_recv',
- typsend => 'txid_snapshot_send', typalign => 'd', typstorage => 'x' },
+ typsend => 'txid_snapshot_send', typalign => 'l', typstorage => 'x' },
{ oid => '5038', array_type_oid => '5039', descr => 'transaction snapshot',
typname => 'pg_snapshot', typlen => '-1', typbyval => 'f', typcategory => 'U',
typinput => 'pg_snapshot_in', typoutput => 'pg_snapshot_out',
typreceive => 'pg_snapshot_recv', typsend => 'pg_snapshot_send',
- typalign => 'd', typstorage => 'x' },
+ typalign => 'l', typstorage => 'x' },
# range types
{ oid => '3904', array_type_oid => '3905', descr => 'range of integers',
@@ -485,13 +485,13 @@
typname => 'tsrange', typlen => '-1', typbyval => 'f', typtype => 'r',
typcategory => 'R', typinput => 'range_in', typoutput => 'range_out',
typreceive => 'range_recv', typsend => 'range_send',
- typanalyze => 'range_typanalyze', typalign => 'd', typstorage => 'x' },
+ typanalyze => 'range_typanalyze', typalign => 'l', typstorage => 'x' },
{ oid => '3910', array_type_oid => '3911',
descr => 'range of timestamps with time zone',
typname => 'tstzrange', typlen => '-1', typbyval => 'f', typtype => 'r',
typcategory => 'R', typinput => 'range_in', typoutput => 'range_out',
typreceive => 'range_recv', typsend => 'range_send',
- typanalyze => 'range_typanalyze', typalign => 'd', typstorage => 'x' },
+ typanalyze => 'range_typanalyze', typalign => 'l', typstorage => 'x' },
{ oid => '3912', array_type_oid => '3913', descr => 'range of dates',
typname => 'daterange', typlen => '-1', typbyval => 'f', typtype => 'r',
typcategory => 'R', typinput => 'range_in', typoutput => 'range_out',
@@ -501,7 +501,7 @@
typname => 'int8range', typlen => '-1', typbyval => 'f', typtype => 'r',
typcategory => 'R', typinput => 'range_in', typoutput => 'range_out',
typreceive => 'range_recv', typsend => 'range_send',
- typanalyze => 'range_typanalyze', typalign => 'd', typstorage => 'x' },
+ typanalyze => 'range_typanalyze', typalign => 'l', typstorage => 'x' },
# multirange types
{ oid => '4451', array_type_oid => '6150', descr => 'multirange of integers',
@@ -522,14 +522,14 @@
typcategory => 'R', typinput => 'multirange_in',
typoutput => 'multirange_out', typreceive => 'multirange_recv',
typsend => 'multirange_send', typanalyze => 'multirange_typanalyze',
- typalign => 'd', typstorage => 'x' },
+ typalign => 'l', typstorage => 'x' },
{ oid => '4534', array_type_oid => '6153',
descr => 'multirange of timestamps with time zone',
typname => 'tstzmultirange', typlen => '-1', typbyval => 'f', typtype => 'm',
typcategory => 'R', typinput => 'multirange_in',
typoutput => 'multirange_out', typreceive => 'multirange_recv',
typsend => 'multirange_send', typanalyze => 'multirange_typanalyze',
- typalign => 'd', typstorage => 'x' },
+ typalign => 'l', typstorage => 'x' },
{ oid => '4535', array_type_oid => '6155', descr => 'multirange of dates',
typname => 'datemultirange', typlen => '-1', typbyval => 'f', typtype => 'm',
typcategory => 'R', typinput => 'multirange_in',
@@ -541,7 +541,7 @@
typcategory => 'R', typinput => 'multirange_in',
typoutput => 'multirange_out', typreceive => 'multirange_recv',
typsend => 'multirange_send', typanalyze => 'multirange_typanalyze',
- typalign => 'd', typstorage => 'x' },
+ typalign => 'l', typstorage => 'x' },
# pseudo-types
# types with typtype='p' represent various special cases in the type system.
@@ -556,14 +556,14 @@
typname => 'record', typlen => '-1', typbyval => 'f', typtype => 'p',
typcategory => 'P', typarray => '_record', typinput => 'record_in',
typoutput => 'record_out', typreceive => 'record_recv',
- typsend => 'record_send', typalign => 'd', typstorage => 'x' },
+ typsend => 'record_send', typalign => 'm', typstorage => 'x' },
# Arrays of records have typcategory P, so they can't be autogenerated.
{ oid => '2287',
typname => '_record', typlen => '-1', typbyval => 'f', typtype => 'p',
typcategory => 'P', typsubscript => 'array_subscript_handler',
typelem => 'record', typinput => 'array_in', typoutput => 'array_out',
typreceive => 'array_recv', typsend => 'array_send',
- typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' },
+ typanalyze => 'array_typanalyze', typalign => 'm', typstorage => 'x' },
{ oid => '2275', array_type_oid => '1263', descr => 'C-style string',
typname => 'cstring', typlen => '-2', typbyval => 'f', typtype => 'p',
typcategory => 'P', typinput => 'cstring_in', typoutput => 'cstring_out',
@@ -575,7 +575,7 @@
{ oid => '2277', descr => 'pseudo-type representing a polymorphic array type',
typname => 'anyarray', typlen => '-1', typbyval => 'f', typtype => 'p',
typcategory => 'P', typinput => 'anyarray_in', typoutput => 'anyarray_out',
- typreceive => 'anyarray_recv', typsend => 'anyarray_send', typalign => 'd',
+ typreceive => 'anyarray_recv', typsend => 'anyarray_send', typalign => 'm',
typstorage => 'x' },
{ oid => '2278',
descr => 'pseudo-type for the result of a function with no real result',
@@ -648,7 +648,7 @@
descr => 'pseudo-type representing a range over a polymorphic base type',
typname => 'anyrange', typlen => '-1', typbyval => 'f', typtype => 'p',
typcategory => 'P', typinput => 'anyrange_in', typoutput => 'anyrange_out',
- typreceive => '-', typsend => '-', typalign => 'd', typstorage => 'x' },
+ typreceive => '-', typsend => '-', typalign => 'm', typstorage => 'x' },
{ oid => '5077',
descr => 'pseudo-type representing a polymorphic common type',
typname => 'anycompatible', typlen => '4', typbyval => 't', typtype => 'p',
@@ -661,7 +661,7 @@
typtype => 'p', typcategory => 'P', typinput => 'anycompatiblearray_in',
typoutput => 'anycompatiblearray_out',
typreceive => 'anycompatiblearray_recv', typsend => 'anycompatiblearray_send',
- typalign => 'd', typstorage => 'x' },
+ typalign => 'm', typstorage => 'x' },
{ oid => '5079',
descr => 'pseudo-type representing a polymorphic common type that is not an array',
typname => 'anycompatiblenonarray', typlen => '4', typbyval => 't',
@@ -673,19 +673,19 @@
typname => 'anycompatiblerange', typlen => '-1', typbyval => 'f',
typtype => 'p', typcategory => 'P', typinput => 'anycompatiblerange_in',
typoutput => 'anycompatiblerange_out', typreceive => '-', typsend => '-',
- typalign => 'd', typstorage => 'x' },
+ typalign => 'm', typstorage => 'x' },
{ oid => '4537',
descr => 'pseudo-type representing a polymorphic base type that is a multirange',
typname => 'anymultirange', typlen => '-1', typbyval => 'f', typtype => 'p',
typcategory => 'P', typinput => 'anymultirange_in',
typoutput => 'anymultirange_out', typreceive => '-', typsend => '-',
- typalign => 'd', typstorage => 'x' },
+ typalign => 'm', typstorage => 'x' },
{ oid => '4538',
descr => 'pseudo-type representing a multirange over a polymorphic common type',
typname => 'anycompatiblemultirange', typlen => '-1', typbyval => 'f',
typtype => 'p', typcategory => 'P', typinput => 'anycompatiblemultirange_in',
typoutput => 'anycompatiblemultirange_out', typreceive => '-', typsend => '-',
- typalign => 'd', typstorage => 'x' },
+ typalign => 'm', typstorage => 'x' },
{ oid => '4600', descr => 'pseudo-type representing BRIN bloom summary',
typname => 'pg_brin_bloom_summary', typlen => '-1', typbyval => 'f',
typcategory => 'Z', typinput => 'brin_bloom_summary_in',
@@ -704,5 +704,5 @@
descr => 'object identifier(oid8), 8 bytes',
typname => 'oid8', typlen => '8', typbyval => 't', typcategory => 'N',
typinput => 'oid8in', typoutput => 'oid8out', typreceive => 'oid8recv',
- typsend => 'oid8send', typalign => 'd' },
+ typsend => 'oid8send', typalign => 'l' },
]
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index 70d4a20c02b..b749a47d651 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -302,7 +302,9 @@ MAKE_SYSCACHE(TYPENAMENSP, pg_type_typname_nsp_index, 64);
#define TYPALIGN_CHAR 'c' /* char alignment (i.e. unaligned) */
#define TYPALIGN_SHORT 's' /* short alignment (typically 2 bytes) */
#define TYPALIGN_INT 'i' /* int alignment (typically 4 bytes) */
+#define TYPALIGN_INT64 'l' /* int64 alignment (often 8 bytes) */
#define TYPALIGN_DOUBLE 'd' /* double alignment (often 8 bytes) */
+#define TYPALIGN_MAX 'm' /* maximum alignment (usually 8 bytes) */
#define TYPSTORAGE_PLAIN 'p' /* type not prepared for toasting */
#define TYPSTORAGE_EXTERNAL 'e' /* toastable, don't try to compress */
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 339268dc8ef..5699c033ade 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -12,9 +12,6 @@
/* The normal alignment of `int64_t', in bytes. */
#undef ALIGNOF_INT64_T
-/* The normal alignment of `long', in bytes. */
-#undef ALIGNOF_LONG
-
/* The normal alignment of `PG_INT128_TYPE', in bytes. */
#undef ALIGNOF_PG_INT128_TYPE
diff --git a/src/pl/plpython/plpy_typeio.c b/src/pl/plpython/plpy_typeio.c
index 44055de6aeb..d4dbb6b5b85 100644
--- a/src/pl/plpython/plpy_typeio.c
+++ b/src/pl/plpython/plpy_typeio.c
@@ -329,7 +329,7 @@ PLy_output_setup_func(PLyObToDatum *arg, MemoryContext arg_mcxt,
/* hard-wired knowledge about type RECORD: */
arg->typbyval = false;
arg->typlen = -1;
- arg->typalign = TYPALIGN_DOUBLE;
+ arg->typalign = TYPALIGN_MAX;
}
/*
@@ -452,7 +452,7 @@ PLy_input_setup_func(PLyDatumToOb *arg, MemoryContext arg_mcxt,
/* hard-wired knowledge about type RECORD: */
arg->typbyval = false;
arg->typlen = -1;
- arg->typalign = TYPALIGN_DOUBLE;
+ arg->typalign = TYPALIGN_MAX;
}
/*
diff --git a/src/test/regress/expected/create_type.out b/src/test/regress/expected/create_type.out
index 5181c4290b4..07919b4fe0e 100644
--- a/src/test/regress/expected/create_type.out
+++ b/src/test/regress/expected/create_type.out
@@ -49,6 +49,7 @@ CREATE TYPE city_budget (
output = int44out,
element = int4,
category = 'x', -- just to verify the system will take it
+ alignment = max, -- ditto (overspecifying alignment is safe)
preferred = true -- ditto
);
-- Test creation and destruction of shell types
diff --git a/src/test/regress/expected/float8.out b/src/test/regress/expected/float8.out
index 9c519f1a1a1..a688cbc3c83 100644
--- a/src/test/regress/expected/float8.out
+++ b/src/test/regress/expected/float8.out
@@ -1088,8 +1088,10 @@ LINE 1: ...8 (input = xfloat8in, output = xfloat8out, like = no_such_ty...
create type xfloat8 (input = xfloat8in, output = xfloat8out, like = float8);
create cast (xfloat8 as float8) without function;
create cast (float8 as xfloat8) without function;
-create cast (xfloat8 as bigint) without function;
-create cast (bigint as xfloat8) without function;
+-- this hack depends on bigint and float8 having the same pass-by-value-ness:
+create function bigint_xfloat8(bigint) returns xfloat8 immutable strict
+ language internal as 'int8up';
+create cast (bigint as xfloat8) with function bigint_xfloat8(bigint);
-- float8: seeeeeee eeeeeeee eeeeeeee mmmmmmmm mmmmmmmm(x4)
-- we don't care to assume the platform's strtod() handles subnormals
-- correctly; those are "use at your own risk". However we do test
@@ -1503,5 +1505,5 @@ DETAIL: drop cascades to function xfloat8in(cstring)
drop cascades to function xfloat8out(xfloat8)
drop cascades to cast from xfloat8 to double precision
drop cascades to cast from double precision to xfloat8
-drop cascades to cast from xfloat8 to bigint
+drop cascades to function bigint_xfloat8(bigint)
drop cascades to cast from bigint to xfloat8
diff --git a/src/test/regress/expected/type_sanity.out b/src/test/regress/expected/type_sanity.out
index 1d21d3eb446..936fa36a600 100644
--- a/src/test/regress/expected/type_sanity.out
+++ b/src/test/regress/expected/type_sanity.out
@@ -23,7 +23,7 @@ WHERE t1.typnamespace = 0 OR
(t1.typlen <= 0 AND t1.typlen != -1 AND t1.typlen != -2) OR
(t1.typtype not in ('b', 'c', 'd', 'e', 'm', 'p', 'r')) OR
NOT t1.typisdefined OR
- (t1.typalign not in ('c', 's', 'i', 'd')) OR
+ (t1.typalign not in ('c', 's', 'i', 'l', 'd', 'm')) OR
(t1.typstorage not in ('p', 'x', 'e', 'm'));
oid | typname
-----+---------
@@ -36,7 +36,7 @@ WHERE t1.typbyval AND
(t1.typlen != 1 OR t1.typalign != 'c') AND
(t1.typlen != 2 OR t1.typalign != 's') AND
(t1.typlen != 4 OR t1.typalign != 'i') AND
- (t1.typlen != 8 OR t1.typalign != 'd');
+ (t1.typlen != 8 OR (t1.typalign != 'l' AND t1.typalign != 'd'));
oid | typname
-----+---------
(0 rows)
@@ -108,6 +108,8 @@ FROM pg_type as t1
LEFT JOIN pg_type as t2 ON rngsubtype = t2.oid
WHERE t1.typtype = 'r' AND
(t1.typalign != (CASE WHEN t2.typalign = 'd' THEN 'd'::"char"
+ WHEN t2.typalign = 'l' THEN 'l'::"char"
+ WHEN t2.typalign = 'm' THEN 'm'::"char"
ELSE 'i'::"char" END)
OR t2.oid IS NULL);
oid | typname | typalign | typname | typalign
@@ -423,6 +425,8 @@ SELECT t1.oid, t1.typname, t1.typalign, t2.typname, t2.typalign
FROM pg_type AS t1, pg_type AS t2
WHERE t1.typarray = t2.oid AND
t2.typalign != (CASE WHEN t1.typalign = 'd' THEN 'd'::"char"
+ WHEN t1.typalign = 'l' THEN 'l'::"char"
+ WHEN t1.typalign = 'm' THEN 'm'::"char"
ELSE 'i'::"char" END);
oid | typname | typalign | typname | typalign
-----+---------+----------+---------+----------
diff --git a/src/test/regress/sql/create_type.sql b/src/test/regress/sql/create_type.sql
index c25018029c2..94c5b949c25 100644
--- a/src/test/regress/sql/create_type.sql
+++ b/src/test/regress/sql/create_type.sql
@@ -47,6 +47,7 @@ CREATE TYPE city_budget (
output = int44out,
element = int4,
category = 'x', -- just to verify the system will take it
+ alignment = max, -- ditto (overspecifying alignment is safe)
preferred = true -- ditto
);
diff --git a/src/test/regress/sql/float8.sql b/src/test/regress/sql/float8.sql
index 0ef271f2702..c6b59a322ab 100644
--- a/src/test/regress/sql/float8.sql
+++ b/src/test/regress/sql/float8.sql
@@ -355,8 +355,10 @@ create type xfloat8 (input = xfloat8in, output = xfloat8out, like = no_such_type
create type xfloat8 (input = xfloat8in, output = xfloat8out, like = float8);
create cast (xfloat8 as float8) without function;
create cast (float8 as xfloat8) without function;
-create cast (xfloat8 as bigint) without function;
-create cast (bigint as xfloat8) without function;
+-- this hack depends on bigint and float8 having the same pass-by-value-ness:
+create function bigint_xfloat8(bigint) returns xfloat8 immutable strict
+ language internal as 'int8up';
+create cast (bigint as xfloat8) with function bigint_xfloat8(bigint);
-- float8: seeeeeee eeeeeeee eeeeeeee mmmmmmmm mmmmmmmm(x4)
diff --git a/src/test/regress/sql/type_sanity.sql b/src/test/regress/sql/type_sanity.sql
index 95d5b6e0915..625305c42bc 100644
--- a/src/test/regress/sql/type_sanity.sql
+++ b/src/test/regress/sql/type_sanity.sql
@@ -28,7 +28,7 @@ WHERE t1.typnamespace = 0 OR
(t1.typlen <= 0 AND t1.typlen != -1 AND t1.typlen != -2) OR
(t1.typtype not in ('b', 'c', 'd', 'e', 'm', 'p', 'r')) OR
NOT t1.typisdefined OR
- (t1.typalign not in ('c', 's', 'i', 'd')) OR
+ (t1.typalign not in ('c', 's', 'i', 'l', 'd', 'm')) OR
(t1.typstorage not in ('p', 'x', 'e', 'm'));
-- Look for "pass by value" types that can't be passed by value.
@@ -39,7 +39,7 @@ WHERE t1.typbyval AND
(t1.typlen != 1 OR t1.typalign != 'c') AND
(t1.typlen != 2 OR t1.typalign != 's') AND
(t1.typlen != 4 OR t1.typalign != 'i') AND
- (t1.typlen != 8 OR t1.typalign != 'd');
+ (t1.typlen != 8 OR (t1.typalign != 'l' AND t1.typalign != 'd'));
-- Look for "toastable" types that aren't varlena.
@@ -90,6 +90,8 @@ FROM pg_type as t1
LEFT JOIN pg_type as t2 ON rngsubtype = t2.oid
WHERE t1.typtype = 'r' AND
(t1.typalign != (CASE WHEN t2.typalign = 'd' THEN 'd'::"char"
+ WHEN t2.typalign = 'l' THEN 'l'::"char"
+ WHEN t2.typalign = 'm' THEN 'm'::"char"
ELSE 'i'::"char" END)
OR t2.oid IS NULL);
@@ -302,6 +304,8 @@ SELECT t1.oid, t1.typname, t1.typalign, t2.typname, t2.typalign
FROM pg_type AS t1, pg_type AS t2
WHERE t1.typarray = t2.oid AND
t2.typalign != (CASE WHEN t1.typalign = 'd' THEN 'd'::"char"
+ WHEN t1.typalign = 'l' THEN 'l'::"char"
+ WHEN t1.typalign = 'm' THEN 'm'::"char"
ELSE 'i'::"char" END);
-- Check for typelem set without a handler
--
2.43.7