PostgreSQL Source Code  git master
array.h File Reference
#include "fmgr.h"
#include "utils/expandeddatum.h"
Include dependency graph for array.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  ArrayType
 
struct  ExpandedArrayHeader
 
union  AnyArrayType
 
struct  ArrayBuildState
 
struct  ArrayBuildStateArr
 
struct  ArrayBuildStateAny
 
struct  ArrayMetaState
 
struct  ArrayMapState
 

Macros

#define MAXDIM   6
 
#define MaxArraySize   ((Size) (MaxAllocSize / sizeof(Datum)))
 
#define EA_MAGIC   689375833 /* ID for debugging crosschecks */
 
#define DatumGetArrayTypeP(X)   ((ArrayType *) PG_DETOAST_DATUM(X))
 
#define DatumGetArrayTypePCopy(X)   ((ArrayType *) PG_DETOAST_DATUM_COPY(X))
 
#define PG_GETARG_ARRAYTYPE_P(n)   DatumGetArrayTypeP(PG_GETARG_DATUM(n))
 
#define PG_GETARG_ARRAYTYPE_P_COPY(n)   DatumGetArrayTypePCopy(PG_GETARG_DATUM(n))
 
#define PG_RETURN_ARRAYTYPE_P(x)   PG_RETURN_POINTER(x)
 
#define PG_GETARG_EXPANDED_ARRAY(n)   DatumGetExpandedArray(PG_GETARG_DATUM(n))
 
#define PG_GETARG_EXPANDED_ARRAYX(n, metacache)    DatumGetExpandedArrayX(PG_GETARG_DATUM(n), metacache)
 
#define PG_RETURN_EXPANDED_ARRAY(x)   PG_RETURN_DATUM(EOHPGetRWDatum(&(x)->hdr))
 
#define PG_GETARG_ANY_ARRAY_P(n)   DatumGetAnyArrayP(PG_GETARG_DATUM(n))
 
#define ARR_SIZE(a)   VARSIZE(a)
 
#define ARR_NDIM(a)   ((a)->ndim)
 
#define ARR_HASNULL(a)   ((a)->dataoffset != 0)
 
#define ARR_ELEMTYPE(a)   ((a)->elemtype)
 
#define ARR_DIMS(a)    ((int *) (((char *) (a)) + sizeof(ArrayType)))
 
#define ARR_LBOUND(a)
 
#define ARR_NULLBITMAP(a)
 
#define ARR_OVERHEAD_NONULLS(ndims)    MAXALIGN(sizeof(ArrayType) + 2 * sizeof(int) * (ndims))
 
#define ARR_OVERHEAD_WITHNULLS(ndims, nitems)
 
#define ARR_DATA_OFFSET(a)    (ARR_HASNULL(a) ? (a)->dataoffset : ARR_OVERHEAD_NONULLS(ARR_NDIM(a)))
 
#define ARR_DATA_PTR(a)    (((char *) (a)) + ARR_DATA_OFFSET(a))
 
#define AARR_NDIM(a)
 
#define AARR_HASNULL(a)
 
#define AARR_ELEMTYPE(a)
 
#define AARR_DIMS(a)
 
#define AARR_LBOUND(a)
 

Typedefs

typedef struct ArrayType ArrayType
 
typedef struct ExpandedArrayHeader ExpandedArrayHeader
 
typedef union AnyArrayType AnyArrayType
 
typedef struct ArrayBuildState ArrayBuildState
 
typedef struct ArrayBuildStateArr ArrayBuildStateArr
 
typedef struct ArrayBuildStateAny ArrayBuildStateAny
 
typedef struct ArrayMetaState ArrayMetaState
 
typedef struct ArrayMapState ArrayMapState
 
typedef struct ArrayIteratorDataArrayIterator
 

Functions

void CopyArrayEls (ArrayType *array, Datum *values, bool *nulls, int nitems, int typlen, bool typbyval, char typalign, bool freedata)
 
Datum array_get_element (Datum arraydatum, int nSubscripts, int *indx, int arraytyplen, int elmlen, bool elmbyval, char elmalign, bool *isNull)
 
Datum array_set_element (Datum arraydatum, int nSubscripts, int *indx, Datum dataValue, bool isNull, int arraytyplen, int elmlen, bool elmbyval, char elmalign)
 
Datum array_get_slice (Datum arraydatum, int nSubscripts, int *upperIndx, int *lowerIndx, bool *upperProvided, bool *lowerProvided, int arraytyplen, int elmlen, bool elmbyval, char elmalign)
 
Datum array_set_slice (Datum arraydatum, int nSubscripts, int *upperIndx, int *lowerIndx, bool *upperProvided, bool *lowerProvided, Datum srcArrayDatum, bool isNull, int arraytyplen, int elmlen, bool elmbyval, char elmalign)
 
Datum array_ref (ArrayType *array, int nSubscripts, int *indx, int arraytyplen, int elmlen, bool elmbyval, char elmalign, bool *isNull)
 
ArrayTypearray_set (ArrayType *array, int nSubscripts, int *indx, Datum dataValue, bool isNull, int arraytyplen, int elmlen, bool elmbyval, char elmalign)
 
Datum array_map (Datum arrayd, struct ExprState *exprstate, struct ExprContext *econtext, Oid retType, ArrayMapState *amstate)
 
void array_bitmap_copy (bits8 *destbitmap, int destoffset, const bits8 *srcbitmap, int srcoffset, int nitems)
 
ArrayTypeconstruct_array (Datum *elems, int nelems, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
 
ArrayTypeconstruct_array_builtin (Datum *elems, int nelems, Oid elmtype)
 
ArrayTypeconstruct_md_array (Datum *elems, bool *nulls, int ndims, int *dims, int *lbs, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
 
ArrayTypeconstruct_empty_array (Oid elmtype)
 
ExpandedArrayHeaderconstruct_empty_expanded_array (Oid element_type, MemoryContext parentcontext, ArrayMetaState *metacache)
 
void deconstruct_array (ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
 
void deconstruct_array_builtin (ArrayType *array, Oid elmtype, Datum **elemsp, bool **nullsp, int *nelemsp)
 
bool array_contains_nulls (ArrayType *array)
 
ArrayBuildStateinitArrayResult (Oid element_type, MemoryContext rcontext, bool subcontext)
 
ArrayBuildStateinitArrayResultWithSize (Oid element_type, MemoryContext rcontext, bool subcontext, int initsize)
 
ArrayBuildStateaccumArrayResult (ArrayBuildState *astate, Datum dvalue, bool disnull, Oid element_type, MemoryContext rcontext)
 
Datum makeArrayResult (ArrayBuildState *astate, MemoryContext rcontext)
 
Datum makeMdArrayResult (ArrayBuildState *astate, int ndims, int *dims, int *lbs, MemoryContext rcontext, bool release)
 
ArrayBuildStateArrinitArrayResultArr (Oid array_type, Oid element_type, MemoryContext rcontext, bool subcontext)
 
ArrayBuildStateArraccumArrayResultArr (ArrayBuildStateArr *astate, Datum dvalue, bool disnull, Oid array_type, MemoryContext rcontext)
 
Datum makeArrayResultArr (ArrayBuildStateArr *astate, MemoryContext rcontext, bool release)
 
ArrayBuildStateAnyinitArrayResultAny (Oid input_type, MemoryContext rcontext, bool subcontext)
 
ArrayBuildStateAnyaccumArrayResultAny (ArrayBuildStateAny *astate, Datum dvalue, bool disnull, Oid input_type, MemoryContext rcontext)
 
Datum makeArrayResultAny (ArrayBuildStateAny *astate, MemoryContext rcontext, bool release)
 
ArrayIterator array_create_iterator (ArrayType *arr, int slice_ndim, ArrayMetaState *mstate)
 
bool array_iterate (ArrayIterator iterator, Datum *value, bool *isnull)
 
void array_free_iterator (ArrayIterator iterator)
 
int ArrayGetOffset (int n, const int *dim, const int *lb, const int *indx)
 
int ArrayGetNItems (int ndim, const int *dims)
 
int ArrayGetNItemsSafe (int ndim, const int *dims, struct Node *escontext)
 
void ArrayCheckBounds (int ndim, const int *dims, const int *lb)
 
bool ArrayCheckBoundsSafe (int ndim, const int *dims, const int *lb, struct Node *escontext)
 
void mda_get_range (int n, int *span, const int *st, const int *endp)
 
void mda_get_prod (int n, const int *range, int *prod)
 
void mda_get_offset_values (int n, int *dist, const int *prod, const int *span)
 
int mda_next_tuple (int n, int *curr, const int *span)
 
int32ArrayGetIntegerTypmods (ArrayType *arr, int *n)
 
Datum expand_array (Datum arraydatum, MemoryContext parentcontext, ArrayMetaState *metacache)
 
ExpandedArrayHeaderDatumGetExpandedArray (Datum d)
 
ExpandedArrayHeaderDatumGetExpandedArrayX (Datum d, ArrayMetaState *metacache)
 
AnyArrayTypeDatumGetAnyArrayP (Datum d)
 
void deconstruct_expanded_array (ExpandedArrayHeader *eah)
 

Variables

PGDLLIMPORT bool Array_nulls
 

Macro Definition Documentation

◆ AARR_DIMS

#define AARR_DIMS (   a)
Value:
(a)->xpn.dims : ARR_DIMS((ArrayType *) (a)))
#define ARR_DIMS(a)
Definition: array.h:294
#define VARATT_IS_EXPANDED_HEADER(PTR)
int a
Definition: isn.c:69

Definition at line 338 of file array.h.

◆ AARR_ELEMTYPE

#define AARR_ELEMTYPE (   a)
Value:
(a)->xpn.element_type : ARR_ELEMTYPE((ArrayType *) (a)))
#define ARR_ELEMTYPE(a)
Definition: array.h:292

Definition at line 335 of file array.h.

◆ AARR_HASNULL

#define AARR_HASNULL (   a)
Value:
((a)->xpn.dvalues != NULL ? (a)->xpn.dnulls != NULL : ARR_HASNULL((a)->xpn.fvalue)) : \
#define ARR_HASNULL(a)
Definition: array.h:291

Definition at line 331 of file array.h.

◆ AARR_LBOUND

#define AARR_LBOUND (   a)
Value:
(a)->xpn.lbound : ARR_LBOUND((ArrayType *) (a)))
#define ARR_LBOUND(a)
Definition: array.h:296

Definition at line 341 of file array.h.

◆ AARR_NDIM

#define AARR_NDIM (   a)
Value:
(a)->xpn.ndims : ARR_NDIM((ArrayType *) (a)))
#define ARR_NDIM(a)
Definition: array.h:290

Definition at line 328 of file array.h.

◆ ARR_DATA_OFFSET

#define ARR_DATA_OFFSET (   a)     (ARR_HASNULL(a) ? (a)->dataoffset : ARR_OVERHEAD_NONULLS(ARR_NDIM(a)))

Definition at line 316 of file array.h.

◆ ARR_DATA_PTR

#define ARR_DATA_PTR (   a)     (((char *) (a)) + ARR_DATA_OFFSET(a))

Definition at line 322 of file array.h.

◆ ARR_DIMS

#define ARR_DIMS (   a)     ((int *) (((char *) (a)) + sizeof(ArrayType)))

Definition at line 294 of file array.h.

◆ ARR_ELEMTYPE

#define ARR_ELEMTYPE (   a)    ((a)->elemtype)

Definition at line 292 of file array.h.

◆ ARR_HASNULL

#define ARR_HASNULL (   a)    ((a)->dataoffset != 0)

Definition at line 291 of file array.h.

◆ ARR_LBOUND

#define ARR_LBOUND (   a)
Value:
((int *) (((char *) (a)) + sizeof(ArrayType) + \
sizeof(int) * ARR_NDIM(a)))
struct ArrayType ArrayType

Definition at line 296 of file array.h.

◆ ARR_NDIM

#define ARR_NDIM (   a)    ((a)->ndim)

Definition at line 290 of file array.h.

◆ ARR_NULLBITMAP

#define ARR_NULLBITMAP (   a)
Value:
(ARR_HASNULL(a) ? \
(bits8 *) (((char *) (a)) + sizeof(ArrayType) + \
2 * sizeof(int) * ARR_NDIM(a)) \
: (bits8 *) NULL)
uint8 bits8
Definition: c.h:500

Definition at line 300 of file array.h.

◆ ARR_OVERHEAD_NONULLS

#define ARR_OVERHEAD_NONULLS (   ndims)     MAXALIGN(sizeof(ArrayType) + 2 * sizeof(int) * (ndims))

Definition at line 310 of file array.h.

◆ ARR_OVERHEAD_WITHNULLS

#define ARR_OVERHEAD_WITHNULLS (   ndims,
  nitems 
)
Value:
MAXALIGN(sizeof(ArrayType) + 2 * sizeof(int) * (ndims) + \
((nitems) + 7) / 8)
#define MAXALIGN(LEN)
Definition: c.h:798
#define nitems(x)
Definition: indent.h:31

Definition at line 312 of file array.h.

◆ ARR_SIZE

#define ARR_SIZE (   a)    VARSIZE(a)

Definition at line 289 of file array.h.

◆ DatumGetArrayTypeP

#define DatumGetArrayTypeP (   X)    ((ArrayType *) PG_DETOAST_DATUM(X))

Definition at line 261 of file array.h.

◆ DatumGetArrayTypePCopy

#define DatumGetArrayTypePCopy (   X)    ((ArrayType *) PG_DETOAST_DATUM_COPY(X))

Definition at line 262 of file array.h.

◆ EA_MAGIC

#define EA_MAGIC   689375833 /* ID for debugging crosschecks */

Definition at line 113 of file array.h.

◆ MaxArraySize

#define MaxArraySize   ((Size) (MaxAllocSize / sizeof(Datum)))

Definition at line 82 of file array.h.

◆ MAXDIM

#define MAXDIM   6

Definition at line 75 of file array.h.

◆ PG_GETARG_ANY_ARRAY_P

#define PG_GETARG_ANY_ARRAY_P (   n)    DatumGetAnyArrayP(PG_GETARG_DATUM(n))

Definition at line 274 of file array.h.

◆ PG_GETARG_ARRAYTYPE_P

#define PG_GETARG_ARRAYTYPE_P (   n)    DatumGetArrayTypeP(PG_GETARG_DATUM(n))

Definition at line 263 of file array.h.

◆ PG_GETARG_ARRAYTYPE_P_COPY

#define PG_GETARG_ARRAYTYPE_P_COPY (   n)    DatumGetArrayTypePCopy(PG_GETARG_DATUM(n))

Definition at line 264 of file array.h.

◆ PG_GETARG_EXPANDED_ARRAY

#define PG_GETARG_EXPANDED_ARRAY (   n)    DatumGetExpandedArray(PG_GETARG_DATUM(n))

Definition at line 268 of file array.h.

◆ PG_GETARG_EXPANDED_ARRAYX

#define PG_GETARG_EXPANDED_ARRAYX (   n,
  metacache 
)     DatumGetExpandedArrayX(PG_GETARG_DATUM(n), metacache)

Definition at line 269 of file array.h.

◆ PG_RETURN_ARRAYTYPE_P

#define PG_RETURN_ARRAYTYPE_P (   x)    PG_RETURN_POINTER(x)

Definition at line 265 of file array.h.

◆ PG_RETURN_EXPANDED_ARRAY

#define PG_RETURN_EXPANDED_ARRAY (   x)    PG_RETURN_DATUM(EOHPGetRWDatum(&(x)->hdr))

Definition at line 271 of file array.h.

Typedef Documentation

◆ AnyArrayType

typedef union AnyArrayType AnyArrayType

◆ ArrayBuildState

◆ ArrayBuildStateAny

◆ ArrayBuildStateArr

◆ ArrayIterator

Definition at line 258 of file array.h.

◆ ArrayMapState

typedef struct ArrayMapState ArrayMapState

◆ ArrayMetaState

◆ ArrayType

typedef struct ArrayType ArrayType

◆ ExpandedArrayHeader

Function Documentation

◆ accumArrayResult()

ArrayBuildState* accumArrayResult ( ArrayBuildState astate,
Datum  dvalue,
bool  disnull,
Oid  element_type,
MemoryContext  rcontext 
)

Definition at line 5331 of file arrayfuncs.c.

5335 {
5336  MemoryContext oldcontext;
5337 
5338  if (astate == NULL)
5339  {
5340  /* First time through --- initialize */
5341  astate = initArrayResult(element_type, rcontext, true);
5342  }
5343  else
5344  {
5345  Assert(astate->element_type == element_type);
5346  }
5347 
5348  oldcontext = MemoryContextSwitchTo(astate->mcontext);
5349 
5350  /* enlarge dvalues[]/dnulls[] if needed */
5351  if (astate->nelems >= astate->alen)
5352  {
5353  astate->alen *= 2;
5354  /* give an array-related error if we go past MaxAllocSize */
5355  if (!AllocSizeIsValid(astate->alen * sizeof(Datum)))
5356  ereport(ERROR,
5357  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
5358  errmsg("array size exceeds the maximum allowed (%d)",
5359  (int) MaxAllocSize)));
5360  astate->dvalues = (Datum *)
5361  repalloc(astate->dvalues, astate->alen * sizeof(Datum));
5362  astate->dnulls = (bool *)
5363  repalloc(astate->dnulls, astate->alen * sizeof(bool));
5364  }
5365 
5366  /*
5367  * Ensure pass-by-ref stuff is copied into mcontext; and detoast it too if
5368  * it's varlena. (You might think that detoasting is not needed here
5369  * because construct_md_array can detoast the array elements later.
5370  * However, we must not let construct_md_array modify the ArrayBuildState
5371  * because that would mean array_agg_finalfn damages its input, which is
5372  * verboten. Also, this way frequently saves one copying step.)
5373  */
5374  if (!disnull && !astate->typbyval)
5375  {
5376  if (astate->typlen == -1)
5377  dvalue = PointerGetDatum(PG_DETOAST_DATUM_COPY(dvalue));
5378  else
5379  dvalue = datumCopy(dvalue, astate->typbyval, astate->typlen);
5380  }
5381 
5382  astate->dvalues[astate->nelems] = dvalue;
5383  astate->dnulls[astate->nelems] = disnull;
5384  astate->nelems++;
5385 
5386  MemoryContextSwitchTo(oldcontext);
5387 
5388  return astate;
5389 }
ArrayBuildState * initArrayResult(Oid element_type, MemoryContext rcontext, bool subcontext)
Definition: arrayfuncs.c:5274
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:132
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
#define PG_DETOAST_DATUM_COPY(datum)
Definition: fmgr.h:242
Assert(fmt[strlen(fmt) - 1] !='\n')
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1528
#define AllocSizeIsValid(size)
Definition: memutils.h:42
#define MaxAllocSize
Definition: memutils.h:40
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
uintptr_t Datum
Definition: postgres.h:64
bool * dnulls
Definition: array.h:191
bool typbyval
Definition: array.h:196
MemoryContext mcontext
Definition: array.h:189
int16 typlen
Definition: array.h:195
Oid element_type
Definition: array.h:194
Datum * dvalues
Definition: array.h:190

