]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Refactor att_align_nominal() to improve performance.
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 2 Feb 2026 19:39:50 +0000 (14:39 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 2 Feb 2026 19:39:50 +0000 (14:39 -0500)
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.

Performance testing shows that ExecEvalScalarArrayOp is sped up by
about 10% by this change, when using a simple per-element function
such as int8eq.  I did not check any of the other loops optimized
here, but it's reasonable to expect similar gains.

Although the motivation for creating this patch was to avoid a
performance loss if we add some more typalign values, it evidently
is worth doing whether that patch lands or not.

Discussion: https://postgr.es/m/1127261.1769649624@sss.pgh.pa.us

contrib/dblink/dblink.c
src/backend/access/common/tupdesc.c
src/backend/executor/execExprInterp.c
src/backend/utils/adt/array_expanded.c
src/backend/utils/adt/arrayfuncs.c
src/backend/utils/adt/multirangetypes.c
src/backend/utils/adt/varlena.c
src/include/access/tupmacs.h
src/include/utils/arrayaccess.h
src/pl/plpython/plpy_typeio.c

index 8cb3166495c145c58b849ccd2d505014dda7392d..2498d80c8e7df9775eee90aade05dcf16347f511 100644 (file)
@@ -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 */
index 94b4f1f9975721b95bc94825ffce501b84e29bf4..b69d10f0a45b364a7f60da176b56d044b06547b1 100644 (file)
@@ -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);
 }
 
 /*
index a7a5ac1e83b0e878c61c4576bde42a816aa315c7..61ff5ddc74c24bbc29c32298c652d85001d44f60 100644 (file)
@@ -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);
                        }
index 01e3dddcbbb579ca0c5ef0eaa381127678b5cfe0..7e8352af52b296b3d2dcd4a8520340a418e402ad 100644 (file)
@@ -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,
index e71d32773b5cb7c24ba2b5bb52828b51ca445f90..da68915ee20aa3c05ecb994a8c7f86582d3bb734 100644 (file)
@@ -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);
                }
        }
 
index 07e2a81d46ae3b08beeba9750b309f586266423e..b1942387dc5c22db7fcacb7c151cb8ff08059895 100644 (file)
@@ -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);
        }
 }
 
index 6c1ebb0866db7fe1a38f0a2d1c649e0fe6aa6635..552ac0c61d308a15032431fcbfb2235094179efc 100644 (file)
@@ -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 */
index 3e5530658c9471aed48091f419396fc085bd6ce4..d64c18b950bbbfcaf93edc128e1e535bd1453a4b 100644 (file)
@@ -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
index abb8659de02a9d16d3fbceccdba21d49aa332de7..a325ae52574d8fc47ae492c958d2f4091495a31b 100644 (file)
@@ -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)
index 1f69109b081c027d38eca240fcb4838dff419803..44055de6aeb6d266303e93bee896f97f3ab636b6 100644 (file)
@@ -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 */