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:502

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:800
#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 5332 of file arrayfuncs.c.

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

5813 {
5814  if (astate == NULL)
5815  astate = initArrayResultAny(input_type, rcontext, true);
5816 
5817  if (astate->scalarstate)
5818  (void) accumArrayResult(astate->scalarstate,
5819  dvalue, disnull,
5820  input_type, rcontext);
5821  else
5822  (void) accumArrayResultArr(astate->arraystate,
5823  dvalue, disnull,
5824  input_type, rcontext);
5825 
5826  return astate;
5827 }
ArrayBuildState * accumArrayResult(ArrayBuildState *astate, Datum dvalue, bool disnull, Oid element_type, MemoryContext rcontext)
Definition: arrayfuncs.c:5332
ArrayBuildStateAny * initArrayResultAny(Oid input_type, MemoryContext rcontext, bool subcontext)
Definition: arrayfuncs.c:5764
ArrayBuildStateArr * accumArrayResultArr(ArrayBuildStateArr *astate, Datum dvalue, bool disnull, Oid array_type, MemoryContext rcontext)
Definition: arrayfuncs.c:5532
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 5532 of file arrayfuncs.c.

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

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

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 3749 of file arrayfuncs.c.

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

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_columns_length(), 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 4579 of file arrayfuncs.c.

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

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

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 1821 of file arrayfuncs.c.

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

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

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

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

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

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 3157 of file arrayfuncs.c.

3160 {
3162  nSubscripts, indx,
3163  dataValue, isNull,
3164  arraytyplen,
3165  elmlen, elmbyval, elmalign));
3166 }
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:2202

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 2202 of file arrayfuncs.c.

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

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

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:171
#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:3749
void deconstruct_array_builtin(ArrayType *array, Oid elmtype, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3679
int32 pg_strtoint32(const char *s)
Definition: numutils.c:384
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:594

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 3355 of file arrayfuncs.c.

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

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 3375 of file arrayfuncs.c.

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

3582 {
3583  ArrayType *array = construct_empty_array(element_type);
3584  Datum d;
3585 
3586  d = expand_array(PointerGetDatum(array), parentcontext, metacache);
3587  pfree(array);
3588  return (ExpandedArrayHeader *) DatumGetEOHP(d);
3589 }
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 3476 of file arrayfuncs.c.

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

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 962 of file arrayfuncs.c.

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

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:135
#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 3613 of file arrayfuncs.c.

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

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 3679 of file arrayfuncs.c.

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

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:1021
#define AllocSetContextCreate
Definition: memutils.h:126
#define ALLOCSET_START_SMALL_SIZES
Definition: memutils.h:167
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 5275 of file arrayfuncs.c.

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

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 5764 of file arrayfuncs.c.

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

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 5486 of file arrayfuncs.c.

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

5294 {
5295  ArrayBuildState *astate;
5296  MemoryContext arr_context = rcontext;
5297 
5298  /* Make a temporary context to hold all the junk */
5299  if (subcontext)
5300  arr_context = AllocSetContextCreate(rcontext,
5301  "accumArrayResult",
5303 
5304  astate = (ArrayBuildState *)
5305  MemoryContextAlloc(arr_context, sizeof(ArrayBuildState));
5306  astate->mcontext = arr_context;
5307  astate->private_cxt = subcontext;
5308  astate->alen = initsize;
5309  astate->dvalues = (Datum *)
5310  MemoryContextAlloc(arr_context, astate->alen * sizeof(Datum));
5311  astate->dnulls = (bool *)
5312  MemoryContextAlloc(arr_context, astate->alen * sizeof(bool));
5313  astate->nelems = 0;
5314  astate->element_type = element_type;
5315  get_typlenbyvalalign(element_type,
5316  &astate->typlen,
5317  &astate->typbyval,
5318  &astate->typalign);
5319 
5320  return astate;
5321 }
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 5402 of file arrayfuncs.c.

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

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 5837 of file arrayfuncs.c.

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

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 5685 of file arrayfuncs.c.

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

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 5434 of file arrayfuncs.c.

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

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 44 of file arrayfuncs.c.

Referenced by ReadArrayToken().