References ArrayBuildState::alen, AllocSizeIsValid, Assert(), datumCopy(), ArrayBuildState::dnulls, ArrayBuildState::dvalues, ArrayBuildState::element_type, ereport, errcode(), errmsg(), ERROR, initArrayResult(), MaxAllocSize, ArrayBuildState::mcontext, MemoryContextSwitchTo(), ArrayBuildState::nelems, PG_DETOAST_DATUM_COPY, PointerGetDatum(), repalloc(), ArrayBuildState::typbyval, and ArrayBuildState::typlen.

Referenced by accumArrayResultAny(), array_agg_transfn(), array_positions(), array_to_datum_internal(), brin_minmax_multi_summary_out(), daitch_mokotoff_coding(), dblink_get_connections(), find_or_create_child_node(), multirange_agg_transfn(), optionListToArray(), parse_ident(), pg_get_statisticsobjdef_expressions(), pg_stats_ext_mcvlist_items(), PLySequence_ToArray_recurse(), populate_array_element(), range_agg_transfn(), regexp_split_to_array(), serialize_expr_stats(), split_text_accum_result(), transformRelOptions(), and tuple_data_split_internal().

◆ accumArrayResultAny()

ArrayBuildStateAny* accumArrayResultAny ( ArrayBuildStateAny astate,
Datum  dvalue,
bool  disnull,
Oid  input_type,
MemoryContext  rcontext 
)

Definition at line 5808 of file arrayfuncs.c.

5812 {
5813  if (astate == NULL)
5814  astate = initArrayResultAny(input_type, rcontext, true);
5815 
5816  if (astate->scalarstate)
5817  (void) accumArrayResult(astate->scalarstate,
5818  dvalue, disnull,
5819  input_type, rcontext);
5820  else
5821  (void) accumArrayResultArr(astate->arraystate,
5822  dvalue, disnull,
5823  input_type, rcontext);
5824 
5825  return astate;
5826 }
ArrayBuildState * accumArrayResult(ArrayBuildState *astate, Datum dvalue, bool disnull, Oid element_type, MemoryContext rcontext)
Definition: arrayfuncs.c:5331
ArrayBuildStateAny * initArrayResultAny(Oid input_type, MemoryContext rcontext, bool subcontext)
Definition: arrayfuncs.c:5763
ArrayBuildStateArr * accumArrayResultArr(ArrayBuildStateArr *astate, Datum dvalue, bool disnull, Oid array_type, MemoryContext rcontext)
Definition: arrayfuncs.c:5531
ArrayBuildStateArr * arraystate
Definition: array.h:230
ArrayBuildState * scalarstate
Definition: array.h:229

References accumArrayResult(), accumArrayResultArr(), ArrayBuildStateAny::arraystate, initArrayResultAny(), and ArrayBuildStateAny::scalarstate.

Referenced by ExecScanSubPlan(), and ExecSetParamPlan().

◆ accumArrayResultArr()

ArrayBuildStateArr* accumArrayResultArr ( ArrayBuildStateArr astate,
Datum  dvalue,
bool  disnull,
Oid  array_type,
MemoryContext  rcontext 
)

Definition at line 5531 of file arrayfuncs.c.

5535 {
5536  ArrayType *arg;
5537  MemoryContext oldcontext;
5538  int *dims,
5539  *lbs,
5540  ndims,
5541  nitems,
5542  ndatabytes;
5543  char *data;
5544  int i;
5545 
5546  /*
5547  * We disallow accumulating null subarrays. Another plausible definition
5548  * is to ignore them, but callers that want that can just skip calling
5549  * this function.
5550  */
5551  if (disnull)
5552  ereport(ERROR,
5553  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
5554  errmsg("cannot accumulate null arrays")));
5555 
5556  /* Detoast input array in caller's context */
5557  arg = DatumGetArrayTypeP(dvalue);
5558 
5559  if (astate == NULL)
5560  astate = initArrayResultArr(array_type, InvalidOid, rcontext, true);
5561  else
5562  Assert(astate->array_type == array_type);
5563 
5564  oldcontext = MemoryContextSwitchTo(astate->mcontext);
5565 
5566  /* Collect this input's dimensions */
5567  ndims = ARR_NDIM(arg);
5568  dims = ARR_DIMS(arg);
5569  lbs = ARR_LBOUND(arg);
5570  data = ARR_DATA_PTR(arg);
5571  nitems = ArrayGetNItems(ndims, dims);
5572  ndatabytes = ARR_SIZE(arg) - ARR_DATA_OFFSET(arg);
5573 
5574  if (astate->ndims == 0)
5575  {
5576  /* First input; check/save the dimensionality info */
5577 
5578  /* Should we allow empty inputs and just produce an empty output? */
5579  if (ndims == 0)
5580  ereport(ERROR,
5581  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
5582  errmsg("cannot accumulate empty arrays")));
5583  if (ndims + 1 > MAXDIM)
5584  ereport(ERROR,
5585  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
5586  errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
5587  ndims + 1, MAXDIM)));
5588 
5589  /*
5590  * The output array will have n+1 dimensions, with the ones after the
5591  * first matching the input's dimensions.
5592  */
5593  astate->ndims = ndims + 1;
5594  astate->dims[0] = 0;
5595  memcpy(&astate->dims[1], dims, ndims * sizeof(int));
5596  astate->lbs[0] = 1;
5597  memcpy(&astate->lbs[1], lbs, ndims * sizeof(int));
5598 
5599  /* Allocate at least enough data space for this item */
5600  astate->abytes = pg_nextpower2_32(Max(1024, ndatabytes + 1));
5601  astate->data = (char *) palloc(astate->abytes);
5602  }
5603  else
5604  {
5605  /* Second or later input: must match first input's dimensionality */
5606  if (astate->ndims != ndims + 1)
5607  ereport(ERROR,
5608  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
5609  errmsg("cannot accumulate arrays of different dimensionality")));
5610  for (i = 0; i < ndims; i++)
5611  {
5612  if (astate->dims[i + 1] != dims[i] || astate->lbs[i + 1] != lbs[i])
5613  ereport(ERROR,
5614  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
5615  errmsg("cannot accumulate arrays of different dimensionality")));
5616  }
5617 
5618  /* Enlarge data space if needed */
5619  if (astate->nbytes + ndatabytes > astate->abytes)
5620  {
5621  astate->abytes = Max(astate->abytes * 2,
5622  astate->nbytes + ndatabytes);
5623  astate->data = (char *) repalloc(astate->data, astate->abytes);
5624  }
5625  }
5626 
5627  /*
5628  * Copy the data portion of the sub-array. Note we assume that the
5629  * advertised data length of the sub-array is properly aligned. We do not
5630  * have to worry about detoasting elements since whatever's in the
5631  * sub-array should be OK already.
5632  */
5633  memcpy(astate->data + astate->nbytes, data, ndatabytes);
5634  astate->nbytes += ndatabytes;
5635 
5636  /* Deal with null bitmap if needed */
5637  if (astate->nullbitmap || ARR_HASNULL(arg))
5638  {
5639  int newnitems = astate->nitems + nitems;
5640 
5641  if (astate->nullbitmap == NULL)
5642  {
5643  /*
5644  * First input with nulls; we must retrospectively handle any
5645  * previous inputs by marking all their items non-null.
5646  */
5647  astate->aitems = pg_nextpower2_32(Max(256, newnitems + 1));
5648  astate->nullbitmap = (bits8 *) palloc((astate->aitems + 7) / 8);
5649  array_bitmap_copy(astate->nullbitmap, 0,
5650  NULL, 0,
5651  astate->nitems);
5652  }
5653  else if (newnitems > astate->aitems)
5654  {
5655  astate->aitems = Max(astate->aitems * 2, newnitems);
5656  astate->nullbitmap = (bits8 *)
5657  repalloc(astate->nullbitmap, (astate->aitems + 7) / 8);
5658  }
5659  array_bitmap_copy(astate->nullbitmap, astate->nitems,
5660  ARR_NULLBITMAP(arg), 0,
5661  nitems);
5662  }
5663 
5664  astate->nitems += nitems;
5665  astate->dims[0] += 1;
5666 
5667  MemoryContextSwitchTo(oldcontext);
5668 
5669  /* Release detoasted copy if any */
5670  if ((Pointer) arg != DatumGetPointer(dvalue))
5671  pfree(arg);
5672 
5673  return astate;
5674 }
#define ARR_DATA_PTR(a)
Definition: array.h:322
#define MAXDIM
Definition: array.h:75
#define ARR_NULLBITMAP(a)
Definition: array.h:300
#define DatumGetArrayTypeP(X)
Definition: array.h:261
#define ARR_SIZE(a)
Definition: array.h:289
#define ARR_DATA_OFFSET(a)
Definition: array.h:316
ArrayBuildStateArr * initArrayResultArr(Oid array_type, Oid element_type, MemoryContext rcontext, bool subcontext)
Definition: arrayfuncs.c:5485
void array_bitmap_copy(bits8 *destbitmap, int destoffset, const bits8 *srcbitmap, int srcoffset, int nitems)
Definition: arrayfuncs.c:4947
int ArrayGetNItems(int ndim, const int *dims)
Definition: arrayutils.c:57
#define Max(x, y)
Definition: c.h:985
char * Pointer
Definition: c.h:470
int i
Definition: isn.c:73
void pfree(void *pointer)
Definition: mcxt.c:1508
void * palloc(Size size)
Definition: mcxt.c:1304
void * arg
static uint32 pg_nextpower2_32(uint32 num)
Definition: pg_bitutils.h:189
const void * data
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312
#define InvalidOid
Definition: postgres_ext.h:36
bits8 * nullbitmap
Definition: array.h:209
int lbs[MAXDIM]
Definition: array.h:216
MemoryContext mcontext
Definition: array.h:207
int dims[MAXDIM]
Definition: array.h:215

References ArrayBuildStateArr::abytes, ArrayBuildStateArr::aitems, arg, ARR_DATA_OFFSET, ARR_DATA_PTR, ARR_DIMS, ARR_HASNULL, ARR_LBOUND, ARR_NDIM, ARR_NULLBITMAP, ARR_SIZE, array_bitmap_copy(), ArrayBuildStateArr::array_type, ArrayGetNItems(), Assert(), ArrayBuildStateArr::data, data, DatumGetArrayTypeP, DatumGetPointer(), ArrayBuildStateArr::dims, ereport, errcode(), errmsg(), ERROR, i, initArrayResultArr(), InvalidOid, ArrayBuildStateArr::lbs, Max, MAXDIM, ArrayBuildStateArr::mcontext, MemoryContextSwitchTo(), ArrayBuildStateArr::nbytes, ArrayBuildStateArr::ndims, ArrayBuildStateArr::nitems, nitems, ArrayBuildStateArr::nullbitmap, palloc(), pfree(), pg_nextpower2_32(), and repalloc().

Referenced by accumArrayResultAny(), and array_agg_array_transfn().

◆ array_bitmap_copy()

void array_bitmap_copy ( bits8 destbitmap,
int  destoffset,
const bits8 srcbitmap,
int  srcoffset,
int  nitems 
)

Definition at line 4947 of file arrayfuncs.c.

4950 {
4951  int destbitmask,
4952  destbitval,
4953  srcbitmask,
4954  srcbitval;
4955 
4956  Assert(destbitmap);
4957  if (nitems <= 0)
4958  return; /* don't risk fetch off end of memory */
4959  destbitmap += destoffset / 8;
4960  destbitmask = 1 << (destoffset % 8);
4961  destbitval = *destbitmap;
4962  if (srcbitmap)
4963  {
4964  srcbitmap += srcoffset / 8;
4965  srcbitmask = 1 << (srcoffset % 8);
4966  srcbitval = *srcbitmap;
4967  while (nitems-- > 0)
4968  {
4969  if (srcbitval & srcbitmask)
4970  destbitval |= destbitmask;
4971  else
4972  destbitval &= ~destbitmask;
4973  destbitmask <<= 1;
4974  if (destbitmask == 0x100)
4975  {
4976  *destbitmap++ = destbitval;
4977  destbitmask = 1;
4978  if (nitems > 0)
4979  destbitval = *destbitmap;
4980  }
4981  srcbitmask <<= 1;
4982  if (srcbitmask == 0x100)
4983  {
4984  srcbitmap++;
4985  srcbitmask = 1;
4986  if (nitems > 0)
4987  srcbitval = *srcbitmap;
4988  }
4989  }
4990  if (destbitmask != 1)
4991  *destbitmap = destbitval;
4992  }
4993  else
4994  {
4995  while (nitems-- > 0)
4996  {
4997  destbitval |= destbitmask;
4998  destbitmask <<= 1;
4999  if (destbitmask == 0x100)
5000  {
5001  *destbitmap++ = destbitval;
5002  destbitmask = 1;
5003  if (nitems > 0)
5004  destbitval = *destbitmap;
5005  }
5006  }
5007  if (destbitmask != 1)
5008  *destbitmap = destbitval;
5009  }
5010 }

References Assert(), and nitems.

Referenced by accumArrayResultArr(), array_agg_array_combine(), array_cat(), array_extract_slice(), array_insert_slice(), array_set_element(), array_set_slice(), ExecEvalArrayExpr(), and makeArrayResultArr().

◆ array_contains_nulls()

bool array_contains_nulls ( ArrayType array)

Definition at line 3748 of file arrayfuncs.c.

3749 {
3750  int nelems;
3751  bits8 *bitmap;
3752  int bitmask;
3753 
3754  /* Easy answer if there's no null bitmap */
3755  if (!ARR_HASNULL(array))
3756  return false;
3757 
3758  nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
3759 
3760  bitmap = ARR_NULLBITMAP(array);
3761 
3762  /* check whole bytes of the bitmap byte-at-a-time */
3763  while (nelems >= 8)
3764  {
3765  if (*bitmap != 0xFF)
3766  return true;
3767  bitmap++;
3768  nelems -= 8;
3769  }
3770 
3771  /* check last partial byte */
3772  bitmask = 1;
3773  while (nelems > 0)
3774  {
3775  if ((*bitmap & bitmask) == 0)
3776  return true;
3777  bitmask <<= 1;
3778  nelems--;
3779  }
3780 
3781  return false;
3782 }

References ARR_DIMS, ARR_HASNULL, ARR_NDIM, ARR_NULLBITMAP, and ArrayGetNItems().

Referenced by _arrq_cons(), _lca(), _lt_q_regex(), _ltree_compress(), array_fill_internal(), array_iterator(), array_position_common(), array_positions(), ArrayGetIntegerTypmods(), arrq_cons(), cube_a_f8(), cube_a_f8_f8(), cube_subset(), get_jsonb_path_all(), get_path_all(), getWeights(), lt_q_regex(), pg_isolation_test_session_is_blocked(), pg_logical_slot_get_changes_guts(), sanity_check_tid_array(), width_bucket_array(), and worker_spi_launch().

◆ array_create_iterator()

ArrayIterator array_create_iterator ( ArrayType arr,
int  slice_ndim,
ArrayMetaState mstate 
)

Definition at line 4578 of file arrayfuncs.c.

