mirror of
https://github.com/postgres/postgres.git
synced 2026-03-23 19:04:11 -04:00
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
127 lines
3.2 KiB
C
127 lines
3.2 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* arrayaccess.h
|
|
* Declarations for element-by-element access to Postgres arrays.
|
|
*
|
|
*
|
|
* Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
*
|
|
* src/include/utils/arrayaccess.h
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
#ifndef ARRAYACCESS_H
|
|
#define ARRAYACCESS_H
|
|
|
|
#include "access/tupmacs.h"
|
|
#include "utils/array.h"
|
|
|
|
|
|
/*
|
|
* 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
|
|
* 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
|
|
* that, these functions can only fetch elements sequentially.
|
|
*/
|
|
|
|
typedef struct array_iter
|
|
{
|
|
/* datumptr being NULL or not tells if we have flat or expanded array */
|
|
|
|
/* Fields used when we have an expanded array */
|
|
Datum *datumptr; /* Pointer to Datum array */
|
|
bool *isnullptr; /* Pointer to isnull array */
|
|
|
|
/* Fields used when we have a flat array */
|
|
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,
|
|
int elmlen, bool elmbyval, char elmalign)
|
|
{
|
|
if (VARATT_IS_EXPANDED_HEADER(a))
|
|
{
|
|
if (a->xpn.dvalues)
|
|
{
|
|
it->datumptr = a->xpn.dvalues;
|
|
it->isnullptr = a->xpn.dnulls;
|
|
/* we must fill all fields to prevent compiler warnings */
|
|
it->dataptr = NULL;
|
|
it->bitmapptr = NULL;
|
|
}
|
|
else
|
|
{
|
|
/* Work with flat array embedded in the expanded datum */
|
|
it->datumptr = NULL;
|
|
it->isnullptr = NULL;
|
|
it->dataptr = ARR_DATA_PTR(a->xpn.fvalue);
|
|
it->bitmapptr = ARR_NULLBITMAP(a->xpn.fvalue);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
it->datumptr = NULL;
|
|
it->isnullptr = NULL;
|
|
it->dataptr = ARR_DATA_PTR((ArrayType *) 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)
|
|
{
|
|
Datum ret;
|
|
|
|
if (it->datumptr)
|
|
{
|
|
ret = it->datumptr[i];
|
|
*isnull = it->isnullptr ? it->isnullptr[i] : false;
|
|
}
|
|
else
|
|
{
|
|
if (it->bitmapptr && (*(it->bitmapptr) & it->bitmask) == 0)
|
|
{
|
|
*isnull = true;
|
|
ret = (Datum) 0;
|
|
}
|
|
else
|
|
{
|
|
*isnull = false;
|
|
ret = fetch_att(it->dataptr, it->elmbyval, it->elmlen);
|
|
it->dataptr = att_addlength_pointer(it->dataptr, it->elmlen,
|
|
it->dataptr);
|
|
it->dataptr = (char *) att_nominal_alignby(it->dataptr,
|
|
it->elmalignby);
|
|
}
|
|
it->bitmask <<= 1;
|
|
if (it->bitmask == 0x100)
|
|
{
|
|
if (it->bitmapptr)
|
|
it->bitmapptr++;
|
|
it->bitmask = 1;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#endif /* ARRAYACCESS_H */
|