4579 {
4580  ArrayIterator iterator = palloc0(sizeof(ArrayIteratorData));
4581 
4582  /*
4583  * Sanity-check inputs --- caller should have got this right already
4584  */
4585  Assert(PointerIsValid(arr));
4586  if (slice_ndim < 0 || slice_ndim > ARR_NDIM(arr))
4587  elog(ERROR, "invalid arguments to array_create_iterator");
4588 
4589  /*
4590  * Remember basic info about the array and its element type
4591  */
4592  iterator->arr = arr;
4593  iterator->nullbitmap = ARR_NULLBITMAP(arr);
4594  iterator->nitems = ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr));
4595 
4596  if (mstate != NULL)
4597  {
4598  Assert(mstate->element_type == ARR_ELEMTYPE(arr));
4599 
4600  iterator->typlen = mstate->typlen;
4601  iterator->typbyval = mstate->typbyval;
4602  iterator->typalign = mstate->typalign;
4603  }
4604  else
4606  &iterator->typlen,
4607  &iterator->typbyval,
4608  &iterator->typalign);
4609 
4610  /*
4611  * Remember the slicing parameters.
4612  */
4613  iterator->slice_ndim = slice_ndim;
4614 
4615  if (slice_ndim > 0)
4616  {
4617  /*
4618  * Get pointers into the array's dims and lbound arrays to represent
4619  * the dims/lbound arrays of a slice. These are the same as the
4620  * rightmost N dimensions of the array.
4621  */
4622  iterator->slice_dims = ARR_DIMS(arr) + ARR_NDIM(arr) - slice_ndim;
4623  iterator->slice_lbound = ARR_LBOUND(arr) + ARR_NDIM(arr) - slice_ndim;
4624 
4625  /*
4626  * Compute number of elements in a slice.
4627  */
4628  iterator->slice_len = ArrayGetNItems(slice_ndim,
4629  iterator->slice_dims);
4630 
4631  /*
4632  * Create workspace for building sub-arrays.
4633  */
4634  iterator->slice_values = (Datum *)
4635  palloc(iterator->slice_len * sizeof(Datum));
4636  iterator->slice_nulls = (bool *)
4637  palloc(iterator->slice_len * sizeof(bool));
4638  }
4639 
4640  /*
4641  * Initialize our data pointer and linear element number. These will
4642  * advance through the array during array_iterate().
4643  */
4644  iterator->data_ptr = ARR_DATA_PTR(arr);
4645  iterator->current_item = 0;
4646 
4647  return iterator;
4648 }
#define PointerIsValid(pointer)
Definition: c.h:750
#define elog(elevel,...)
Definition: elog.h:224
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2227
void * palloc0(Size size)
Definition: mcxt.c:1334
ArrayType * arr
Definition: arrayfuncs.c:71
bool * slice_nulls
Definition: arrayfuncs.c:84
Datum * slice_values
Definition: arrayfuncs.c:83
bits8 * nullbitmap
Definition: arrayfuncs.c:72
char typalign
Definition: array.h:241
int16 typlen
Definition: array.h:239
Oid element_type
Definition: array.h:238
bool typbyval
Definition: array.h:240

References ArrayIteratorData::arr, ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_LBOUND, ARR_NDIM, ARR_NULLBITMAP, ArrayGetNItems(), Assert(), ArrayIteratorData::current_item, ArrayIteratorData::data_ptr, ArrayMetaState::element_type, elog, ERROR, get_typlenbyvalalign(), ArrayIteratorData::nitems, ArrayIteratorData::nullbitmap, palloc(), palloc0(), PointerIsValid, ArrayIteratorData::slice_dims, ArrayIteratorData::slice_lbound, ArrayIteratorData::slice_len, ArrayIteratorData::slice_ndim, ArrayIteratorData::slice_nulls, ArrayIteratorData::slice_values, ArrayIteratorData::typalign, ArrayMetaState::typalign, ArrayIteratorData::typbyval, ArrayMetaState::typbyval, ArrayIteratorData::typlen, and ArrayMetaState::typlen.

Referenced by array_position_common(), array_positions(), and exec_stmt_foreach_a().

◆ array_free_iterator()

void array_free_iterator ( ArrayIterator  iterator)

Definition at line 4740 of file arrayfuncs.c.

4741 {
4742  if (iterator->slice_ndim > 0)
4743  {
4744  pfree(iterator->slice_values);
4745  pfree(iterator->slice_nulls);
4746  }
4747  pfree(iterator);
4748 }

References pfree(), ArrayIteratorData::slice_ndim, ArrayIteratorData::slice_nulls, and ArrayIteratorData::slice_values.

Referenced by array_position_common(), and array_positions().

◆ array_get_element()

Datum array_get_element ( Datum  arraydatum,
int  nSubscripts,
int *  indx,
int  arraytyplen,
int  elmlen,
bool  elmbyval,
char  elmalign,
bool isNull 
)

Definition at line 1820 of file arrayfuncs.c.

1828 {
1829  int i,
1830  ndim,
1831  *dim,
1832  *lb,
1833  offset,
1834  fixedDim[1],
1835  fixedLb[1];
1836  char *arraydataptr,
1837  *retptr;
1838  bits8 *arraynullsptr;
1839 
1840  if (arraytyplen > 0)
1841  {
1842  /*
1843  * fixed-length arrays -- these are assumed to be 1-d, 0-based
1844  */
1845  ndim = 1;
1846  fixedDim[0] = arraytyplen / elmlen;
1847  fixedLb[0] = 0;
1848  dim = fixedDim;
1849  lb = fixedLb;
1850  arraydataptr = (char *) DatumGetPointer(arraydatum);
1851  arraynullsptr = NULL;
1852  }
1853  else if (VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(arraydatum)))
1854  {
1855  /* expanded array: let's do this in a separate function */
1856  return array_get_element_expanded(arraydatum,
1857  nSubscripts,
1858  indx,
1859  arraytyplen,
1860  elmlen,
1861  elmbyval,
1862  elmalign,
1863  isNull);
1864  }
1865  else
1866  {
1867  /* detoast array if necessary, producing normal varlena input */
1868  ArrayType *array = DatumGetArrayTypeP(arraydatum);
1869 
1870  ndim = ARR_NDIM(array);
1871  dim = ARR_DIMS(array);
1872  lb = ARR_LBOUND(array);
1873  arraydataptr = ARR_DATA_PTR(array);
1874  arraynullsptr = ARR_NULLBITMAP(array);
1875  }
1876 
1877  /*
1878  * Return NULL for invalid subscript
1879  */
1880  if (ndim != nSubscripts || ndim <= 0 || ndim > MAXDIM)
1881  {
1882  *isNull = true;
1883  return (Datum) 0;
1884  }
1885  for (i = 0; i < ndim; i++)
1886  {
1887  if (indx[i] < lb[i] || indx[i] >= (dim[i] + lb[i]))
1888  {
1889  *isNull = true;
1890  return (Datum) 0;
1891  }
1892  }
1893 
1894  /*
1895  * Calculate the element number
1896  */
1897  offset = ArrayGetOffset(nSubscripts, dim, lb, indx);
1898 
1899  /*
1900  * Check for NULL array element
1901  */
1902  if (array_get_isnull(arraynullsptr, offset))
1903  {
1904  *isNull = true;
1905  return (Datum) 0;
1906  }
1907 
1908  /*
1909  * OK, get the element
1910  */
1911  *isNull = false;
1912  retptr = array_seek(arraydataptr, 0, arraynullsptr, offset,
1913  elmlen, elmbyval, elmalign);
1914  return ArrayCast(retptr, elmbyval, elmlen);
1915 }
static bool array_get_isnull(const bits8 *nullbitmap, int offset)
Definition: arrayfuncs.c:4762
static Datum array_get_element_expanded(Datum arraydatum, int nSubscripts, int *indx, int arraytyplen, int elmlen, bool elmbyval, char elmalign, bool *isNull)
Definition: arrayfuncs.c:1921
static Datum ArrayCast(char *value, bool byval, int len)
Definition: arrayfuncs.c:4797
static char * array_seek(char *ptr, int offset, bits8 *nullbitmap, int nitems, int typlen, bool typbyval, char typalign)
Definition: arrayfuncs.c:4847
int ArrayGetOffset(int n, const int *dim, const int *lb, const int *indx)
Definition: arrayutils.c:32
#define VARATT_IS_EXTERNAL_EXPANDED(PTR)
Definition: varatt.h:298

References ARR_DATA_PTR, ARR_DIMS, ARR_LBOUND, ARR_NDIM, ARR_NULLBITMAP, array_get_element_expanded(), array_get_isnull(), array_seek(), ArrayCast(), ArrayGetOffset(), DatumGetArrayTypeP, DatumGetPointer(), i, MAXDIM, and VARATT_IS_EXTERNAL_EXPANDED.

Referenced by array_ref(), array_subscript_fetch(), array_subscript_fetch_old(), ATExecAlterColumnType(), and RelationBuildTupleDesc().

◆ array_get_slice()

Datum array_get_slice ( Datum  arraydatum,
int  nSubscripts,
int *  upperIndx,
int *  lowerIndx,
bool upperProvided,
bool lowerProvided,
int  arraytyplen,
int  elmlen,
bool  elmbyval,
char  elmalign 
)

Definition at line 2030 of file arrayfuncs.c.

2040 {
2041  ArrayType *array;
2042  ArrayType *newarray;
2043  int i,
2044  ndim,
2045  *dim,
2046  *lb,
2047  *newlb;
2048  int fixedDim[1],
2049  fixedLb[1];
2050  Oid elemtype;
2051  char *arraydataptr;
2052  bits8 *arraynullsptr;
2053  int32 dataoffset;
2054  int bytes,
2055  span[MAXDIM];
2056 
2057  if (arraytyplen > 0)
2058  {
2059  /*
2060  * fixed-length arrays -- currently, cannot slice these because parser
2061  * labels output as being of the fixed-length array type! Code below
2062  * shows how we could support it if the parser were changed to label
2063  * output as a suitable varlena array type.
2064  */
2065  ereport(ERROR,
2066  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2067  errmsg("slices of fixed-length arrays not implemented")));
2068 
2069  /*
2070  * fixed-length arrays -- these are assumed to be 1-d, 0-based
2071  *
2072  * XXX where would we get the correct ELEMTYPE from?
2073  */
2074  ndim = 1;
2075  fixedDim[0] = arraytyplen / elmlen;
2076  fixedLb[0] = 0;
2077  dim = fixedDim;
2078  lb = fixedLb;
2079  elemtype = InvalidOid; /* XXX */
2080  arraydataptr = (char *) DatumGetPointer(arraydatum);
2081  arraynullsptr = NULL;
2082  }
2083  else
2084  {
2085  /* detoast input array if necessary */
2086  array = DatumGetArrayTypeP(arraydatum);
2087 
2088  ndim = ARR_NDIM(array);
2089  dim = ARR_DIMS(array);
2090  lb = ARR_LBOUND(array);
2091  elemtype = ARR_ELEMTYPE(array);
2092  arraydataptr = ARR_DATA_PTR(array);
2093  arraynullsptr = ARR_NULLBITMAP(array);
2094  }
2095 
2096  /*
2097  * Check provided subscripts. A slice exceeding the current array limits
2098  * is silently truncated to the array limits. If we end up with an empty
2099  * slice, return an empty array.
2100  */
2101  if (ndim < nSubscripts || ndim <= 0 || ndim > MAXDIM)
2102  return PointerGetDatum(construct_empty_array(elemtype));
2103 
2104  for (i = 0; i < nSubscripts; i++)
2105  {
2106  if (!lowerProvided[i] || lowerIndx[i] < lb[i])
2107  lowerIndx[i] = lb[i];
2108  if (!upperProvided[i] || upperIndx[i] >= (dim[i] + lb[i]))
2109  upperIndx[i] = dim[i] + lb[i] - 1;
2110  if (lowerIndx[i] > upperIndx[i])
2111  return PointerGetDatum(construct_empty_array(elemtype));
2112  }
2113  /* fill any missing subscript positions with full array range */
2114  for (; i < ndim; i++)
2115  {
2116  lowerIndx[i] = lb[i];
2117  upperIndx[i] = dim[i] + lb[i] - 1;
2118  if (lowerIndx[i] > upperIndx[i])
2119  return PointerGetDatum(construct_empty_array(elemtype));
2120  }
2121 
2122  mda_get_range(ndim, span, lowerIndx, upperIndx);
2123 
2124  bytes = array_slice_size(arraydataptr, arraynullsptr,
2125  ndim, dim, lb,
2126  lowerIndx, upperIndx,
2127  elmlen, elmbyval, elmalign);
2128 
2129  /*
2130  * Currently, we put a null bitmap in the result if the source has one;
2131  * could be smarter ...
2132  */
2133  if (arraynullsptr)
2134  {
2135  dataoffset = ARR_OVERHEAD_WITHNULLS(ndim, ArrayGetNItems(ndim, span));
2136  bytes += dataoffset;
2137  }
2138  else
2139  {
2140  dataoffset = 0; /* marker for no null bitmap */
2141  bytes += ARR_OVERHEAD_NONULLS(ndim);
2142  }
2143 
2144  newarray = (ArrayType *) palloc0(bytes);
2145  SET_VARSIZE(newarray, bytes);
2146  newarray->ndim = ndim;
2147  newarray->dataoffset = dataoffset;
2148  newarray->elemtype = elemtype;
2149  memcpy(ARR_DIMS(newarray), span, ndim * sizeof(int));
2150 
2151  /*
2152  * Lower bounds of the new array are set to 1. Formerly (before 7.3) we
2153  * copied the given lowerIndx values ... but that seems confusing.
2154  */
2155  newlb = ARR_LBOUND(newarray);
2156  for (i = 0; i < ndim; i++)
2157  newlb[i] = 1;
2158 
2159  array_extract_slice(newarray,
2160  ndim, dim, lb,
2161  arraydataptr, arraynullsptr,
2162  lowerIndx, upperIndx,
2163  elmlen, elmbyval, elmalign);
2164 
2165  return PointerGetDatum(newarray);
2166 }
#define ARR_OVERHEAD_WITHNULLS(ndims, nitems)
Definition: array.h:312
#define ARR_OVERHEAD_NONULLS(ndims)
Definition: array.h:310
static int array_slice_size(char *arraydataptr, bits8 *arraynullsptr, int ndim, int *dim, int *lb, int *st, int *endp, int typlen, bool typbyval, char typalign)
Definition: arrayfuncs.c:5018
ArrayType * construct_empty_array(Oid elmtype)
Definition: arrayfuncs.c:3561
static void array_extract_slice(ArrayType *newarray, int ndim, int *dim, int *lb, char *arraydataptr, bits8 *arraynullsptr, int *st, int *endp, int typlen, bool typbyval, char typalign)
Definition: arrayfuncs.c:5078
void mda_get_range(int n, int *span, const int *st, const int *endp)
Definition: arrayutils.c:153
signed int int32
Definition: c.h:481
unsigned int Oid
Definition: postgres_ext.h:31
Oid elemtype
Definition: array.h:97
int ndim
Definition: array.h:95
int32 dataoffset
Definition: array.h:96
#define SET_VARSIZE(PTR, len)
Definition: varatt.h:305

References ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_LBOUND, ARR_NDIM, ARR_NULLBITMAP, ARR_OVERHEAD_NONULLS, ARR_OVERHEAD_WITHNULLS, array_extract_slice(), array_slice_size(), ArrayGetNItems(), construct_empty_array(), ArrayType::dataoffset, DatumGetArrayTypeP, DatumGetPointer(), ArrayType::elemtype, ereport, errcode(), errmsg(), ERROR, i, InvalidOid, MAXDIM, mda_get_range(), ArrayType::ndim, palloc0(), PointerGetDatum(), and SET_VARSIZE.

Referenced by array_subscript_fetch_old_slice(), array_subscript_fetch_slice(), and trim_array().

◆ array_iterate()

bool array_iterate ( ArrayIterator  iterator,
Datum value,
bool isnull 
)

Definition at line 4657 of file arrayfuncs.c.

4658 {
4659  /* Done if we have reached the end of the array */
4660  if (iterator->current_item >= iterator->nitems)
4661  return false;
4662 
4663  if (iterator->slice_ndim == 0)
4664  {
4665  /*
4666  * Scalar case: return one element.
4667  */
4668  if (array_get_isnull(iterator->nullbitmap, iterator->current_item++))
4669  {
4670  *isnull = true;
4671  *value = (Datum) 0;
4672  }
4673  else
4674  {
4675  /* non-NULL, so fetch the individual Datum to return */
4676  char *p = iterator->data_ptr;
4677 
4678  *isnull = false;
4679  *value = fetch_att(p, iterator->typbyval, iterator->typlen);
4680 
4681  /* Move our data pointer forward to the next element */
4682  p = att_addlength_pointer(p, iterator->typlen, p);
4683  p = (char *) att_align_nominal(p, iterator->typalign);
4684  iterator->data_ptr = p;
4685  }
4686  }
4687  else
4688  {
4689  /*
4690  * Slice case: build and return an array of the requested size.
4691  */
4692  ArrayType *result;
4693  Datum *values = iterator->slice_values;
4694  bool *nulls = iterator->slice_nulls;
4695  char *p = iterator->data_ptr;
4696  int i;
4697 
4698  for (i = 0; i < iterator->slice_len; i++)
4699  {
4700  if (array_get_isnull(iterator->nullbitmap,
4701  iterator->current_item++))
4702  {
4703  nulls[i] = true;
4704  values[i] = (Datum) 0;
4705  }
4706  else
4707  {
4708  nulls[i] = false;
4709  values[i] = fetch_att(p, iterator->typbyval, iterator->typlen);
4710 
4711  /* Move our data pointer forward to the next element */
4712  p = att_addlength_pointer(p, iterator->typlen, p);
4713  p = (char *) att_align_nominal(p, iterator->typalign);
4714  }
4715  }
4716 
4717  iterator->data_ptr = p;
4718 
4719  result = construct_md_array(values,
4720  nulls,
4721  iterator->slice_ndim,
4722  iterator->slice_dims,
4723  iterator->slice_lbound,
4724  ARR_ELEMTYPE(iterator->arr),
4725  iterator->typlen,
4726  iterator->typbyval,
4727  iterator->typalign);
4728 
4729  *isnull = false;
4730  *value = PointerGetDatum(result);
4731  }
4732 
4733  return true;
4734 }
ArrayType * construct_md_array(Datum *elems, bool *nulls, int ndims, int *dims, int *lbs, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:3475
static Datum values[MAXATTR]
Definition: bootstrap.c:152
static struct @150 value
#define att_align_nominal(cur_offset, attalign)
Definition: tupmacs.h:129
#define att_addlength_pointer(cur_offset, attlen, attptr)
Definition: tupmacs.h:157
static Datum fetch_att(const void *T, bool attbyval, int attlen)
Definition: tupmacs.h:52

References ArrayIteratorData::arr, ARR_ELEMTYPE, array_get_isnull(), att_addlength_pointer, att_align_nominal, construct_md_array(), ArrayIteratorData::current_item, ArrayIteratorData::data_ptr, fetch_att(), i, ArrayIteratorData::nitems, ArrayIteratorData::nullbitmap, PointerGetDatum(), ArrayIteratorData::slice_dims, ArrayIteratorData::slice_lbound, ArrayIteratorData::slice_len, ArrayIteratorData::slice_ndim, ArrayIteratorData::slice_nulls, ArrayIteratorData::slice_values, ArrayIteratorData::typalign, ArrayIteratorData::typbyval, ArrayIteratorData::typlen, value, and values.

Referenced by array_position_common(), array_positions(), and exec_stmt_foreach_a().

◆ array_map()

Datum array_map ( Datum  arrayd,
struct ExprState exprstate,
struct ExprContext econtext,
Oid  retType,
ArrayMapState amstate 
)

Definition at line 3194 of file arrayfuncs.c.

3197 {
3198  AnyArrayType *v = DatumGetAnyArrayP(arrayd);
3199  ArrayType *result;
3200  Datum *values;
3201  bool *nulls;
3202  int *dim;
3203  int ndim;
3204  int nitems;
3205  int i;
3206  int32 nbytes = 0;
3207  int32 dataoffset;
3208  bool hasnulls;
3209  Oid inpType;
3210  int inp_typlen;
3211  bool inp_typbyval;
3212  char inp_typalign;
3213  int typlen;
3214  bool typbyval;
3215  char typalign;
3216  array_iter iter;
3217  ArrayMetaState *inp_extra;
3218  ArrayMetaState *ret_extra;
3219  Datum *transform_source = exprstate->innermost_caseval;
3220  bool *transform_source_isnull = exprstate->innermost_casenull;
3221 
3222  inpType = AARR_ELEMTYPE(v);
3223  ndim = AARR_NDIM(v);
3224  dim = AARR_DIMS(v);
3225  nitems = ArrayGetNItems(ndim, dim);
3226 
3227  /* Check for empty array */
3228  if (nitems <= 0)
3229  {
3230  /* Return empty array */
3231  return PointerGetDatum(construct_empty_array(retType));
3232  }
3233 
3234  /*
3235  * We arrange to look up info about input and return element types only
3236  * once per series of calls, assuming the element type doesn't change
3237  * underneath us.
3238  */
3239  inp_extra = &amstate->inp_extra;
3240  ret_extra = &amstate->ret_extra;
3241 
3242  if (inp_extra->element_type != inpType)
3243  {
3244  get_typlenbyvalalign(inpType,
3245  &inp_extra->typlen,
3246  &inp_extra->typbyval,
3247  &inp_extra->typalign);
3248  inp_extra->element_type = inpType;
3249  }
3250  inp_typlen = inp_extra->typlen;
3251  inp_typbyval = inp_extra->typbyval;
3252  inp_typalign = inp_extra->typalign;
3253 
3254  if (ret_extra->element_type != retType)
3255  {
3256  get_typlenbyvalalign(retType,
3257  &ret_extra->typlen,
3258  &ret_extra->typbyval,
3259  &ret_extra->typalign);
3260  ret_extra->element_type = retType;
3261  }
3262  typlen = ret_extra->typlen;
3263  typbyval = ret_extra->typbyval;
3264  typalign = ret_extra->typalign;
3265 
3266  /* Allocate temporary arrays for new values */
3267  values = (Datum *) palloc(nitems * sizeof(Datum));
3268  nulls = (bool *) palloc(nitems * sizeof(bool));
3269 
3270  /* Loop over source data */
3271  array_iter_setup(&iter, v);
3272  hasnulls = false;
3273 
3274  for (i = 0; i < nitems; i++)
3275  {
3276  /* Get source element, checking for NULL */
3277  *transform_source =
3278  array_iter_next(&iter, transform_source_isnull, i,
3279  inp_typlen, inp_typbyval, inp_typalign);
3280 
3281  /* Apply the given expression to source element */
3282  values[i] = ExecEvalExpr(exprstate, econtext, &nulls[i]);
3283 
3284  if (nulls[i])
3285  hasnulls = true;
3286  else
3287  {
3288  /* Ensure data is not toasted */
3289  if (typlen == -1)
3291  /* Update total result size */
3292  nbytes = att_addlength_datum(nbytes, typlen, values[i]);
3293  nbytes = att_align_nominal(nbytes, typalign);
3294  /* check for overflow of total request */
3295  if (!AllocSizeIsValid(nbytes))
3296  ereport(ERROR,
3297  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
3298  errmsg("array size exceeds the maximum allowed (%d)",
3299  (int) MaxAllocSize)));
3300  }
3301  }
3302 
3303  /* Allocate and fill the result array */
3304  if (hasnulls)
3305  {
3306  dataoffset = ARR_OVERHEAD_WITHNULLS(ndim, nitems);
3307  nbytes += dataoffset;
3308  }
3309  else
3310  {
3311  dataoffset = 0; /* marker for no null bitmap */
3312  nbytes += ARR_OVERHEAD_NONULLS(ndim);
3313  }
3314  result = (ArrayType *) palloc0(nbytes);
3315  SET_VARSIZE(result, nbytes);
3316  result->ndim = ndim;
3317  result->dataoffset = dataoffset;
3318  result->elemtype = retType;
3319  memcpy(ARR_DIMS(result), AARR_DIMS(v), ndim * sizeof(int));
3320  memcpy(ARR_LBOUND(result), AARR_LBOUND(v), ndim * sizeof(int));
3321 
3322  CopyArrayEls(result,
3323  values, nulls, nitems,
3324  typlen, typbyval, typalign,
3325  false);
3326 
3327  /*
3328  * Note: do not risk trying to pfree the results of the called expression
3329  */
3330  pfree(values);
3331  pfree(nulls);
3332 
3333  return PointerGetDatum(result);
3334 }
#define AARR_DIMS(a)
Definition: array.h:338
#define AARR_ELEMTYPE(a)
Definition: array.h:335
#define AARR_LBOUND(a)
Definition: array.h:341
#define AARR_NDIM(a)
Definition: array.h:328
AnyArrayType * DatumGetAnyArrayP(Datum d)
static Datum array_iter_next(array_iter *it, bool *isnull, int i, int elmlen, bool elmbyval, char elmalign)
Definition: arrayaccess.h:81
static void array_iter_setup(array_iter *it, AnyArrayType *a)
Definition: arrayaccess.h:49
void CopyArrayEls(ArrayType *array, Datum *values, bool *nulls, int nitems, int typlen, bool typbyval, char typalign, bool freedata)
Definition: arrayfuncs.c:961
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:333
#define PG_DETOAST_DATUM(datum)
Definition: fmgr.h:240
char typalign
Definition: pg_type.h:176
ArrayMetaState inp_extra
Definition: array.h:253
ArrayMetaState ret_extra
Definition: array.h:254
bool * innermost_casenull
Definition: execnodes.h:129
Datum * innermost_caseval
Definition: execnodes.h:128
#define att_addlength_datum(cur_offset, attlen, attdatum)
Definition: tupmacs.h:145

References AARR_DIMS, AARR_ELEMTYPE, AARR_LBOUND, AARR_NDIM, AllocSizeIsValid, ARR_DIMS, ARR_LBOUND, ARR_OVERHEAD_NONULLS, ARR_OVERHEAD_WITHNULLS, array_iter_next(), array_iter_setup(), ArrayGetNItems(), att_addlength_datum, att_align_nominal, construct_empty_array(), CopyArrayEls(), ArrayType::dataoffset, DatumGetAnyArrayP(), ArrayMetaState::element_type, ArrayType::elemtype, ereport, errcode(), errmsg(), ERROR, ExecEvalExpr(), get_typlenbyvalalign(), i, ExprState::innermost_casenull, ExprState::innermost_caseval, ArrayMapState::inp_extra, MaxAllocSize, ArrayType::ndim, nitems, palloc(), palloc0(), pfree(), PG_DETOAST_DATUM, PointerGetDatum(), ArrayMapState::ret_extra, SET_VARSIZE, typalign, ArrayMetaState::typalign, ArrayMetaState::typbyval, ArrayMetaState::typlen, and values.

Referenced by ExecEvalArrayCoerce().

◆ array_ref()

Datum array_ref ( ArrayType array,
int  nSubscripts,
int *  indx,
int  arraytyplen,
int  elmlen,
bool  elmbyval,
char  elmalign,
bool isNull 
)

Definition at line 3139 of file arrayfuncs.c.

3142 {
3143  return array_get_element(PointerGetDatum(array), nSubscripts, indx,
3144  arraytyplen, elmlen, elmbyval, elmalign,
3145  isNull);
3146 }
Datum array_get_element(Datum arraydatum, int nSubscripts, int *indx, int arraytyplen, int elmlen, bool elmbyval, char elmalign, bool *isNull)
Definition: arrayfuncs.c:1820

References array_get_element(), and PointerGetDatum().

Referenced by GUCArrayAdd(), GUCArrayDelete(), GUCArrayReset(), pg_get_functiondef(), and TransformGUCArray().

◆ array_set()

ArrayType* array_set ( ArrayType array,
int  nSubscripts,
int *  indx,
Datum  dataValue,
bool  isNull,
int  arraytyplen,
int  elmlen,
bool  elmbyval,
char  elmalign 
)

Definition at line 3156 of file arrayfuncs.c.

3159 {
3161  nSubscripts, indx,
3162  dataValue, isNull,
3163  arraytyplen,
3164  elmlen, elmbyval, elmalign));
3165 }
Datum array_set_element(Datum arraydatum, int nSubscripts, int *indx, Datum dataValue, bool isNull, int arraytyplen, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:2201

References array_set_element(), DatumGetArrayTypeP, and PointerGetDatum().

Referenced by GUCArrayAdd(), GUCArrayDelete(), GUCArrayReset(), and pg_extension_config_dump().

◆ array_set_element()

Datum array_set_element ( Datum  arraydatum,
int  nSubscripts,
int *  indx,
Datum  dataValue,
bool  isNull,
int  arraytyplen,
int  elmlen,
bool  elmbyval,
char  elmalign 
)

Definition at line 2201 of file arrayfuncs.c.

2210 {
2211  ArrayType *array;
2212  ArrayType *newarray;
2213  int i,
2214  ndim,
2215  dim[MAXDIM],
2216  lb[MAXDIM],
2217  offset;
2218  char *elt_ptr;
2219  bool newhasnulls;
2220  bits8 *oldnullbitmap;
2221  int oldnitems,
2222  newnitems,
2223  olddatasize,
2224  newsize,
2225  olditemlen,
2226  newitemlen,
2227  overheadlen,
2228  oldoverheadlen,
2229  addedbefore,
2230  addedafter,
2231  lenbefore,
2232  lenafter;
2233 
2234  if (arraytyplen > 0)
2235  {
2236  /*
2237  * fixed-length arrays -- these are assumed to be 1-d, 0-based. We
2238  * cannot extend them, either.
2239  */
2240  char *resultarray;
2241 
2242  if (nSubscripts != 1)
2243  ereport(ERROR,
2244  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
2245  errmsg("wrong number of array subscripts")));
2246 
2247  if (indx[0] < 0 || indx[0] >= arraytyplen / elmlen)
2248  ereport(ERROR,
2249  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
2250  errmsg("array subscript out of range")));
2251 
2252  if (isNull)
2253  ereport(ERROR,
2254  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
2255  errmsg("cannot assign null value to an element of a fixed-length array")));
2256 
2257  resultarray = (char *) palloc(arraytyplen);
2258  memcpy(resultarray, DatumGetPointer(arraydatum), arraytyplen);
2259  elt_ptr = (char *) resultarray + indx[0] * elmlen;
2260  ArrayCastAndSet(dataValue, elmlen, elmbyval, elmalign, elt_ptr);
2261  return PointerGetDatum(resultarray);
2262  }
2263 
2264  if (nSubscripts <= 0 || nSubscripts > MAXDIM)
2265  ereport(ERROR,
2266  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
2267  errmsg("wrong number of array subscripts")));
2268 
2269  /* make sure item to be inserted is not toasted */
2270  if (elmlen == -1 && !isNull)
2271  dataValue = PointerGetDatum(PG_DETOAST_DATUM(dataValue));
2272 
2274  {
2275  /* expanded array: let's do this in a separate function */
2276  return array_set_element_expanded(arraydatum,
2277  nSubscripts,
2278  indx,
2279  dataValue,
2280  isNull,
2281  arraytyplen,
2282  elmlen,
2283  elmbyval,
2284  elmalign);
2285  }
2286 
2287  /* detoast input array if necessary */
2288  array = DatumGetArrayTypeP(arraydatum);
2289 
2290  ndim = ARR_NDIM(array);
2291 
2292  /*
2293  * if number of dims is zero, i.e. an empty array, create an array with
2294  * nSubscripts dimensions, and set the lower bounds to the supplied
2295  * subscripts
2296  */
2297  if (ndim == 0)
2298  {
2299  Oid elmtype = ARR_ELEMTYPE(array);
2300 
2301  for (i = 0; i < nSubscripts; i++)
2302  {
2303  dim[i] = 1;
2304  lb[i] = indx[i];
2305  }
2306 
2307  return PointerGetDatum(construct_md_array(&dataValue, &isNull,
2308  nSubscripts, dim, lb,
2309  elmtype,
2310  elmlen, elmbyval, elmalign));
2311  }
2312 
2313  if (ndim != nSubscripts)
2314  ereport(ERROR,
2315  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
2316  errmsg("wrong number of array subscripts")));
2317 
2318  /* copy dim/lb since we may modify them */
2319  memcpy(dim, ARR_DIMS(array), ndim * sizeof(int));
2320  memcpy(lb, ARR_LBOUND(array), ndim * sizeof(int));
2321 
2322  newhasnulls = (ARR_HASNULL(array) || isNull);
2323  addedbefore = addedafter = 0;
2324 
2325  /*
2326  * Check subscripts. We assume the existing subscripts passed
2327  * ArrayCheckBounds, so that dim[i] + lb[i] can be computed without
2328  * overflow. But we must beware of other overflows in our calculations of
2329  * new dim[] values.
2330  */
2331  if (ndim == 1)
2332  {
2333  if (indx[0] < lb[0])
2334  {
2335  /* addedbefore = lb[0] - indx[0]; */
2336  /* dim[0] += addedbefore; */
2337  if (pg_sub_s32_overflow(lb[0], indx[0], &addedbefore) ||
2338  pg_add_s32_overflow(dim[0], addedbefore, &dim[0]))
2339  ereport(ERROR,
2340  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
2341  errmsg("array size exceeds the maximum allowed (%d)",
2342  (int) MaxArraySize)));
2343  lb[0] = indx[0];
2344  if (addedbefore > 1)
2345  newhasnulls = true; /* will insert nulls */
2346  }
2347  if (indx[0] >= (dim[0] + lb[0]))
2348  {
2349  /* addedafter = indx[0] - (dim[0] + lb[0]) + 1; */
2350  /* dim[0] += addedafter; */
2351  if (pg_sub_s32_overflow(indx[0], dim[0] + lb[0], &addedafter) ||
2352  pg_add_s32_overflow(addedafter, 1, &addedafter) ||
2353  pg_add_s32_overflow(dim[0], addedafter, &dim[0]))
2354  ereport(ERROR,
2355  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
2356  errmsg("array size exceeds the maximum allowed (%d)",
2357  (int) MaxArraySize)));
2358  if (addedafter > 1)
2359  newhasnulls = true; /* will insert nulls */
2360  }
2361  }
2362  else
2363  {
2364  /*
2365  * XXX currently we do not support extending multi-dimensional arrays
2366  * during assignment
2367  */
2368  for (i = 0; i < ndim; i++)
2369  {
2370  if (indx[i] < lb[i] ||
2371  indx[i] >= (dim[i] + lb[i]))
2372  ereport(ERROR,
2373  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
2374  errmsg("array subscript out of range")));
2375  }
2376  }
2377 
2378  /* This checks for overflow of the array dimensions */
2379  newnitems = ArrayGetNItems(ndim, dim);
2380  ArrayCheckBounds(ndim, dim, lb);
2381 
2382  /*
2383  * Compute sizes of items and areas to copy
2384  */
2385  if (newhasnulls)
2386  overheadlen = ARR_OVERHEAD_WITHNULLS(ndim, newnitems);
2387  else
2388  overheadlen = ARR_OVERHEAD_NONULLS(ndim);
2389  oldnitems = ArrayGetNItems(ndim, ARR_DIMS(array));
2390  oldnullbitmap = ARR_NULLBITMAP(array);
2391  oldoverheadlen = ARR_DATA_OFFSET(array);
2392  olddatasize = ARR_SIZE(array) - oldoverheadlen;
2393  if (addedbefore)
2394  {
2395  offset = 0;
2396  lenbefore = 0;
2397  olditemlen = 0;
2398  lenafter = olddatasize;
2399  }
2400  else if (addedafter)
2401  {
2402  offset = oldnitems;
2403  lenbefore = olddatasize;
2404  olditemlen = 0;
2405  lenafter = 0;
2406  }
2407  else
2408  {
2409  offset = ArrayGetOffset(nSubscripts, dim, lb, indx);
2410  elt_ptr = array_seek(ARR_DATA_PTR(array), 0, oldnullbitmap, offset,
2411  elmlen, elmbyval, elmalign);
2412  lenbefore = (int) (elt_ptr - ARR_DATA_PTR(array));
2413  if (array_get_isnull(oldnullbitmap, offset))
2414  olditemlen = 0;
2415  else
2416  {
2417  olditemlen = att_addlength_pointer(0, elmlen, elt_ptr);
2418  olditemlen = att_align_nominal(olditemlen, elmalign);
2419  }
2420  lenafter = (int) (olddatasize - lenbefore - olditemlen);
2421  }
2422 
2423  if (isNull)
2424  newitemlen = 0;
2425  else
2426  {
2427  newitemlen = att_addlength_datum(0, elmlen, dataValue);
2428  newitemlen = att_align_nominal(newitemlen, elmalign);
2429  }
2430 
2431  newsize = overheadlen + lenbefore + newitemlen + lenafter;
2432 
2433  /*
2434  * OK, create the new array and fill in header/dimensions
2435  */
2436  newarray = (ArrayType *) palloc0(newsize);
2437  SET_VARSIZE(newarray, newsize);
2438  newarray->ndim = ndim;
2439  newarray->dataoffset = newhasnulls ? overheadlen : 0;
2440  newarray->elemtype = ARR_ELEMTYPE(array);
2441  memcpy(ARR_DIMS(newarray), dim, ndim * sizeof(int));
2442  memcpy(ARR_LBOUND(newarray), lb, ndim * sizeof(int));
2443 
2444  /*
2445  * Fill in data
2446  */
2447  memcpy((char *) newarray + overheadlen,
2448  (char *) array + oldoverheadlen,
2449  lenbefore);
2450  if (!isNull)
2451  ArrayCastAndSet(dataValue, elmlen, elmbyval, elmalign,
2452  (char *) newarray + overheadlen + lenbefore);
2453  memcpy((char *) newarray + overheadlen + lenbefore + newitemlen,
2454  (char *) array + oldoverheadlen + lenbefore + olditemlen,
2455  lenafter);
2456 
2457  /*
2458  * Fill in nulls bitmap if needed
2459  *
2460  * Note: it's possible we just replaced the last NULL with a non-NULL, and
2461  * could get rid of the bitmap. Seems not worth testing for though.
2462  */
2463  if (newhasnulls)
2464  {
2465  bits8 *newnullbitmap = ARR_NULLBITMAP(newarray);
2466 
2467  /* palloc0 above already marked any inserted positions as nulls */
2468  /* Fix the inserted value */
2469  if (addedafter)
2470  array_set_isnull(newnullbitmap, newnitems - 1, isNull);
2471  else
2472  array_set_isnull(newnullbitmap, offset, isNull);
2473  /* Fix the copied range(s) */
2474  if (addedbefore)
2475  array_bitmap_copy(newnullbitmap, addedbefore,
2476  oldnullbitmap, 0,
2477  oldnitems);
2478  else
2479  {
2480  array_bitmap_copy(newnullbitmap, 0,
2481  oldnullbitmap, 0,
2482  offset);
2483  if (addedafter == 0)
2484  array_bitmap_copy(newnullbitmap, offset + 1,
2485  oldnullbitmap, offset + 1,
2486  oldnitems - offset - 1);
2487  }
2488  }
2489 
2490  return PointerGetDatum(newarray);
2491 }
#define MaxArraySize
Definition: array.h:82
static Datum array_set_element_expanded(Datum arraydatum, int nSubscripts, int *indx, Datum dataValue, bool isNull, int arraytyplen, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:2501
static void array_set_isnull(bits8 *nullbitmap, int offset, bool isNull)
Definition: arrayfuncs.c:4779
static int ArrayCastAndSet(Datum src, int typlen, bool typbyval, char typalign, char *dest)
Definition: arrayfuncs.c:4808
void ArrayCheckBounds(int ndim, const int *dims, const int *lb)
Definition: arrayutils.c:117
static bool pg_sub_s32_overflow(int32 a, int32 b, int32 *result)
Definition: int.h:122
static bool pg_add_s32_overflow(int32 a, int32 b, int32 *result)
Definition: int.h:104

References ARR_DATA_OFFSET, ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_HASNULL, ARR_LBOUND, ARR_NDIM, ARR_NULLBITMAP, ARR_OVERHEAD_NONULLS, ARR_OVERHEAD_WITHNULLS, ARR_SIZE, array_bitmap_copy(), array_get_isnull(), array_seek(), array_set_element_expanded(), array_set_isnull(), ArrayCastAndSet(), ArrayCheckBounds(), ArrayGetNItems(), ArrayGetOffset(), att_addlength_datum, att_addlength_pointer, att_align_nominal, construct_md_array(), ArrayType::dataoffset, DatumGetArrayTypeP, DatumGetPointer(), ArrayType::elemtype, ereport, errcode(), errmsg(), ERROR, i, MaxArraySize, MAXDIM, ArrayType::ndim, palloc(), palloc0(), pg_add_s32_overflow(), PG_DETOAST_DATUM, pg_sub_s32_overflow(), PointerGetDatum(), SET_VARSIZE, and VARATT_IS_EXTERNAL_EXPANDED.

Referenced by array_append(), array_prepend(), array_set(), and array_subscript_assign().

◆ array_set_slice()

Datum array_set_slice ( Datum  arraydatum,
int  nSubscripts,
int *  upperIndx,
int *  lowerIndx,
bool upperProvided,
bool lowerProvided,
Datum  srcArrayDatum,
bool  isNull,
int  arraytyplen,
int  elmlen,
bool  elmbyval,
char  elmalign 
)

Definition at line 2806 of file arrayfuncs.c.

2818 {
2819  ArrayType *array;
2820  ArrayType *srcArray;
2821  ArrayType *newarray;
2822  int i,
2823  ndim,
2824  dim[MAXDIM],
2825  lb[MAXDIM],
2826  span[MAXDIM];
2827  bool newhasnulls;
2828  int nitems,
2829  nsrcitems,
2830  olddatasize,
2831  newsize,
2832  olditemsize,
2833  newitemsize,
2834  overheadlen,
2835  oldoverheadlen,
2836  addedbefore,
2837  addedafter,
2838  lenbefore,
2839  lenafter,
2840  itemsbefore,
2841  itemsafter,
2842  nolditems;
2843 
2844  /* Currently, assignment from a NULL source array is a no-op */
2845  if (isNull)
2846  return arraydatum;
2847 
2848  if (arraytyplen > 0)
2849  {
2850  /*
2851  * fixed-length arrays -- not got round to doing this...
2852  */
2853  ereport(ERROR,
2854  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2855  errmsg("updates on slices of fixed-length arrays not implemented")));
2856  }
2857 
2858  /* detoast arrays if necessary */
2859  array = DatumGetArrayTypeP(arraydatum);
2860  srcArray = DatumGetArrayTypeP(srcArrayDatum);
2861 
2862  /* note: we assume srcArray contains no toasted elements */
2863 
2864  ndim = ARR_NDIM(array);
2865 
2866  /*
2867  * if number of dims is zero, i.e. an empty array, create an array with
2868  * nSubscripts dimensions, and set the upper and lower bounds to the
2869  * supplied subscripts
2870  */
2871  if (ndim == 0)
2872  {
2873  Datum *dvalues;
2874  bool *dnulls;
2875  int nelems;
2876  Oid elmtype = ARR_ELEMTYPE(array);
2877 
2878  deconstruct_array(srcArray, elmtype, elmlen, elmbyval, elmalign,
2879  &dvalues, &dnulls, &nelems);
2880 
2881  for (i = 0; i < nSubscripts; i++)
2882  {
2883  if (!upperProvided[i] || !lowerProvided[i])
2884  ereport(ERROR,
2885  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
2886  errmsg("array slice subscript must provide both boundaries"),
2887  errdetail("When assigning to a slice of an empty array value,"
2888  " slice boundaries must be fully specified.")));
2889 
2890  dim[i] = 1 + upperIndx[i] - lowerIndx[i];
2891  lb[i] = lowerIndx[i];
2892  }
2893 
2894  /* complain if too few source items; we ignore extras, however */
2895  if (nelems < ArrayGetNItems(nSubscripts, dim))
2896  ereport(ERROR,
2897  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
2898  errmsg("source array too small")));
2899 
2900  return PointerGetDatum(construct_md_array(dvalues, dnulls, nSubscripts,
2901  dim, lb, elmtype,
2902  elmlen, elmbyval, elmalign));
2903  }
2904 
2905  if (ndim < nSubscripts || ndim <= 0 || ndim > MAXDIM)
2906  ereport(ERROR,
2907  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
2908  errmsg("wrong number of array subscripts")));
2909 
2910  /* copy dim/lb since we may modify them */
2911  memcpy(dim, ARR_DIMS(array), ndim * sizeof(int));
2912  memcpy(lb, ARR_LBOUND(array), ndim * sizeof(int));
2913 
2914  newhasnulls = (ARR_HASNULL(array) || ARR_HASNULL(srcArray));
2915  addedbefore = addedafter = 0;
2916 
2917  /*
2918  * Check subscripts. We assume the existing subscripts passed
2919  * ArrayCheckBounds, so that dim[i] + lb[i] can be computed without
2920  * overflow. But we must beware of other overflows in our calculations of
2921  * new dim[] values.
2922  */
2923  if (ndim == 1)
2924  {
2925  Assert(nSubscripts == 1);
2926  if (!lowerProvided[0])
2927  lowerIndx[0] = lb[0];
2928  if (!upperProvided[0])
2929  upperIndx[0] = dim[0] + lb[0] - 1;
2930  if (lowerIndx[0] > upperIndx[0])
2931  ereport(ERROR,
2932  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
2933  errmsg("upper bound cannot be less than lower bound")));
2934  if (lowerIndx[0] < lb[0])
2935  {
2936  /* addedbefore = lb[0] - lowerIndx[0]; */
2937  /* dim[0] += addedbefore; */
2938  if (pg_sub_s32_overflow(lb[0], lowerIndx[0], &addedbefore) ||
2939  pg_add_s32_overflow(dim[0], addedbefore, &dim[0]))
2940  ereport(ERROR,
2941  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
2942  errmsg("array size exceeds the maximum allowed (%d)",
2943  (int) MaxArraySize)));
2944  lb[0] = lowerIndx[0];
2945  if (addedbefore > 1)
2946  newhasnulls = true; /* will insert nulls */
2947  }
2948  if (upperIndx[0] >= (dim[0] + lb[0]))
2949  {
2950  /* addedafter = upperIndx[0] - (dim[0] + lb[0]) + 1; */
2951  /* dim[0] += addedafter; */
2952  if (pg_sub_s32_overflow(upperIndx[0], dim[0] + lb[0], &addedafter) ||
2953  pg_add_s32_overflow(addedafter, 1, &addedafter) ||
2954  pg_add_s32_overflow(dim[0], addedafter, &dim[0]))
2955  ereport(ERROR,
2956  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
2957  errmsg("array size exceeds the maximum allowed (%d)",
2958  (int) MaxArraySize)));
2959  if (addedafter > 1)
2960  newhasnulls = true; /* will insert nulls */
2961  }
2962  }
2963  else
2964  {
2965  /*
2966  * XXX currently we do not support extending multi-dimensional arrays
2967  * during assignment
2968  */
2969  for (i = 0; i < nSubscripts; i++)
2970  {
2971  if (!lowerProvided[i])
2972  lowerIndx[i] = lb[i];
2973  if (!upperProvided[i])
2974  upperIndx[i] = dim[i] + lb[i] - 1;
2975  if (lowerIndx[i] > upperIndx[i])
2976  ereport(ERROR,
2977  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
2978  errmsg("upper bound cannot be less than lower bound")));
2979  if (lowerIndx[i] < lb[i] ||
2980  upperIndx[i] >= (dim[i] + lb[i]))
2981  ereport(ERROR,
2982  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
2983  errmsg("array subscript out of range")));
2984  }
2985  /* fill any missing subscript positions with full array range */
2986  for (; i < ndim; i++)
2987  {
2988  lowerIndx[i] = lb[i];
2989  upperIndx[i] = dim[i] + lb[i] - 1;
2990  if (lowerIndx[i] > upperIndx[i])
2991  ereport(ERROR,
2992  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
2993  errmsg("upper bound cannot be less than lower bound")));
2994  }
2995  }
2996 
2997  /* Do this mainly to check for overflow */
2998  nitems = ArrayGetNItems(ndim, dim);
2999  ArrayCheckBounds(ndim, dim, lb);
3000 
3001  /*
3002  * Make sure source array has enough entries. Note we ignore the shape of
3003  * the source array and just read entries serially.
3004  */
3005  mda_get_range(ndim, span, lowerIndx, upperIndx);
3006  nsrcitems = ArrayGetNItems(ndim, span);
3007  if (nsrcitems > ArrayGetNItems(ARR_NDIM(srcArray), ARR_DIMS(srcArray)))
3008  ereport(ERROR,
3009  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
3010  errmsg("source array too small")));
3011 
3012  /*
3013  * Compute space occupied by new entries, space occupied by replaced
3014  * entries, and required space for new array.
3015  */
3016  if (newhasnulls)
3017  overheadlen = ARR_OVERHEAD_WITHNULLS(ndim, nitems);
3018  else
3019  overheadlen = ARR_OVERHEAD_NONULLS(ndim);
3020  newitemsize = array_nelems_size(ARR_DATA_PTR(srcArray), 0,
3021  ARR_NULLBITMAP(srcArray), nsrcitems,
3022  elmlen, elmbyval, elmalign);
3023  oldoverheadlen = ARR_DATA_OFFSET(array);
3024  olddatasize = ARR_SIZE(array) - oldoverheadlen;
3025  if (ndim > 1)
3026  {
3027  /*
3028  * here we do not need to cope with extension of the array; it would
3029  * be a lot more complicated if we had to do so...
3030  */
3031  olditemsize = array_slice_size(ARR_DATA_PTR(array),
3032  ARR_NULLBITMAP(array),
3033  ndim, dim, lb,
3034  lowerIndx, upperIndx,
3035  elmlen, elmbyval, elmalign);
3036  lenbefore = lenafter = 0; /* keep compiler quiet */
3037  itemsbefore = itemsafter = nolditems = 0;
3038  }
3039  else
3040  {
3041  /*
3042  * here we must allow for possibility of slice larger than orig array
3043  * and/or not adjacent to orig array subscripts
3044  */
3045  int oldlb = ARR_LBOUND(array)[0];
3046  int oldub = oldlb + ARR_DIMS(array)[0] - 1;
3047  int slicelb = Max(oldlb, lowerIndx[0]);
3048  int sliceub = Min(oldub, upperIndx[0]);
3049  char *oldarraydata = ARR_DATA_PTR(array);
3050  bits8 *oldarraybitmap = ARR_NULLBITMAP(array);
3051 
3052  /* count/size of old array entries that will go before the slice */
3053  itemsbefore = Min(slicelb, oldub + 1) - oldlb;
3054  lenbefore = array_nelems_size(oldarraydata, 0, oldarraybitmap,
3055  itemsbefore,
3056  elmlen, elmbyval, elmalign);
3057  /* count/size of old array entries that will be replaced by slice */
3058  if (slicelb > sliceub)
3059  {
3060  nolditems = 0;
3061  olditemsize = 0;
3062  }
3063  else
3064  {
3065  nolditems = sliceub - slicelb + 1;
3066  olditemsize = array_nelems_size(oldarraydata + lenbefore,
3067  itemsbefore, oldarraybitmap,
3068  nolditems,
3069  elmlen, elmbyval, elmalign);
3070  }
3071  /* count/size of old array entries that will go after the slice */
3072  itemsafter = oldub + 1 - Max(sliceub + 1, oldlb);
3073  lenafter = olddatasize - lenbefore - olditemsize;
3074  }
3075 
3076  newsize = overheadlen + olddatasize - olditemsize + newitemsize;
3077 
3078  newarray = (ArrayType *) palloc0(newsize);
3079  SET_VARSIZE(newarray, newsize);
3080  newarray->ndim = ndim;
3081  newarray->dataoffset = newhasnulls ? overheadlen : 0;
3082  newarray->elemtype = ARR_ELEMTYPE(array);
3083  memcpy(ARR_DIMS(newarray), dim, ndim * sizeof(int));
3084  memcpy(ARR_LBOUND(newarray), lb, ndim * sizeof(int));
3085 
3086  if (ndim > 1)
3087  {
3088  /*
3089  * here we do not need to cope with extension of the array; it would
3090  * be a lot more complicated if we had to do so...
3091  */
3092  array_insert_slice(newarray, array, srcArray,
3093  ndim, dim, lb,
3094  lowerIndx, upperIndx,
3095  elmlen, elmbyval, elmalign);
3096  }
3097  else
3098  {
3099  /* fill in data */
3100  memcpy((char *) newarray + overheadlen,
3101  (char *) array + oldoverheadlen,
3102  lenbefore);
3103  memcpy((char *) newarray + overheadlen + lenbefore,
3104  ARR_DATA_PTR(srcArray),
3105  newitemsize);
3106  memcpy((char *) newarray + overheadlen + lenbefore + newitemsize,
3107  (char *) array + oldoverheadlen + lenbefore + olditemsize,
3108  lenafter);
3109  /* fill in nulls bitmap if needed */
3110  if (newhasnulls)
3111  {
3112  bits8 *newnullbitmap = ARR_NULLBITMAP(newarray);
3113  bits8 *oldnullbitmap = ARR_NULLBITMAP(array);
3114 
3115  /* palloc0 above already marked any inserted positions as nulls */
3116  array_bitmap_copy(newnullbitmap, addedbefore,
3117  oldnullbitmap, 0,
3118  itemsbefore);
3119  array_bitmap_copy(newnullbitmap, lowerIndx[0] - lb[0],
3120  ARR_NULLBITMAP(srcArray), 0,
3121  nsrcitems);
3122  array_bitmap_copy(newnullbitmap, addedbefore + itemsbefore + nolditems,
3123  oldnullbitmap, itemsbefore + nolditems,
3124  itemsafter);
3125  }
3126  }
3127 
3128  return PointerGetDatum(newarray);
3129 }
void deconstruct_array(ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3612
static void array_insert_slice(ArrayType *destArray, ArrayType *origArray, ArrayType *srcArray, int ndim, int *dim, int *lb, int *st, int *endp, int typlen, bool typbyval, char typalign)
Definition: arrayfuncs.c:5151
static int array_nelems_size(char *ptr, int offset, bits8 *nullbitmap, int nitems, int typlen, bool typbyval, char typalign)
Definition: arrayfuncs.c:4895
#define Min(x, y)
Definition: c.h:991
int errdetail(const char *fmt,...)
Definition: elog.c:1205

References ARR_DATA_OFFSET, ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_HASNULL, ARR_LBOUND, ARR_NDIM, ARR_NULLBITMAP, ARR_OVERHEAD_NONULLS, ARR_OVERHEAD_WITHNULLS, ARR_SIZE, array_bitmap_copy(), array_insert_slice(), array_nelems_size(), array_slice_size(), ArrayCheckBounds(), ArrayGetNItems(), Assert(), construct_md_array(), ArrayType::dataoffset, DatumGetArrayTypeP, deconstruct_array(), ArrayType::elemtype, ereport, errcode(), errdetail(), errmsg(), ERROR, i, Max, MaxArraySize, MAXDIM, mda_get_range(), Min, ArrayType::ndim, nitems, palloc0(), pg_add_s32_overflow(), pg_sub_s32_overflow(), PointerGetDatum(), and SET_VARSIZE.

Referenced by array_subscript_assign_slice().

◆ ArrayCheckBounds()

void ArrayCheckBounds ( int  ndim,
const int *  dims,
const int *  lb 
)

Definition at line 117 of file arrayutils.c.

118 {
119  (void) ArrayCheckBoundsSafe(ndim, dims, lb, NULL);
120 }
bool ArrayCheckBoundsSafe(int ndim, const int *dims, const int *lb, struct Node *escontext)
Definition: arrayutils.c:127

References ArrayCheckBoundsSafe().

Referenced by array_cat(), array_fill_internal(), array_recv(), array_set_element(), array_set_element_expanded(), array_set_slice(), construct_md_array(), ExecEvalArrayExpr(), and makeArrayResultArr().

◆ ArrayCheckBoundsSafe()

bool ArrayCheckBoundsSafe ( int  ndim,
const int *  dims,
const int *  lb,
struct Node escontext 
)

Definition at line 127 of file arrayutils.c.

129 {
130  int i;
131 
132  for (i = 0; i < ndim; i++)
133  {
134  /* PG_USED_FOR_ASSERTS_ONLY prevents variable-isn't-read warnings */
136 
137  if (pg_add_s32_overflow(dims[i], lb[i], &sum))
138  ereturn(escontext, false,
139  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
140  errmsg("array lower bound is too large: %d",
141  lb[i])));
142  }
143 
144  return true;
145 }
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:169
#define ereturn(context, dummy_value,...)
Definition: elog.h:276

References ereturn, errcode(), errmsg(), i, pg_add_s32_overflow(), and PG_USED_FOR_ASSERTS_ONLY.

Referenced by ArrayCheckBounds().

◆ ArrayGetIntegerTypmods()

int32* ArrayGetIntegerTypmods ( ArrayType arr,
int *  n 
)

Definition at line 233 of file arrayutils.c.

234 {
235  int32 *result;
236  Datum *elem_values;
237  int i;
238 
239  if (ARR_ELEMTYPE(arr) != CSTRINGOID)
240  ereport(ERROR,
241  (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
242  errmsg("typmod array must be type cstring[]")));
243 
244  if (ARR_NDIM(arr) != 1)
245  ereport(ERROR,
246  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
247  errmsg("typmod array must be one-dimensional")));
248 
249  if (array_contains_nulls(arr))
250  ereport(ERROR,
251  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
252  errmsg("typmod array must not contain nulls")));
253 
254  deconstruct_array_builtin(arr, CSTRINGOID, &elem_values, NULL, n);
255 
256  result = (int32 *) palloc(*n * sizeof(int32));
257 
258  for (i = 0; i < *n; i++)
259  result[i] = pg_strtoint32(DatumGetCString(elem_values[i]));
260 
261  pfree(elem_values);
262 
263  return result;
264 }
bool array_contains_nulls(ArrayType *array)
Definition: arrayfuncs.c:3748
void deconstruct_array_builtin(ArrayType *array, Oid elmtype, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3678
int32 pg_strtoint32(const char *s)
Definition: numutils.c:383
static char * DatumGetCString(Datum X)
Definition: postgres.h:335

References ARR_ELEMTYPE, ARR_NDIM, array_contains_nulls(), DatumGetCString(), deconstruct_array_builtin(), ereport, errcode(), errmsg(), ERROR, i, palloc(), pfree(), and pg_strtoint32().

Referenced by anybit_typmodin(), anychar_typmodin(), anytime_typmodin(), anytimestamp_typmodin(), intervaltypmodin(), and numerictypmodin().

◆ ArrayGetNItems()

◆ ArrayGetNItemsSafe()

int ArrayGetNItemsSafe ( int  ndim,
const int *  dims,
struct Node escontext 
)

Definition at line 67 of file arrayutils.c.

68 {
69  int32 ret;
70  int i;
71 
72  if (ndim <= 0)
73  return 0;
74  ret = 1;
75  for (i = 0; i < ndim; i++)
76  {
77  int64 prod;
78 
79  /* A negative dimension implies that UB-LB overflowed ... */
80  if (dims[i] < 0)
81  ereturn(escontext, -1,
82  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
83  errmsg("array size exceeds the maximum allowed (%d)",
84  (int) MaxArraySize)));
85 
86  prod = (int64) ret * (int64) dims[i];
87 
88  ret = (int32) prod;
89  if ((int64) ret != prod)
90  ereturn(escontext, -1,
91  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
92  errmsg("array size exceeds the maximum allowed (%d)",
93  (int) MaxArraySize)));
94  }
95  Assert(ret >= 0);
96  if ((Size) ret > MaxArraySize)
97  ereturn(escontext, -1,
98  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
99  errmsg("array size exceeds the maximum allowed (%d)",
100  (int) MaxArraySize)));
101  return (int) ret;
102 }
size_t Size
Definition: c.h:592

References Assert(), ereturn, errcode(), errmsg(), i, and MaxArraySize.

Referenced by ArrayGetNItems().

◆ ArrayGetOffset()

int ArrayGetOffset ( int  n,
const int *  dim,
const int *  lb,
const int *  indx 
)

Definition at line 32 of file arrayutils.c.

33 {
34  int i,
35  scale = 1,
36  offset = 0;
37 
38  for (i = n - 1; i >= 0; i--)
39  {
40  offset += (indx[i] - lb[i]) * scale;
41  scale *= dim[i];
42  }
43  return offset;
44 }
int scale
Definition: pgbench.c:181

References i, and scale.

Referenced by array_extract_slice(), array_get_element(), array_get_element_expanded(), array_insert_slice(), array_set_element(), array_set_element_expanded(), and array_slice_size().

◆ construct_array()

ArrayType* construct_array ( Datum elems,
int  nelems,
Oid  elmtype,
int  elmlen,
bool  elmbyval,
char  elmalign 
)

Definition at line 3354 of file arrayfuncs.c.

3357 {
3358  int dims[1];
3359  int lbs[1];
3360 
3361  dims[0] = nelems;
3362  lbs[0] = 1;
3363 
3364  return construct_md_array(elems, NULL, 1, dims, lbs,
3365  elmtype, elmlen, elmbyval, elmalign);
3366 }

References construct_md_array().

Referenced by ATExecAlterColumnType(), construct_array_builtin(), enum_range_internal(), float4_accum(), float8_accum(), float8_combine(), float8_regr_accum(), float8_regr_combine(), serialize_expr_stats(), StoreAttrDefault(), and update_attstats().

◆ construct_array_builtin()

ArrayType* construct_array_builtin ( Datum elems,
int  nelems,
Oid  elmtype 
)

Definition at line 3374 of file arrayfuncs.c.

3375 {
3376  int elmlen;
3377  bool elmbyval;
3378  char elmalign;
3379 
3380  switch (elmtype)
3381  {
3382  case CHAROID:
3383  elmlen = 1;
3384  elmbyval = true;
3385  elmalign = TYPALIGN_CHAR;
3386  break;
3387 
3388  case CSTRINGOID:
3389  elmlen = -2;
3390  elmbyval = false;
3391  elmalign = TYPALIGN_CHAR;
3392  break;
3393 
3394  case FLOAT4OID:
3395  elmlen = sizeof(float4);
3396  elmbyval = true;
3397  elmalign = TYPALIGN_INT;
3398  break;
3399 
3400  case INT2OID:
3401  elmlen = sizeof(int16);
3402  elmbyval = true;
3403  elmalign = TYPALIGN_SHORT;
3404  break;
3405 
3406  case INT4OID:
3407  elmlen = sizeof(int32);
3408  elmbyval = true;
3409  elmalign = TYPALIGN_INT;
3410  break;
3411 
3412  case INT8OID:
3413  elmlen = sizeof(int64);
3414  elmbyval = FLOAT8PASSBYVAL;
3415  elmalign = TYPALIGN_DOUBLE;
3416  break;
3417 
3418  case NAMEOID:
3419  elmlen = NAMEDATALEN;
3420  elmbyval = false;
3421  elmalign = TYPALIGN_CHAR;
3422  break;
3423 
3424  case OIDOID:
3425  case REGTYPEOID:
3426  elmlen = sizeof(Oid);
3427  elmbyval = true;
3428  elmalign = TYPALIGN_INT;
3429  break;
3430 
3431  case TEXTOID:
3432  elmlen = -1;
3433  elmbyval = false;
3434  elmalign = TYPALIGN_INT;
3435  break;
3436 
3437  case TIDOID:
3438  elmlen = sizeof(ItemPointerData);
3439  elmbyval = false;
3440  elmalign = TYPALIGN_SHORT;
3441  break;
3442 
3443  default:
3444  elog(ERROR, "type %u not supported by construct_array_builtin()", elmtype);
3445  /* keep compiler quiet */
3446  elmlen = 0;
3447  elmbyval = false;
3448  elmalign = 0;
3449  }
3450 
3451  return construct_array(elems, nelems, elmtype, elmlen, elmbyval, elmalign);
3452 }
ArrayType * construct_array(Datum *elems, int nelems, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:3354
signed short int16
Definition: c.h:480
#define FLOAT8PASSBYVAL
Definition: c.h:622
float float4
Definition: c.h:616
struct ItemPointerData ItemPointerData
#define NAMEDATALEN

References construct_array(), elog, ERROR, FLOAT8PASSBYVAL, and NAMEDATALEN.

Referenced by AlterPolicy(), bt_page_print_tuples(), build_regtype_array(), convert_requires_to_datum(), CreateConstraintEntry(), CreateFunction(), CreatePolicy(), CreateStatistics(), current_schemas(), executeItemOptUnwrapTarget(), extension_config_remove(), filter_list_to_array(), get_hba_options(), GetWALBlockInfo(), gin_leafpage_items(), gin_page_opaque_info(), gist_page_opaque_info(), GUCArrayAdd(), GUCArrayDelete(), GUCArrayReset(), hash_metapage_info(), heap_tuple_infomask_flags(), hstore_akeys(), interpret_function_parameter_list(), makeMultirangeConstructors(), pg_blocking_pids(), pg_extension_config_dump(), pg_safe_snapshot_blocking_pids(), pg_settings_get_flags(), publicationListToArray(), RemoveRoleFromObjectPolicy(), serialize_expr_stats(), show_trgm(), test_rls_hooks_permissive(), test_rls_hooks_restrictive(), ts_lexize(), tsvector_to_array(), tsvector_unnest(), typenameTypeMod(), and update_attstats().

◆ construct_empty_array()

◆ construct_empty_expanded_array()

ExpandedArrayHeader* construct_empty_expanded_array ( Oid  element_type,
MemoryContext  parentcontext,
ArrayMetaState metacache 
)

Definition at line 3578 of file arrayfuncs.c.

3581 {
3582  ArrayType *array = construct_empty_array(element_type);
3583  Datum d;
3584 
3585  d = expand_array(PointerGetDatum(array), parentcontext, metacache);
3586  pfree(array);
3587  return (ExpandedArrayHeader *) DatumGetEOHP(d);
3588 }
Datum expand_array(Datum arraydatum, MemoryContext parentcontext, ArrayMetaState *metacache)
ExpandedObjectHeader * DatumGetEOHP(Datum d)
Definition: expandeddatum.c:29

References construct_empty_array(), DatumGetEOHP(), expand_array(), pfree(), and PointerGetDatum().

Referenced by fetch_array_arg_replace_nulls().

◆ construct_md_array()

ArrayType* construct_md_array ( Datum elems,
bool nulls,
int  ndims,
int *  dims,
int *  lbs,
Oid  elmtype,
int  elmlen,
bool  elmbyval,
char  elmalign 
)

Definition at line 3475 of file arrayfuncs.c.

3481 {
3482  ArrayType *result;
3483  bool hasnulls;
3484  int32 nbytes;
3485  int32 dataoffset;
3486  int i;
3487  int nelems;
3488 
3489  if (ndims < 0) /* we do allow zero-dimension arrays */
3490  ereport(ERROR,
3491  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3492  errmsg("invalid number of dimensions: %d", ndims)));
3493  if (ndims > MAXDIM)
3494  ereport(ERROR,
3495  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
3496  errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
3497  ndims, MAXDIM)));
3498 
3499  /* This checks for overflow of the array dimensions */
3500  nelems = ArrayGetNItems(ndims, dims);
3501  ArrayCheckBounds(ndims, dims, lbs);
3502 
3503  /* if ndims <= 0 or any dims[i] == 0, return empty array */
3504  if (nelems <= 0)
3505  return construct_empty_array(elmtype);
3506 
3507  /* compute required space */
3508  nbytes = 0;
3509  hasnulls = false;
3510  for (i = 0; i < nelems; i++)
3511  {
3512  if (nulls && nulls[i])
3513  {
3514  hasnulls = true;
3515  continue;
3516  }
3517  /* make sure data is not toasted */
3518  if (elmlen == -1)
3519  elems[i] = PointerGetDatum(PG_DETOAST_DATUM(elems[i]));
3520  nbytes = att_addlength_datum(nbytes, elmlen, elems[i]);
3521  nbytes = att_align_nominal(nbytes, elmalign);
3522  /* check for overflow of total request */
3523  if (!AllocSizeIsValid(nbytes))
3524  ereport(ERROR,
3525  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
3526  errmsg("array size exceeds the maximum allowed (%d)",
3527  (int) MaxAllocSize)));
3528  }
3529 
3530  /* Allocate and initialize result array */
3531  if (hasnulls)
3532  {
3533  dataoffset = ARR_OVERHEAD_WITHNULLS(ndims, nelems);
3534  nbytes += dataoffset;
3535  }
3536  else
3537  {
3538  dataoffset = 0; /* marker for no null bitmap */
3539  nbytes += ARR_OVERHEAD_NONULLS(ndims);
3540  }
3541  result = (ArrayType *) palloc0(nbytes);
3542  SET_VARSIZE(result, nbytes);
3543  result->ndim = ndims;
3544  result->dataoffset = dataoffset;
3545  result->elemtype = elmtype;
3546  memcpy(ARR_DIMS(result), dims, ndims * sizeof(int));
3547  memcpy(ARR_LBOUND(result), lbs, ndims * sizeof(int));
3548 
3549  CopyArrayEls(result,
3550  elems, nulls, nelems,
3551  elmlen, elmbyval, elmalign,
3552  false);
3553 
3554  return result;
3555 }

References AllocSizeIsValid, ARR_DIMS, ARR_LBOUND, ARR_OVERHEAD_NONULLS, ARR_OVERHEAD_WITHNULLS, ArrayCheckBounds(), ArrayGetNItems(), att_addlength_datum, att_align_nominal, construct_empty_array(), CopyArrayEls(), ArrayType::dataoffset, ArrayType::elemtype, ereport, errcode(), errmsg(), ERROR, i, MaxAllocSize, MAXDIM, ArrayType::ndim, palloc0(), PG_DETOAST_DATUM, PointerGetDatum(), and SET_VARSIZE.

Referenced by array_iterate(), array_set_element(), array_set_slice(), array_shuffle_n(), build_regexp_match_result(), build_test_info_result(), build_test_match_result(), construct_array(), ExecEvalArrayExpr(), hstore_avals(), hstore_slice_to_array(), hstore_to_array_internal(), makeMdArrayResult(), percentile_cont_multi_final_common(), percentile_disc_multi_final(), plpgsql_fulfill_promise(), and strlist_to_textarray().

◆ CopyArrayEls()

void CopyArrayEls ( ArrayType array,
Datum values,
bool nulls,
int  nitems,
int  typlen,
bool  typbyval,
char  typalign,
bool  freedata 
)

Definition at line 961 of file arrayfuncs.c.

969 {
970  char *p = ARR_DATA_PTR(array);
971  bits8 *bitmap = ARR_NULLBITMAP(array);
972  int bitval = 0;
973  int bitmask = 1;
974  int i;
975 
976  if (typbyval)
977  freedata = false;
978 
979  for (i = 0; i < nitems; i++)
980  {
981  if (nulls && nulls[i])
982  {
983  if (!bitmap) /* shouldn't happen */
984  elog(ERROR, "null array element where not supported");
985  /* bitmap bit stays 0 */
986  }
987  else
988  {
989  bitval |= bitmask;
990  p += ArrayCastAndSet(values[i], typlen, typbyval, typalign, p);
991  if (freedata)
993  }
994  if (bitmap)
995  {
996  bitmask <<= 1;
997  if (bitmask == 0x100)
998  {
999  *bitmap++ = bitval;
1000  bitval = 0;
1001  bitmask = 1;
1002  }
1003  }
1004  }
1005 
1006  if (bitmap && bitmask != 1)
1007  *bitmap = bitval;
1008 }

References ARR_DATA_PTR, ARR_NULLBITMAP, ArrayCastAndSet(), DatumGetPointer(), elog, ERROR, i, nitems, pfree(), typalign, and values.

Referenced by array_in(), array_map(), array_recv(), array_replace_internal(), construct_md_array(), and EA_flatten_into().

◆ DatumGetAnyArrayP()

AnyArrayType* DatumGetAnyArrayP ( Datum  d)

Definition at line 401 of file array_expanded.c.

402 {
403  ExpandedArrayHeader *eah;
404 
405  /*
406  * If it's an expanded array (RW or RO), return the header pointer.
407  */
409  {
410  eah = (ExpandedArrayHeader *) DatumGetEOHP(d);
411  Assert(eah->ea_magic == EA_MAGIC);
412  return (AnyArrayType *) eah;
413  }
414 
415  /* Else do regular detoasting as needed */
416  return (AnyArrayType *) PG_DETOAST_DATUM(d);
417 }
#define EA_MAGIC
Definition: array.h:113

References Assert(), DatumGetEOHP(), DatumGetPointer(), EA_MAGIC, ExpandedArrayHeader::ea_magic, PG_DETOAST_DATUM, and VARATT_IS_EXTERNAL_EXPANDED.

Referenced by array_map().

◆ DatumGetExpandedArray()

ExpandedArrayHeader* DatumGetExpandedArray ( Datum  d)

Definition at line 352 of file array_expanded.c.

353 {
354  /* If it's a writable expanded array already, just return it */
356  {
358 
359  Assert(eah->ea_magic == EA_MAGIC);
360  return eah;
361  }
362 
363  /* Else expand the hard way */
364  d = expand_array(d, CurrentMemoryContext, NULL);
365  return (ExpandedArrayHeader *) DatumGetEOHP(d);
366 }
MemoryContext CurrentMemoryContext
Definition: mcxt.c:131
#define VARATT_IS_EXTERNAL_EXPANDED_RW(PTR)
Definition: varatt.h:296

References Assert(), CurrentMemoryContext, DatumGetEOHP(), DatumGetPointer(), EA_MAGIC, ExpandedArrayHeader::ea_magic, expand_array(), and VARATT_IS_EXTERNAL_EXPANDED_RW.

Referenced by array_set_element_expanded(), and statext_expressions_load().

◆ DatumGetExpandedArrayX()

ExpandedArrayHeader* DatumGetExpandedArrayX ( Datum  d,
ArrayMetaState metacache 
)

Definition at line 372 of file array_expanded.c.

373 {
374  /* If it's a writable expanded array already, just return it */
376  {
378 
379  Assert(eah->ea_magic == EA_MAGIC);
380  /* Update cache if provided */
381  if (metacache)
382  {
383  metacache->element_type = eah->element_type;
384  metacache->typlen = eah->typlen;
385  metacache->typbyval = eah->typbyval;
386  metacache->typalign = eah->typalign;
387  }
388  return eah;
389  }
390 
391  /* Else expand using caller's cache if any */
392  d = expand_array(d, CurrentMemoryContext, metacache);
393  return (ExpandedArrayHeader *) DatumGetEOHP(d);
394 }

References Assert(), CurrentMemoryContext, DatumGetEOHP(), DatumGetPointer(), EA_MAGIC, ExpandedArrayHeader::ea_magic, ExpandedArrayHeader::element_type, ArrayMetaState::element_type, expand_array(), ExpandedArrayHeader::typalign, ArrayMetaState::typalign, ExpandedArrayHeader::typbyval, ArrayMetaState::typbyval, ExpandedArrayHeader::typlen, ArrayMetaState::typlen, and VARATT_IS_EXTERNAL_EXPANDED_RW.

◆ deconstruct_array()

void deconstruct_array ( ArrayType array,
Oid  elmtype,
int  elmlen,
bool  elmbyval,
char  elmalign,
Datum **  elemsp,
bool **  nullsp,
int *  nelemsp 
)

Definition at line 3612 of file arrayfuncs.c.

3616 {
3617  Datum *elems;
3618  bool *nulls;
3619  int nelems;
3620  char *p;
3621  bits8 *bitmap;
3622  int bitmask;
3623  int i;
3624 
3625  Assert(ARR_ELEMTYPE(array) == elmtype);
3626 
3627  nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
3628  *elemsp = elems = (Datum *) palloc(nelems * sizeof(Datum));
3629  if (nullsp)
3630  *nullsp = nulls = (bool *) palloc0(nelems * sizeof(bool));
3631  else
3632  nulls = NULL;
3633  *nelemsp = nelems;
3634 
3635  p = ARR_DATA_PTR(array);
3636  bitmap = ARR_NULLBITMAP(array);
3637  bitmask = 1;
3638 
3639  for (i = 0; i < nelems; i++)
3640  {
3641  /* Get source element, checking for NULL */
3642  if (bitmap && (*bitmap & bitmask) == 0)
3643  {
3644  elems[i] = (Datum) 0;
3645  if (nulls)
3646  nulls[i] = true;
3647  else
3648  ereport(ERROR,
3649  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
3650  errmsg("null array element not allowed in this context")));
3651  }
3652  else
3653  {
3654  elems[i] = fetch_att(p, elmbyval, elmlen);
3655  p = att_addlength_pointer(p, elmlen, p);
3656  p = (char *) att_align_nominal(p, elmalign);
3657  }
3658 
3659  /* advance bitmap pointer if any */
3660  if (bitmap)
3661  {
3662  bitmask <<= 1;
3663  if (bitmask == 0x100)
3664  {
3665  bitmap++;
3666  bitmask = 1;
3667  }
3668  }
3669  }
3670 }

References ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_NDIM, ARR_NULLBITMAP, ArrayGetNItems(), Assert(), att_addlength_pointer, att_align_nominal, ereport, errcode(), errmsg(), ERROR, fetch_att(), i, palloc(), and palloc0().

Referenced by _bt_preprocess_array_keys(), array_contain_compare(), array_set_slice(), array_shuffle_n(), array_to_json_internal(), array_to_jsonb_internal(), arrayconst_startup_fn(), compute_array_stats(), deconstruct_array_builtin(), deconstruct_expanded_array(), ExecIndexEvalArrayKeys(), extract_variadic_args(), get_attstatsslot(), ginarrayextract(), gincost_scalararrayopexpr(), ginqueryarrayextract(), map_sql_value_to_xml_value(), match_clause_to_partition_key(), mcelem_array_selec(), mcv_get_match_bitmap(), multirange_constructor2(), pg_get_publication_tables(), plperl_ref_from_pg_array(), satisfies_hash_partition(), scalararraysel(), and text_format().

◆ deconstruct_array_builtin()

void deconstruct_array_builtin ( ArrayType array,
Oid  elmtype,
Datum **  elemsp,
bool **  nullsp,
int *  nelemsp 
)

Definition at line 3678 of file arrayfuncs.c.

3681 {
3682  int elmlen;
3683  bool elmbyval;
3684  char elmalign;
3685 
3686  switch (elmtype)
3687  {
3688  case CHAROID:
3689  elmlen = 1;
3690  elmbyval = true;
3691  elmalign = TYPALIGN_CHAR;
3692  break;
3693 
3694  case CSTRINGOID:
3695  elmlen = -2;
3696  elmbyval = false;
3697  elmalign = TYPALIGN_CHAR;
3698  break;
3699 
3700  case FLOAT8OID:
3701  elmlen = sizeof(float8);
3702  elmbyval = FLOAT8PASSBYVAL;
3703  elmalign = TYPALIGN_DOUBLE;
3704  break;
3705 
3706  case INT2OID:
3707  elmlen = sizeof(int16);
3708  elmbyval = true;
3709  elmalign = TYPALIGN_SHORT;
3710  break;
3711 
3712  case OIDOID:
3713  elmlen = sizeof(Oid);
3714  elmbyval = true;
3715  elmalign = TYPALIGN_INT;
3716  break;
3717 
3718  case TEXTOID:
3719  elmlen = -1;
3720  elmbyval = false;
3721  elmalign = TYPALIGN_INT;
3722  break;
3723 
3724  case TIDOID:
3725  elmlen = sizeof(ItemPointerData);
3726  elmbyval = false;
3727  elmalign = TYPALIGN_SHORT;
3728  break;
3729 
3730  default:
3731  elog(ERROR, "type %u not supported by deconstruct_array_builtin()", elmtype);
3732  /* keep compiler quiet */
3733  elmlen = 0;
3734  elmbyval = false;
3735  elmalign = 0;
3736  }
3737 
3738  deconstruct_array(array, elmtype, elmlen, elmbyval, elmalign, elemsp, nullsp, nelemsp);
3739 }
double float8
Definition: c.h:617

References deconstruct_array(), elog, ERROR, and FLOAT8PASSBYVAL.

Referenced by array_to_tsvector(), ArrayGetIntegerTypmods(), binary_upgrade_create_empty_extension(), build_function_result_tupdesc_d(), DecodeTextArrayToBitmapset(), decompile_column_index_array(), extension_config_remove(), generateClonedIndexStmt(), get_func_arg_info(), get_func_input_arg_names(), get_func_result_name(), get_jsonb_path_all(), get_path_all(), get_reloptions(), ghstore_consistent(), gin_extract_hstore_query(), gin_extract_jsonb_query(), hstore_from_array(), hstore_from_arrays(), hstore_slice_to_array(), hstoreArrayToPairs(), json_object(), json_object_two_arg(), jsonb_delete_array(), jsonb_delete_path(), jsonb_exists_all(), jsonb_exists_any(), jsonb_insert(), jsonb_object(), jsonb_object_two_arg(), jsonb_set(), oid_array_to_list(), parse_key_value_arrays(), parseRelOptionsInternal(), percentile_cont_multi_final_common(), percentile_disc_multi_final(), pg_get_constraintdef_worker(), pg_get_object_address(), pg_logical_slot_get_changes_guts(), textarray_to_stringlist(), textarray_to_strvaluelist(), TidListEval(), transformRelOptions(), tsvector_delete_arr(), tsvector_filter(), tsvector_setweight_by_filter(), untransformRelOptions(), and worker_spi_launch().

◆ deconstruct_expanded_array()

void deconstruct_expanded_array ( ExpandedArrayHeader eah)

Definition at line 424 of file array_expanded.c.

425 {
426  if (eah->dvalues == NULL)
427  {
429  Datum *dvalues;
430  bool *dnulls;
431  int nelems;
432 
433  dnulls = NULL;
435  eah->element_type,
436  eah->typlen, eah->typbyval, eah->typalign,
437  &dvalues,
438  ARR_HASNULL(eah->fvalue) ? &dnulls : NULL,
439  &nelems);
440 
441  /*
442  * Update header only after successful completion of this step. If
443  * deconstruct_array fails partway through, worst consequence is some
444  * leaked memory in the object's context. If the caller fails at a
445  * later point, that's fine, since the deconstructed representation is
446  * valid anyhow.
447  */
448  eah->dvalues = dvalues;
449  eah->dnulls = dnulls;
450  eah->dvalueslen = eah->nelems = nelems;
451  MemoryContextSwitchTo(oldcxt);
452  }
453 }
ExpandedObjectHeader hdr
Definition: array.h:118
Datum * dvalues
Definition: array.h:146
ArrayType * fvalue
Definition: array.h:165
MemoryContext eoh_context

References ARR_HASNULL, deconstruct_array(), ExpandedArrayHeader::dnulls, ExpandedArrayHeader::dvalues, ExpandedArrayHeader::dvalueslen, ExpandedArrayHeader::element_type, ExpandedObjectHeader::eoh_context, ExpandedArrayHeader::fvalue, ExpandedArrayHeader::hdr, MemoryContextSwitchTo(), ExpandedArrayHeader::nelems, ExpandedArrayHeader::typalign, ExpandedArrayHeader::typbyval, and ExpandedArrayHeader::typlen.

Referenced by array_contain_compare(), array_get_element_expanded(), array_set_element_expanded(), and statext_expressions_load().

◆ expand_array()

Datum expand_array ( Datum  arraydatum,
MemoryContext  parentcontext,
ArrayMetaState metacache 
)

Definition at line 50 of file array_expanded.c.

52 {
53  ArrayType *array;
55  MemoryContext objcxt;
56  MemoryContext oldcxt;
57  ArrayMetaState fakecache;
58 
59  /*
60  * Allocate private context for expanded object. We start by assuming
61  * that the array won't be very large; but if it does grow a lot, don't
62  * constrain aset.c's large-context behavior.
63  */
64  objcxt = AllocSetContextCreate(parentcontext,
65  "expanded array",
67 
68  /* Set up expanded array header */
69  eah = (ExpandedArrayHeader *)
70  MemoryContextAlloc(objcxt, sizeof(ExpandedArrayHeader));
71 
72  EOH_init_header(&eah->hdr, &EA_methods, objcxt);
73  eah->ea_magic = EA_MAGIC;
74 
75  /* If the source is an expanded array, we may be able to optimize */
77  {
78  ExpandedArrayHeader *oldeah = (ExpandedArrayHeader *) DatumGetEOHP(arraydatum);
79 
80  Assert(oldeah->ea_magic == EA_MAGIC);
81 
82  /*
83  * Update caller's cache if provided; we don't need it this time, but
84  * next call might be for a non-expanded source array. Furthermore,
85  * if the caller didn't provide a cache area, use some local storage
86  * to cache anyway, thereby avoiding a catalog lookup in the case
87  * where we fall through to the flat-copy code path.
88  */
89  if (metacache == NULL)
90  metacache = &fakecache;
91  metacache->element_type = oldeah->element_type;
92  metacache->typlen = oldeah->typlen;
93  metacache->typbyval = oldeah->typbyval;
94  metacache->typalign = oldeah->typalign;
95 
96  /*
97  * If element type is pass-by-value and we have a Datum-array
98  * representation, just copy the source's metadata and Datum/isnull
99  * arrays. The original flat array, if present at all, adds no
100  * additional information so we need not copy it.
101  */
102  if (oldeah->typbyval && oldeah->dvalues != NULL)
103  {
104  copy_byval_expanded_array(eah, oldeah);
105  /* return a R/W pointer to the expanded array */
106  return EOHPGetRWDatum(&eah->hdr);
107  }
108 
109  /*
110  * Otherwise, either we have only a flat representation or the
111  * elements are pass-by-reference. In either case, the best thing
112  * seems to be to copy the source as a flat representation and then
113  * deconstruct that later if necessary. For the pass-by-ref case, we
114  * could perhaps save some cycles with custom code that generates the
115  * deconstructed representation in parallel with copying the values,
116  * but it would be a lot of extra code for fairly marginal gain. So,
117  * fall through into the flat-source code path.
118  */
119  }
120 
121  /*
122  * Detoast and copy source array into private context, as a flat array.
123  *
124  * Note that this coding risks leaking some memory in the private context
125  * if we have to fetch data from a TOAST table; however, experimentation
126  * says that the leak is minimal. Doing it this way saves a copy step,
127  * which seems worthwhile, especially if the array is large enough to need
128  * external storage.
129  */
130  oldcxt = MemoryContextSwitchTo(objcxt);
131  array = DatumGetArrayTypePCopy(arraydatum);
132  MemoryContextSwitchTo(oldcxt);
133 
134  eah->ndims = ARR_NDIM(array);
135  /* note these pointers point into the fvalue header! */
136  eah->dims = ARR_DIMS(array);
137  eah->lbound = ARR_LBOUND(array);
138 
139  /* Save array's element-type data for possible use later */
140  eah->element_type = ARR_ELEMTYPE(array);
141  if (metacache && metacache->element_type == eah->element_type)
142  {
143  /* We have a valid cache of representational data */
144  eah->typlen = metacache->typlen;
145  eah->typbyval = metacache->typbyval;
146  eah->typalign = metacache->typalign;
147  }
148  else
149  {
150  /* No, so look it up */
152  &eah->typlen,
153  &eah->typbyval,
154  &eah->typalign);
155  /* Update cache if provided */
156  if (metacache)
157  {
158  metacache->element_type = eah->element_type;
159  metacache->typlen = eah->typlen;
160  metacache->typbyval = eah->typbyval;
161  metacache->typalign = eah->typalign;
162  }
163  }
164 
165  /* we don't make a deconstructed representation now */
166  eah->dvalues = NULL;
167  eah->dnulls = NULL;
168  eah->dvalueslen = 0;
169  eah->nelems = 0;
170  eah->flat_size = 0;
171 
172  /* remember we have a flat representation */
173  eah->fvalue = array;
174  eah->fstartptr = ARR_DATA_PTR(array);
175  eah->fendptr = ((char *) array) + ARR_SIZE(array);
176 
177  /* return a R/W pointer to the expanded array */
178  return EOHPGetRWDatum(&eah->hdr);
179 }
#define DatumGetArrayTypePCopy(X)
Definition: array.h:262
static void copy_byval_expanded_array(ExpandedArrayHeader *eah, ExpandedArrayHeader *oldeah)
static const ExpandedObjectMethods EA_methods
void EOH_init_header(ExpandedObjectHeader *eohptr, const ExpandedObjectMethods *methods, MemoryContext obj_context)
Definition: expandeddatum.c:48
static Datum EOHPGetRWDatum(const struct ExpandedObjectHeader *eohptr)
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1168
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_START_SMALL_SIZES
Definition: memutils.h:170
char * fstartptr
Definition: array.h:166
char * fendptr
Definition: array.h:167

References ALLOCSET_START_SMALL_SIZES, AllocSetContextCreate, ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_LBOUND, ARR_NDIM, ARR_SIZE, Assert(), copy_byval_expanded_array(), DatumGetArrayTypePCopy, DatumGetEOHP(), DatumGetPointer(), ExpandedArrayHeader::dims, ExpandedArrayHeader::dnulls, ExpandedArrayHeader::dvalues, ExpandedArrayHeader::dvalueslen, EA_MAGIC, ExpandedArrayHeader::ea_magic, EA_methods, ExpandedArrayHeader::element_type, ArrayMetaState::element_type, EOH_init_header(), EOHPGetRWDatum(), ExpandedArrayHeader::fendptr, ExpandedArrayHeader::flat_size, ExpandedArrayHeader::fstartptr, ExpandedArrayHeader::fvalue, get_typlenbyvalalign(), ExpandedArrayHeader::hdr, ExpandedArrayHeader::lbound, MemoryContextAlloc(), MemoryContextSwitchTo(), ExpandedArrayHeader::ndims, ExpandedArrayHeader::nelems, ExpandedArrayHeader::typalign, ArrayMetaState::typalign, ExpandedArrayHeader::typbyval, ArrayMetaState::typbyval, ExpandedArrayHeader::typlen, ArrayMetaState::typlen, and VARATT_IS_EXTERNAL_EXPANDED.

Referenced by construct_empty_expanded_array(), DatumGetExpandedArray(), DatumGetExpandedArrayX(), exec_assign_value(), and plpgsql_exec_function().

◆ initArrayResult()

ArrayBuildState* initArrayResult ( Oid  element_type,
MemoryContext  rcontext,
bool  subcontext 
)

Definition at line 5274 of file arrayfuncs.c.

5275 {
5276  /*
5277  * When using a subcontext, we can afford to start with a somewhat larger
5278  * initial array size. Without subcontexts, we'd better hope that most of
5279  * the states stay small ...
5280  */
5281  return initArrayResultWithSize(element_type, rcontext, subcontext,
5282  subcontext ? 64 : 8);
5283 }
ArrayBuildState * initArrayResultWithSize(Oid element_type, MemoryContext rcontext, bool subcontext, int initsize)
Definition: arrayfuncs.c:5291

References initArrayResultWithSize().

Referenced by accumArrayResult(), array_agg_transfn(), array_positions(), array_to_datum_internal(), daitch_mokotoff(), initArrayResultAny(), multirange_agg_transfn(), PLySequence_ToArray_recurse(), populate_array(), range_agg_transfn(), tuple_data_split_internal(), and xpath().

◆ initArrayResultAny()

ArrayBuildStateAny* initArrayResultAny ( Oid  input_type,
MemoryContext  rcontext,
bool  subcontext 
)

Definition at line 5763 of file arrayfuncs.c.

5764 {
5765  ArrayBuildStateAny *astate;
5766  Oid element_type = get_element_type(input_type);
5767 
5768  if (OidIsValid(element_type))
5769  {
5770  /* Array case */
5771  ArrayBuildStateArr *arraystate;
5772 
5773  arraystate = initArrayResultArr(input_type, InvalidOid, rcontext, subcontext);
5774  astate = (ArrayBuildStateAny *)
5775  MemoryContextAlloc(arraystate->mcontext,
5776  sizeof(ArrayBuildStateAny));
5777  astate->scalarstate = NULL;
5778  astate->arraystate = arraystate;
5779  }
5780  else
5781  {
5782  /* Scalar case */
5783  ArrayBuildState *scalarstate;
5784 
5785  /* Let's just check that we have a type that can be put into arrays */
5786  Assert(OidIsValid(get_array_type(input_type)));
5787 
5788  scalarstate = initArrayResult(input_type, rcontext, subcontext);
5789  astate = (ArrayBuildStateAny *)
5790  MemoryContextAlloc(scalarstate->mcontext,
5791  sizeof(ArrayBuildStateAny));
5792  astate->scalarstate = scalarstate;
5793  astate->arraystate = NULL;
5794  }
5795 
5796  return astate;
5797 }
#define OidIsValid(objectId)
Definition: c.h:762
Oid get_element_type(Oid typid)
Definition: lsyscache.c:2715
Oid get_array_type(Oid typid)
Definition: lsyscache.c:2743

References ArrayBuildStateAny::arraystate, Assert(), get_array_type(), get_element_type(), initArrayResult(), initArrayResultArr(), InvalidOid, ArrayBuildState::mcontext, ArrayBuildStateArr::mcontext, MemoryContextAlloc(), OidIsValid, and ArrayBuildStateAny::scalarstate.

Referenced by accumArrayResultAny(), ExecScanSubPlan(), and ExecSetParamPlan().

◆ initArrayResultArr()

ArrayBuildStateArr* initArrayResultArr ( Oid  array_type,
Oid  element_type,
MemoryContext  rcontext,
bool  subcontext 
)

Definition at line 5485 of file arrayfuncs.c.

5487 {
5488  ArrayBuildStateArr *astate;
5489  MemoryContext arr_context = rcontext; /* by default use the parent ctx */
5490 
5491  /* Lookup element type, unless element_type already provided */
5492  if (!OidIsValid(element_type))
5493  {
5494  element_type = get_element_type(array_type);
5495 
5496  if (!OidIsValid(element_type))
5497  ereport(ERROR,
5498  (errcode(ERRCODE_DATATYPE_MISMATCH),
5499  errmsg("data type %s is not an array type",
5500  format_type_be(array_type))));
5501  }
5502 
5503  /* Make a temporary context to hold all the junk */
5504  if (subcontext)
5505  arr_context = AllocSetContextCreate(rcontext,
5506  "accumArrayResultArr",
5508 
5509  /* Note we initialize all fields to zero */
5510  astate = (ArrayBuildStateArr *)
5511  MemoryContextAllocZero(arr_context, sizeof(ArrayBuildStateArr));
5512  astate->mcontext = arr_context;
5513  astate->private_cxt = subcontext;
5514 
5515  /* Save relevant datatype information */
5516  astate->array_type = array_type;
5517  astate->element_type = element_type;
5518 
5519  return astate;
5520 }
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1202
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:153
bool private_cxt
Definition: array.h:219

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, ArrayBuildStateArr::array_type, ArrayBuildStateArr::element_type, ereport, errcode(), errmsg(), ERROR, format_type_be(), get_element_type(), ArrayBuildStateArr::mcontext, MemoryContextAllocZero(), OidIsValid, and ArrayBuildStateArr::private_cxt.

Referenced by accumArrayResultArr(), array_agg_array_combine(), array_agg_array_deserialize(), array_agg_array_transfn(), and initArrayResultAny().

◆ initArrayResultWithSize()

ArrayBuildState* initArrayResultWithSize ( Oid  element_type,
MemoryContext  rcontext,
bool  subcontext,
int  initsize 
)

Definition at line 5291 of file arrayfuncs.c.

5293 {
5294  ArrayBuildState *astate;
5295  MemoryContext arr_context = rcontext;
5296 
5297  /* Make a temporary context to hold all the junk */
5298  if (subcontext)
5299  arr_context = AllocSetContextCreate(rcontext,
5300  "accumArrayResult",
5302 
5303  astate = (ArrayBuildState *)
5304  MemoryContextAlloc(arr_context, sizeof(ArrayBuildState));
5305  astate->mcontext = arr_context;
5306  astate->private_cxt = subcontext;
5307  astate->alen = initsize;
5308  astate->dvalues = (Datum *)
5309  MemoryContextAlloc(arr_context, astate->alen * sizeof(Datum));
5310  astate->dnulls = (bool *)
5311  MemoryContextAlloc(arr_context, astate->alen * sizeof(bool));
5312  astate->nelems = 0;
5313  astate->element_type = element_type;
5314  get_typlenbyvalalign(element_type,
5315  &astate->typlen,
5316  &astate->typbyval,
5317  &astate->typalign);
5318 
5319  return astate;
5320 }
bool private_cxt
Definition: array.h:198
char typalign
Definition: array.h:197

References ArrayBuildState::alen, ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, ArrayBuildState::dnulls, ArrayBuildState::dvalues, ArrayBuildState::element_type, get_typlenbyvalalign(), ArrayBuildState::mcontext, MemoryContextAlloc(), ArrayBuildState::nelems, ArrayBuildState::private_cxt, ArrayBuildState::typalign, ArrayBuildState::typbyval, and ArrayBuildState::typlen.

Referenced by array_agg_combine(), array_agg_deserialize(), and initArrayResult().

◆ makeArrayResult()

Datum makeArrayResult ( ArrayBuildState astate,
MemoryContext  rcontext 
)

Definition at line 5401 of file arrayfuncs.c.

5403 {
5404  int ndims;
5405  int dims[1];
5406  int lbs[1];
5407 
5408  /* If no elements were presented, we want to create an empty array */
5409  ndims = (astate->nelems > 0) ? 1 : 0;
5410  dims[0] = astate->nelems;
5411  lbs[0] = 1;
5412 
5413  return makeMdArrayResult(astate, ndims, dims, lbs, rcontext,
5414  astate->private_cxt);
5415 }
Datum makeMdArrayResult(ArrayBuildState *astate, int ndims, int *dims, int *lbs, MemoryContext rcontext, bool release)
Definition: arrayfuncs.c:5433

References makeMdArrayResult(), ArrayBuildState::nelems, and ArrayBuildState::private_cxt.

Referenced by array_positions(), brin_minmax_multi_summary_out(), daitch_mokotoff(), dblink_get_connections(), optionListToArray(), parse_ident(), pg_get_statisticsobjdef_expressions(), pg_stats_ext_mcvlist_items(), regexp_split_to_array(), serialize_expr_stats(), text_to_array(), transformRelOptions(), tuple_data_split_internal(), and xpath().

◆ makeArrayResultAny()

Datum makeArrayResultAny ( ArrayBuildStateAny astate,
MemoryContext  rcontext,
bool  release 
)

Definition at line 5836 of file arrayfuncs.c.

5838 {
5839  Datum result;
5840 
5841  if (astate->scalarstate)
5842  {
5843  /* Must use makeMdArrayResult to support "release" parameter */
5844  int ndims;
5845  int dims[1];
5846  int lbs[1];
5847 
5848  /* If no elements were presented, we want to create an empty array */
5849  ndims = (astate->scalarstate->nelems > 0) ? 1 : 0;
5850  dims[0] = astate->scalarstate->nelems;
5851  lbs[0] = 1;
5852 
5853  result = makeMdArrayResult(astate->scalarstate, ndims, dims, lbs,
5854  rcontext, release);
5855  }
5856  else
5857  {
5858  result = makeArrayResultArr(astate->arraystate,
5859  rcontext, release);
5860  }
5861  return result;
5862 }
Datum makeArrayResultArr(ArrayBuildStateArr *astate, MemoryContext rcontext, bool release)
Definition: arrayfuncs.c:5684

References ArrayBuildStateAny::arraystate, makeArrayResultArr(), makeMdArrayResult(), ArrayBuildState::nelems, and ArrayBuildStateAny::scalarstate.

Referenced by ExecScanSubPlan(), and ExecSetParamPlan().

◆ makeArrayResultArr()

Datum makeArrayResultArr ( ArrayBuildStateArr astate,
MemoryContext  rcontext,
bool  release 
)

Definition at line 5684 of file arrayfuncs.c.

5687 {
5688  ArrayType *result;
5689  MemoryContext oldcontext;
5690 
5691  /* Build the final array result in rcontext */
5692  oldcontext = MemoryContextSwitchTo(rcontext);
5693 
5694  if (astate->ndims == 0)
5695  {
5696  /* No inputs, return empty array */
5697  result = construct_empty_array(astate->element_type);
5698  }
5699  else
5700  {
5701  int dataoffset,
5702  nbytes;
5703 
5704  /* Check for overflow of the array dimensions */
5705  (void) ArrayGetNItems(astate->ndims, astate->dims);
5706  ArrayCheckBounds(astate->ndims, astate->dims, astate->lbs);
5707 
5708  /* Compute required space */
5709  nbytes = astate->nbytes;
5710  if (astate->nullbitmap != NULL)
5711  {
5712  dataoffset = ARR_OVERHEAD_WITHNULLS(astate->ndims, astate->nitems);
5713  nbytes += dataoffset;
5714  }
5715  else
5716  {
5717  dataoffset = 0;
5718  nbytes += ARR_OVERHEAD_NONULLS(astate->ndims);
5719  }
5720 
5721  result = (ArrayType *) palloc0(nbytes);
5722  SET_VARSIZE(result, nbytes);
5723  result->ndim = astate->ndims;
5724  result->dataoffset = dataoffset;
5725  result->elemtype = astate->element_type;
5726 
5727  memcpy(ARR_DIMS(result), astate->dims, astate->ndims * sizeof(int));
5728  memcpy(ARR_LBOUND(result), astate->lbs, astate->ndims * sizeof(int));
5729  memcpy(ARR_DATA_PTR(result), astate->data, astate->nbytes);
5730 
5731  if (astate->nullbitmap != NULL)
5732  array_bitmap_copy(ARR_NULLBITMAP(result), 0,
5733  astate->nullbitmap, 0,
5734  astate->nitems);
5735  }
5736 
5737  MemoryContextSwitchTo(oldcontext);
5738 
5739  /* Clean up all the junk */
5740  if (release)
5741  {
5742  Assert(astate->private_cxt);
5743  MemoryContextDelete(astate->mcontext);
5744  }
5745 
5746  return PointerGetDatum(result);
5747 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:442

References ARR_DATA_PTR, ARR_DIMS, ARR_LBOUND, ARR_NULLBITMAP, ARR_OVERHEAD_NONULLS, ARR_OVERHEAD_WITHNULLS, array_bitmap_copy(), ArrayCheckBounds(), ArrayGetNItems(), Assert(), construct_empty_array(), ArrayBuildStateArr::data, ArrayType::dataoffset, ArrayBuildStateArr::dims, ArrayBuildStateArr::element_type, ArrayType::elemtype, ArrayBuildStateArr::lbs, ArrayBuildStateArr::mcontext, MemoryContextDelete(), MemoryContextSwitchTo(), ArrayBuildStateArr::nbytes, ArrayType::ndim, ArrayBuildStateArr::ndims, ArrayBuildStateArr::nitems, ArrayBuildStateArr::nullbitmap, palloc0(), PointerGetDatum(), ArrayBuildStateArr::private_cxt, and SET_VARSIZE.

Referenced by array_agg_array_finalfn(), and makeArrayResultAny().

◆ makeMdArrayResult()

Datum makeMdArrayResult ( ArrayBuildState astate,
int  ndims,
int *  dims,
int *  lbs,
MemoryContext  rcontext,
bool  release 
)

Definition at line 5433 of file arrayfuncs.c.

5439 {
5440  ArrayType *result;
5441  MemoryContext oldcontext;
5442 
5443  /* Build the final array result in rcontext */
5444  oldcontext = MemoryContextSwitchTo(rcontext);
5445 
5446  result = construct_md_array(astate->dvalues,
5447  astate->dnulls,
5448  ndims,
5449  dims,
5450  lbs,
5451  astate->element_type,
5452  astate->typlen,
5453  astate->typbyval,
5454  astate->typalign);
5455 
5456  MemoryContextSwitchTo(oldcontext);
5457 
5458  /* Clean up all the junk */
5459  if (release)
5460  {
5461  Assert(astate->private_cxt);
5462  MemoryContextDelete(astate->mcontext);
5463  }
5464 
5465  return PointerGetDatum(result);
5466 }

References Assert(), construct_md_array(), ArrayBuildState::dnulls, ArrayBuildState::dvalues, ArrayBuildState::element_type, ArrayBuildState::mcontext, MemoryContextDelete(), MemoryContextSwitchTo(), PointerGetDatum(), ArrayBuildState::private_cxt, ArrayBuildState::typalign, ArrayBuildState::typbyval, and ArrayBuildState::typlen.

Referenced by array_agg_finalfn(), makeArrayResult(), makeArrayResultAny(), plperl_array_to_datum(), PLySequence_ToArray(), and populate_array().

◆ mda_get_offset_values()

void mda_get_offset_values ( int  n,
int *  dist,
const int *  prod,
const int *  span 
)

Definition at line 183 of file arrayutils.c.

184 {
185  int i,
186  j;
187 
188  dist[n - 1] = 0;
189  for (j = n - 2; j >= 0; j--)
190  {
191  dist[j] = prod[j] - 1;
192  for (i = j + 1; i < n; i++)
193  dist[j] -= (span[i] - 1) * prod[i];
194  }
195 }
int j
Definition: isn.c:74

References i, and j.

Referenced by array_extract_slice(), array_insert_slice(), and array_slice_size().

◆ mda_get_prod()

void mda_get_prod ( int  n,
const int *  range,
int *  prod 
)

Definition at line 167 of file arrayutils.c.

168 {
169  int i;
170 
171  prod[n - 1] = 1;
172  for (i = n - 2; i >= 0; i--)
173  prod[i] = prod[i + 1] * range[i + 1];
174 }
static struct cvec * range(struct vars *v, chr a, chr b, int cases)
Definition: regc_locale.c:412

References i, and range().

Referenced by array_extract_slice(), array_insert_slice(), and array_slice_size().

◆ mda_get_range()

void mda_get_range ( int  n,
int *  span,
const int *  st,
const int *  endp 
)

Definition at line 153 of file arrayutils.c.

154 {
155  int i;
156 
157  for (i = 0; i < n; i++)
158  span[i] = endp[i] - st[i] + 1;
159 }

References i.

Referenced by array_extract_slice(), array_get_slice(), array_insert_slice(), array_set_slice(), and array_slice_size().

◆ mda_next_tuple()

int mda_next_tuple ( int  n,
int *  curr,
const int *  span 
)

Definition at line 208 of file arrayutils.c.

209 {
210  int i;
211 
212  if (n <= 0)
213  return -1;
214 
215  curr[n - 1] = (curr[n - 1] + 1) % span[n - 1];
216  for (i = n - 1; i && curr[i] == 0; i--)
217  curr[i - 1] = (curr[i - 1] + 1) % span[i - 1];
218 
219  if (i)
220  return i;
221  if (curr[0])
222  return 0;
223 
224  return -1;
225 }

References i.

Referenced by array_extract_slice(), array_insert_slice(), and array_slice_size().

Variable Documentation

◆ Array_nulls

PGDLLIMPORT bool Array_nulls
extern

Definition at line 43 of file arrayfuncs.c.

Referenced by ReadArrayToken().