PostgreSQL Source Code  git master
arrayfuncs.c File Reference
#include "postgres.h"
#include <ctype.h>
#include <math.h>
#include "catalog/pg_type.h"
#include "common/int.h"
#include "funcapi.h"
#include "libpq/pqformat.h"
#include "nodes/nodeFuncs.h"
#include "nodes/supportnodes.h"
#include "optimizer/optimizer.h"
#include "parser/scansup.h"
#include "port/pg_bitutils.h"
#include "utils/array.h"
#include "utils/arrayaccess.h"
#include "utils/builtins.h"
#include "utils/datum.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/selfuncs.h"
#include "utils/typcache.h"
Include dependency graph for arrayfuncs.c:

Go to the source code of this file.

Data Structures

struct  ArrayIteratorData
 
struct  generate_subscripts_fctx
 

Macros

#define ASSGN   "="
 
#define AARR_FREE_IF_COPY(array, n)
 
#define APPENDSTR(str)   (strcpy(p, (str)), p += strlen(p))
 
#define APPENDCHAR(ch)   (*p++ = (ch), *p = '\0')
 

Typedefs

typedef struct ArrayIteratorData ArrayIteratorData
 
typedef struct generate_subscripts_fctx generate_subscripts_fctx
 

Enumerations

enum  ArrayToken {
  ATOK_LEVEL_START , ATOK_LEVEL_END , ATOK_DELIM , ATOK_ELEM ,
  ATOK_ELEM_NULL , ATOK_ERROR
}
 

Functions

static bool ReadArrayDimensions (char **srcptr, int *ndim_p, int *dim, int *lBound, const char *origStr, Node *escontext)
 
static bool ReadDimensionInt (char **srcptr, int *result, const char *origStr, Node *escontext)
 
static bool ReadArrayStr (char **srcptr, FmgrInfo *inputproc, Oid typioparam, int32 typmod, char typdelim, int typlen, bool typbyval, char typalign, int *ndim_p, int *dim, int *nitems_p, Datum **values_p, bool **nulls_p, const char *origStr, Node *escontext)
 
static ArrayToken ReadArrayToken (char **srcptr, StringInfo elembuf, char typdelim, const char *origStr, Node *escontext)
 
static void ReadArrayBinary (StringInfo buf, int nitems, FmgrInfo *receiveproc, Oid typioparam, int32 typmod, int typlen, bool typbyval, char typalign, Datum *values, bool *nulls, bool *hasnulls, int32 *nbytes)
 
static Datum array_get_element_expanded (Datum arraydatum, int nSubscripts, int *indx, int arraytyplen, int elmlen, bool elmbyval, char elmalign, bool *isNull)
 
static Datum array_set_element_expanded (Datum arraydatum, int nSubscripts, int *indx, Datum dataValue, bool isNull, int arraytyplen, int elmlen, bool elmbyval, char elmalign)
 
static bool array_get_isnull (const bits8 *nullbitmap, int offset)
 
static void array_set_isnull (bits8 *nullbitmap, int offset, bool isNull)
 
static Datum ArrayCast (char *value, bool byval, int len)
 
static int ArrayCastAndSet (Datum src, int typlen, bool typbyval, char typalign, char *dest)
 
static char * array_seek (char *ptr, int offset, bits8 *nullbitmap, int nitems, int typlen, bool typbyval, char typalign)
 
static int array_nelems_size (char *ptr, int offset, bits8 *nullbitmap, int nitems, int typlen, bool typbyval, char typalign)
 
static int array_copy (char *destptr, int nitems, char *srcptr, int offset, bits8 *nullbitmap, int typlen, bool typbyval, char typalign)
 
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)
 
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)
 
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)
 
static int array_cmp (FunctionCallInfo fcinfo)
 
static ArrayTypecreate_array_envelope (int ndims, int *dimv, int *lbsv, int nbytes, Oid elmtype, int dataoffset)
 
static ArrayTypearray_fill_internal (ArrayType *dims, ArrayType *lbs, Datum value, bool isnull, Oid elmtype, FunctionCallInfo fcinfo)
 
static ArrayTypearray_replace_internal (ArrayType *array, Datum search, bool search_isnull, Datum replace, bool replace_isnull, bool remove, Oid collation, FunctionCallInfo fcinfo)
 
static int width_bucket_array_float8 (Datum operand, ArrayType *thresholds)
 
static int width_bucket_array_fixed (Datum operand, ArrayType *thresholds, Oid collation, TypeCacheEntry *typentry)
 
static int width_bucket_array_variable (Datum operand, ArrayType *thresholds, Oid collation, TypeCacheEntry *typentry)
 
Datum array_in (PG_FUNCTION_ARGS)
 
void CopyArrayEls (ArrayType *array, Datum *values, bool *nulls, int nitems, int typlen, bool typbyval, char typalign, bool freedata)
 
Datum array_out (PG_FUNCTION_ARGS)
 
Datum array_recv (PG_FUNCTION_ARGS)
 
Datum array_send (PG_FUNCTION_ARGS)
 
Datum array_ndims (PG_FUNCTION_ARGS)
 
Datum array_dims (PG_FUNCTION_ARGS)
 
Datum array_lower (PG_FUNCTION_ARGS)
 
Datum array_upper (PG_FUNCTION_ARGS)
 
Datum array_length (PG_FUNCTION_ARGS)
 
Datum array_cardinality (PG_FUNCTION_ARGS)
 
Datum array_get_element (Datum arraydatum, int nSubscripts, int *indx, int arraytyplen, int elmlen, bool elmbyval, char elmalign, bool *isNull)
 
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_element (Datum arraydatum, int nSubscripts, int *indx, Datum dataValue, bool isNull, 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, ExprState *exprstate, ExprContext *econtext, Oid retType, ArrayMapState *amstate)
 
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)
 
Datum array_eq (PG_FUNCTION_ARGS)
 
Datum array_ne (PG_FUNCTION_ARGS)
 
Datum array_lt (PG_FUNCTION_ARGS)
 
Datum array_gt (PG_FUNCTION_ARGS)
 
Datum array_le (PG_FUNCTION_ARGS)
 
Datum array_ge (PG_FUNCTION_ARGS)
 
Datum btarraycmp (PG_FUNCTION_ARGS)
 
Datum hash_array (PG_FUNCTION_ARGS)
 
Datum hash_array_extended (PG_FUNCTION_ARGS)
 
static bool array_contain_compare (AnyArrayType *array1, AnyArrayType *array2, Oid collation, bool matchall, void **fn_extra)
 
Datum arrayoverlap (PG_FUNCTION_ARGS)
 
Datum arraycontains (PG_FUNCTION_ARGS)
 
Datum arraycontained (PG_FUNCTION_ARGS)
 
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)
 
void array_bitmap_copy (bits8 *destbitmap, int destoffset, const bits8 *srcbitmap, int srcoffset, int nitems)
 
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)
 
Datum array_larger (PG_FUNCTION_ARGS)
 
Datum array_smaller (PG_FUNCTION_ARGS)
 
Datum generate_subscripts (PG_FUNCTION_ARGS)
 
Datum generate_subscripts_nodir (PG_FUNCTION_ARGS)
 
Datum array_fill_with_lower_bounds (PG_FUNCTION_ARGS)
 
Datum array_fill (PG_FUNCTION_ARGS)
 
Datum array_unnest (PG_FUNCTION_ARGS)
 
Datum array_unnest_support (PG_FUNCTION_ARGS)
 
Datum array_remove (PG_FUNCTION_ARGS)
 
Datum array_replace (PG_FUNCTION_ARGS)
 
Datum width_bucket_array (PG_FUNCTION_ARGS)
 
Datum trim_array (PG_FUNCTION_ARGS)
 

Variables

bool Array_nulls = true
 

Macro Definition Documentation

◆ AARR_FREE_IF_COPY

#define AARR_FREE_IF_COPY (   array,
 
)
Value:
do { \
PG_FREE_IF_COPY(array, n); \
} while (0)
#define VARATT_IS_EXPANDED_HEADER(PTR)

Definition at line 50 of file arrayfuncs.c.

◆ APPENDCHAR

#define APPENDCHAR (   ch)    (*p++ = (ch), *p = '\0')

◆ APPENDSTR

#define APPENDSTR (   str)    (strcpy(p, (str)), p += strlen(p))

◆ ASSGN

#define ASSGN   "="

Definition at line 48 of file arrayfuncs.c.

Typedef Documentation

◆ ArrayIteratorData

◆ generate_subscripts_fctx

Enumeration Type Documentation

◆ ArrayToken

enum ArrayToken
Enumerator
ATOK_LEVEL_START 
ATOK_LEVEL_END 
ATOK_DELIM 
ATOK_ELEM 
ATOK_ELEM_NULL 
ATOK_ERROR 

Definition at line 57 of file arrayfuncs.c.

58 {
61  ATOK_DELIM,
62  ATOK_ELEM,
64  ATOK_ERROR,
65 } ArrayToken;
ArrayToken
Definition: arrayfuncs.c:58
@ ATOK_ELEM_NULL
Definition: arrayfuncs.c:63
@ ATOK_DELIM
Definition: arrayfuncs.c:61
@ ATOK_LEVEL_END
Definition: arrayfuncs.c:60
@ ATOK_ELEM
Definition: arrayfuncs.c:62
@ ATOK_LEVEL_START
Definition: arrayfuncs.c:59
@ ATOK_ERROR
Definition: arrayfuncs.c:64

Function Documentation

◆ accumArrayResult()

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

Definition at line 5331 of file arrayfuncs.c.

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

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

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

◆ accumArrayResultAny()

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

Definition at line 5808 of file arrayfuncs.c.

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

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

Referenced by ExecScanSubPlan(), and ExecSetParamPlan().

◆ accumArrayResultArr()

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

Definition at line 5531 of file arrayfuncs.c.

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

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

Referenced by accumArrayResultAny(), and array_agg_array_transfn().

◆ array_bitmap_copy()

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

Definition at line 4947 of file arrayfuncs.c.

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

References Assert(), and nitems.

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

◆ array_cardinality()

Datum array_cardinality ( PG_FUNCTION_ARGS  )

Definition at line 1790 of file arrayfuncs.c.

1791 {
1793 
1795 }
#define AARR_DIMS(a)
Definition: array.h:338
#define PG_GETARG_ANY_ARRAY_P(n)
Definition: array.h:274
#define AARR_NDIM(a)
Definition: array.h:328
#define PG_RETURN_INT32(x)
Definition: fmgr.h:354

References AARR_DIMS, AARR_NDIM, ArrayGetNItems(), PG_GETARG_ANY_ARRAY_P, and PG_RETURN_INT32.

◆ array_cmp()

static int array_cmp ( FunctionCallInfo  fcinfo)
static

Definition at line 3966 of file arrayfuncs.c.

3967 {
3968  LOCAL_FCINFO(locfcinfo, 2);
3969  AnyArrayType *array1 = PG_GETARG_ANY_ARRAY_P(0);
3970  AnyArrayType *array2 = PG_GETARG_ANY_ARRAY_P(1);
3971  Oid collation = PG_GET_COLLATION();
3972  int ndims1 = AARR_NDIM(array1);
3973  int ndims2 = AARR_NDIM(array2);
3974  int *dims1 = AARR_DIMS(array1);
3975  int *dims2 = AARR_DIMS(array2);
3976  int nitems1 = ArrayGetNItems(ndims1, dims1);
3977  int nitems2 = ArrayGetNItems(ndims2, dims2);
3978  Oid element_type = AARR_ELEMTYPE(array1);
3979  int result = 0;
3980  TypeCacheEntry *typentry;
3981  int typlen;
3982  bool typbyval;
3983  char typalign;
3984  int min_nitems;
3985  array_iter it1;
3986  array_iter it2;
3987  int i;
3988 
3989  if (element_type != AARR_ELEMTYPE(array2))
3990  ereport(ERROR,
3991  (errcode(ERRCODE_DATATYPE_MISMATCH),
3992  errmsg("cannot compare arrays of different element types")));
3993 
3994  /*
3995  * We arrange to look up the comparison function only once per series of
3996  * calls, assuming the element type doesn't change underneath us. The
3997  * typcache is used so that we have no memory leakage when being used as
3998  * an index support function.
3999  */
4000  typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
4001  if (typentry == NULL ||
4002  typentry->type_id != element_type)
4003  {
4004  typentry = lookup_type_cache(element_type,
4006  if (!OidIsValid(typentry->cmp_proc_finfo.fn_oid))
4007  ereport(ERROR,
4008  (errcode(ERRCODE_UNDEFINED_FUNCTION),
4009  errmsg("could not identify a comparison function for type %s",
4010  format_type_be(element_type))));
4011  fcinfo->flinfo->fn_extra = (void *) typentry;
4012  }
4013  typlen = typentry->typlen;
4014  typbyval = typentry->typbyval;
4015  typalign = typentry->typalign;
4016 
4017  /*
4018  * apply the operator to each pair of array elements.
4019  */
4020  InitFunctionCallInfoData(*locfcinfo, &typentry->cmp_proc_finfo, 2,
4021  collation, NULL, NULL);
4022 
4023  /* Loop over source data */
4024  min_nitems = Min(nitems1, nitems2);
4025  array_iter_setup(&it1, array1);
4026  array_iter_setup(&it2, array2);
4027 
4028  for (i = 0; i < min_nitems; i++)
4029  {
4030  Datum elt1;
4031  Datum elt2;
4032  bool isnull1;
4033  bool isnull2;
4034  int32 cmpresult;
4035 
4036  /* Get elements, checking for NULL */
4037  elt1 = array_iter_next(&it1, &isnull1, i, typlen, typbyval, typalign);
4038  elt2 = array_iter_next(&it2, &isnull2, i, typlen, typbyval, typalign);
4039 
4040  /*
4041  * We consider two NULLs equal; NULL > not-NULL.
4042  */
4043  if (isnull1 && isnull2)
4044  continue;
4045  if (isnull1)
4046  {
4047  /* arg1 is greater than arg2 */
4048  result = 1;
4049  break;
4050  }
4051  if (isnull2)
4052  {
4053  /* arg1 is less than arg2 */
4054  result = -1;
4055  break;
4056  }
4057 
4058  /* Compare the pair of elements */
4059  locfcinfo->args[0].value = elt1;
4060  locfcinfo->args[0].isnull = false;
4061  locfcinfo->args[1].value = elt2;
4062  locfcinfo->args[1].isnull = false;
4063  cmpresult = DatumGetInt32(FunctionCallInvoke(locfcinfo));
4064 
4065  /* We don't expect comparison support functions to return null */
4066  Assert(!locfcinfo->isnull);
4067 
4068  if (cmpresult == 0)
4069  continue; /* equal */
4070 
4071  if (cmpresult < 0)
4072  {
4073  /* arg1 is less than arg2 */
4074  result = -1;
4075  break;
4076  }
4077  else
4078  {
4079  /* arg1 is greater than arg2 */
4080  result = 1;
4081  break;
4082  }
4083  }
4084 
4085  /*
4086  * If arrays contain same data (up to end of shorter one), apply
4087  * additional rules to sort by dimensionality. The relative significance
4088  * of the different bits of information is historical; mainly we just care
4089  * that we don't say "equal" for arrays of different dimensionality.
4090  */
4091  if (result == 0)
4092  {
4093  if (nitems1 != nitems2)
4094  result = (nitems1 < nitems2) ? -1 : 1;
4095  else if (ndims1 != ndims2)
4096  result = (ndims1 < ndims2) ? -1 : 1;
4097  else
4098  {
4099  for (i = 0; i < ndims1; i++)
4100  {
4101  if (dims1[i] != dims2[i])
4102  {
4103  result = (dims1[i] < dims2[i]) ? -1 : 1;
4104  break;
4105  }
4106  }
4107  if (result == 0)
4108  {
4109  int *lbound1 = AARR_LBOUND(array1);
4110  int *lbound2 = AARR_LBOUND(array2);
4111 
4112  for (i = 0; i < ndims1; i++)
4113  {
4114  if (lbound1[i] != lbound2[i])
4115  {
4116  result = (lbound1[i] < lbound2[i]) ? -1 : 1;
4117  break;
4118  }
4119  }
4120  }
4121  }
4122  }
4123 
4124  /* Avoid leaking memory when handed toasted input. */
4125  AARR_FREE_IF_COPY(array1, 0);
4126  AARR_FREE_IF_COPY(array2, 1);
4127 
4128  return result;
4129 }
#define AARR_ELEMTYPE(a)
Definition: array.h:335
#define AARR_LBOUND(a)
Definition: array.h:341
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
#define AARR_FREE_IF_COPY(array, n)
Definition: arrayfuncs.c:50
#define Min(x, y)
Definition: c.h:991
signed int int32
Definition: c.h:481
#define OidIsValid(objectId)
Definition: c.h:762
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition: fmgr.h:150
#define LOCAL_FCINFO(name, nargs)
Definition: fmgr.h:110
#define FunctionCallInvoke(fcinfo)
Definition: fmgr.h:172
#define PG_GET_COLLATION()
Definition: fmgr.h:198
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
char typalign
Definition: pg_type.h:176
static int32 DatumGetInt32(Datum X)
Definition: postgres.h:202
unsigned int Oid
Definition: postgres_ext.h:31
void * fn_extra
Definition: fmgr.h:64
Oid fn_oid
Definition: fmgr.h:59
FmgrInfo * flinfo
Definition: fmgr.h:87
FmgrInfo cmp_proc_finfo
Definition: typcache.h:76
char typalign
Definition: typcache.h:41
bool typbyval
Definition: typcache.h:40
int16 typlen
Definition: typcache.h:39
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:346
#define TYPECACHE_CMP_PROC_FINFO
Definition: typcache.h:143

References AARR_DIMS, AARR_ELEMTYPE, AARR_FREE_IF_COPY, AARR_LBOUND, AARR_NDIM, array_iter_next(), array_iter_setup(), ArrayGetNItems(), Assert(), TypeCacheEntry::cmp_proc_finfo, DatumGetInt32(), ereport, errcode(), errmsg(), ERROR, FunctionCallInfoBaseData::flinfo, FmgrInfo::fn_extra, FmgrInfo::fn_oid, format_type_be(), FunctionCallInvoke, i, if(), InitFunctionCallInfoData, LOCAL_FCINFO, lookup_type_cache(), Min, OidIsValid, PG_GET_COLLATION, PG_GETARG_ANY_ARRAY_P, typalign, TypeCacheEntry::typalign, TypeCacheEntry::typbyval, TypeCacheEntry::type_id, TYPECACHE_CMP_PROC_FINFO, and TypeCacheEntry::typlen.

Referenced by array_ge(), array_gt(), array_larger(), array_le(), array_lt(), array_smaller(), and btarraycmp().

◆ array_contain_compare()

static bool array_contain_compare ( AnyArrayType array1,
AnyArrayType array2,
Oid  collation,
bool  matchall,
void **  fn_extra 
)
static

Definition at line 4362 of file arrayfuncs.c.

4364 {
4365  LOCAL_FCINFO(locfcinfo, 2);
4366  bool result = matchall;
4367  Oid element_type = AARR_ELEMTYPE(array1);
4368  TypeCacheEntry *typentry;
4369  int nelems1;
4370  Datum *values2;
4371  bool *nulls2;
4372  int nelems2;
4373  int typlen;
4374  bool typbyval;
4375  char typalign;
4376  int i;
4377  int j;
4378  array_iter it1;
4379 
4380  if (element_type != AARR_ELEMTYPE(array2))
4381  ereport(ERROR,
4382  (errcode(ERRCODE_DATATYPE_MISMATCH),
4383  errmsg("cannot compare arrays of different element types")));
4384 
4385  /*
4386  * We arrange to look up the equality function only once per series of
4387  * calls, assuming the element type doesn't change underneath us. The
4388  * typcache is used so that we have no memory leakage when being used as
4389  * an index support function.
4390  */
4391  typentry = (TypeCacheEntry *) *fn_extra;
4392  if (typentry == NULL ||
4393  typentry->type_id != element_type)
4394  {
4395  typentry = lookup_type_cache(element_type,
4397  if (!OidIsValid(typentry->eq_opr_finfo.fn_oid))
4398  ereport(ERROR,
4399  (errcode(ERRCODE_UNDEFINED_FUNCTION),
4400  errmsg("could not identify an equality operator for type %s",
4401  format_type_be(element_type))));
4402  *fn_extra = (void *) typentry;
4403  }
4404  typlen = typentry->typlen;
4405  typbyval = typentry->typbyval;
4406  typalign = typentry->typalign;
4407 
4408  /*
4409  * Since we probably will need to scan array2 multiple times, it's
4410  * worthwhile to use deconstruct_array on it. We scan array1 the hard way
4411  * however, since we very likely won't need to look at all of it.
4412  */
4413  if (VARATT_IS_EXPANDED_HEADER(array2))
4414  {
4415  /* This should be safe even if input is read-only */
4416  deconstruct_expanded_array(&(array2->xpn));
4417  values2 = array2->xpn.dvalues;
4418  nulls2 = array2->xpn.dnulls;
4419  nelems2 = array2->xpn.nelems;
4420  }
4421  else
4422  deconstruct_array((ArrayType *) array2,
4423  element_type, typlen, typbyval, typalign,
4424  &values2, &nulls2, &nelems2);
4425 
4426  /*
4427  * Apply the comparison operator to each pair of array elements.
4428  */
4429  InitFunctionCallInfoData(*locfcinfo, &typentry->eq_opr_finfo, 2,
4430  collation, NULL, NULL);
4431 
4432  /* Loop over source data */
4433  nelems1 = ArrayGetNItems(AARR_NDIM(array1), AARR_DIMS(array1));
4434  array_iter_setup(&it1, array1);
4435 
4436  for (i = 0; i < nelems1; i++)
4437  {
4438  Datum elt1;
4439  bool isnull1;
4440 
4441  /* Get element, checking for NULL */
4442  elt1 = array_iter_next(&it1, &isnull1, i, typlen, typbyval, typalign);
4443 
4444  /*
4445  * We assume that the comparison operator is strict, so a NULL can't
4446  * match anything. XXX this diverges from the "NULL=NULL" behavior of
4447  * array_eq, should we act like that?
4448  */
4449  if (isnull1)
4450  {
4451  if (matchall)
4452  {
4453  result = false;
4454  break;
4455  }
4456  continue;
4457  }
4458 
4459  for (j = 0; j < nelems2; j++)
4460  {
4461  Datum elt2 = values2[j];
4462  bool isnull2 = nulls2 ? nulls2[j] : false;
4463  bool oprresult;
4464 
4465  if (isnull2)
4466  continue; /* can't match */
4467 
4468  /*
4469  * Apply the operator to the element pair; treat NULL as false
4470  */
4471  locfcinfo->args[0].value = elt1;
4472  locfcinfo->args[0].isnull = false;
4473  locfcinfo->args[1].value = elt2;
4474  locfcinfo->args[1].isnull = false;
4475  locfcinfo->isnull = false;
4476  oprresult = DatumGetBool(FunctionCallInvoke(locfcinfo));
4477  if (!locfcinfo->isnull && oprresult)
4478  break;
4479  }
4480 
4481  if (j < nelems2)
4482  {
4483  /* found a match for elt1 */
4484  if (!matchall)
4485  {
4486  result = true;
4487  break;
4488  }
4489  }
4490  else
4491  {
4492  /* no match for elt1 */
4493  if (matchall)
4494  {
4495  result = false;
4496  break;
4497  }
4498  }
4499  }
4500 
4501  return result;
4502 }
void deconstruct_expanded_array(ExpandedArrayHeader *eah)
void deconstruct_array(ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3612
int j
Definition: isn.c:74
static bool DatumGetBool(Datum X)
Definition: postgres.h:90
Datum * dvalues
Definition: array.h:146
FmgrInfo eq_opr_finfo
Definition: typcache.h:75
#define TYPECACHE_EQ_OPR_FINFO
Definition: typcache.h:142
ExpandedArrayHeader xpn
Definition: array.h:180

References AARR_DIMS, AARR_ELEMTYPE, AARR_NDIM, array_iter_next(), array_iter_setup(), ArrayGetNItems(), DatumGetBool(), deconstruct_array(), deconstruct_expanded_array(), ExpandedArrayHeader::dnulls, ExpandedArrayHeader::dvalues, TypeCacheEntry::eq_opr_finfo, ereport, errcode(), errmsg(), ERROR, FmgrInfo::fn_oid, format_type_be(), FunctionCallInvoke, i, InitFunctionCallInfoData, j, LOCAL_FCINFO, lookup_type_cache(), ExpandedArrayHeader::nelems, OidIsValid, typalign, TypeCacheEntry::typalign, TypeCacheEntry::typbyval, TypeCacheEntry::type_id, TYPECACHE_EQ_OPR_FINFO, TypeCacheEntry::typlen, VARATT_IS_EXPANDED_HEADER, and AnyArrayType::xpn.

Referenced by arraycontained(), arraycontains(), and arrayoverlap().

◆ array_contains_nulls()

bool array_contains_nulls ( ArrayType array)

Definition at line 3748 of file arrayfuncs.c.

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

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

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

◆ array_copy()

static int array_copy ( char *  destptr,
int  nitems,
char *  srcptr,
int  offset,
bits8 nullbitmap,
int  typlen,
bool  typbyval,
char  typalign 
)
static

Definition at line 4917 of file arrayfuncs.c.

4920 {
4921  int numbytes;
4922 
4923  numbytes = array_nelems_size(srcptr, offset, nullbitmap, nitems,
4924  typlen, typbyval, typalign);
4925  memcpy(destptr, srcptr, numbytes);
4926  return numbytes;
4927 }
static int array_nelems_size(char *ptr, int offset, bits8 *nullbitmap, int nitems, int typlen, bool typbyval, char typalign)
Definition: arrayfuncs.c:4895

References array_nelems_size(), nitems, and typalign.

Referenced by array_extract_slice(), and array_insert_slice().

◆ array_create_iterator()

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

Definition at line 4578 of file arrayfuncs.c.

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

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

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

◆ array_dims()

Datum array_dims ( PG_FUNCTION_ARGS  )

Definition at line 1668 of file arrayfuncs.c.

1669 {
1671  char *p;
1672  int i;
1673  int *dimv,
1674  *lb;
1675 
1676  /*
1677  * 33 since we assume 15 digits per number + ':' +'[]'
1678  *
1679  * +1 for trailing null
1680  */
1681  char buf[MAXDIM * 33 + 1];
1682 
1683  /* Sanity check: does it look like an array at all? */
1684  if (AARR_NDIM(v) <= 0 || AARR_NDIM(v) > MAXDIM)
1685  PG_RETURN_NULL();
1686 
1687  dimv = AARR_DIMS(v);
1688  lb = AARR_LBOUND(v);
1689 
1690  p = buf;
1691  for (i = 0; i < AARR_NDIM(v); i++)
1692  {
1693  sprintf(p, "[%d:%d]", lb[i], dimv[i] + lb[i] - 1);
1694  p += strlen(p);
1695  }
1696 
1698 }
#define PG_RETURN_NULL()
Definition: fmgr.h:345
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:372
static char * buf
Definition: pg_test_fsync.c:73
#define sprintf
Definition: port.h:240
text * cstring_to_text(const char *s)
Definition: varlena.c:184

References AARR_DIMS, AARR_LBOUND, AARR_NDIM, buf, cstring_to_text(), i, MAXDIM, PG_GETARG_ANY_ARRAY_P, PG_RETURN_NULL, PG_RETURN_TEXT_P, and sprintf.

◆ array_eq()

Datum array_eq ( PG_FUNCTION_ARGS  )

Definition at line 3795 of file arrayfuncs.c.

3796 {
3797  LOCAL_FCINFO(locfcinfo, 2);
3798  AnyArrayType *array1 = PG_GETARG_ANY_ARRAY_P(0);
3799  AnyArrayType *array2 = PG_GETARG_ANY_ARRAY_P(1);
3800  Oid collation = PG_GET_COLLATION();
3801  int ndims1 = AARR_NDIM(array1);
3802  int ndims2 = AARR_NDIM(array2);
3803  int *dims1 = AARR_DIMS(array1);
3804  int *dims2 = AARR_DIMS(array2);
3805  int *lbs1 = AARR_LBOUND(array1);
3806  int *lbs2 = AARR_LBOUND(array2);
3807  Oid element_type = AARR_ELEMTYPE(array1);
3808  bool result = true;
3809  int nitems;
3810  TypeCacheEntry *typentry;
3811  int typlen;
3812  bool typbyval;
3813  char typalign;
3814  array_iter it1;
3815  array_iter it2;
3816  int i;
3817 
3818  if (element_type != AARR_ELEMTYPE(array2))
3819  ereport(ERROR,
3820  (errcode(ERRCODE_DATATYPE_MISMATCH),
3821  errmsg("cannot compare arrays of different element types")));
3822 
3823  /* fast path if the arrays do not have the same dimensionality */
3824  if (ndims1 != ndims2 ||
3825  memcmp(dims1, dims2, ndims1 * sizeof(int)) != 0 ||
3826  memcmp(lbs1, lbs2, ndims1 * sizeof(int)) != 0)
3827  result = false;
3828  else
3829  {
3830  /*
3831  * We arrange to look up the equality function only once per series of
3832  * calls, assuming the element type doesn't change underneath us. The
3833  * typcache is used so that we have no memory leakage when being used
3834  * as an index support function.
3835  */
3836  typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
3837  if (typentry == NULL ||
3838  typentry->type_id != element_type)
3839  {
3840  typentry = lookup_type_cache(element_type,
3842  if (!OidIsValid(typentry->eq_opr_finfo.fn_oid))
3843  ereport(ERROR,
3844  (errcode(ERRCODE_UNDEFINED_FUNCTION),
3845  errmsg("could not identify an equality operator for type %s",
3846  format_type_be(element_type))));
3847  fcinfo->flinfo->fn_extra = (void *) typentry;
3848  }
3849  typlen = typentry->typlen;
3850  typbyval = typentry->typbyval;
3851  typalign = typentry->typalign;
3852 
3853  /*
3854  * apply the operator to each pair of array elements.
3855  */
3856  InitFunctionCallInfoData(*locfcinfo, &typentry->eq_opr_finfo, 2,
3857  collation, NULL, NULL);
3858 
3859  /* Loop over source data */
3860  nitems = ArrayGetNItems(ndims1, dims1);
3861  array_iter_setup(&it1, array1);
3862  array_iter_setup(&it2, array2);
3863 
3864  for (i = 0; i < nitems; i++)
3865  {
3866  Datum elt1;
3867  Datum elt2;
3868  bool isnull1;
3869  bool isnull2;
3870  bool oprresult;
3871 
3872  /* Get elements, checking for NULL */
3873  elt1 = array_iter_next(&it1, &isnull1, i,
3874  typlen, typbyval, typalign);
3875  elt2 = array_iter_next(&it2, &isnull2, i,
3876  typlen, typbyval, typalign);
3877 
3878  /*
3879  * We consider two NULLs equal; NULL and not-NULL are unequal.
3880  */
3881  if (isnull1 && isnull2)
3882  continue;
3883  if (isnull1 || isnull2)
3884  {
3885  result = false;
3886  break;
3887  }
3888 
3889  /*
3890  * Apply the operator to the element pair; treat NULL as false
3891  */
3892  locfcinfo->args[0].value = elt1;
3893  locfcinfo->args[0].isnull = false;
3894  locfcinfo->args[1].value = elt2;
3895  locfcinfo->args[1].isnull = false;
3896  locfcinfo->isnull = false;
3897  oprresult = DatumGetBool(FunctionCallInvoke(locfcinfo));
3898  if (locfcinfo->isnull || !oprresult)
3899  {
3900  result = false;
3901  break;
3902  }
3903  }
3904  }
3905 
3906  /* Avoid leaking memory when handed toasted input. */
3907  AARR_FREE_IF_COPY(array1, 0);
3908  AARR_FREE_IF_COPY(array2, 1);
3909 
3910  PG_RETURN_BOOL(result);
3911 }
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:359

References AARR_DIMS, AARR_ELEMTYPE, AARR_FREE_IF_COPY, AARR_LBOUND, AARR_NDIM, array_iter_next(), array_iter_setup(), ArrayGetNItems(), DatumGetBool(), TypeCacheEntry::eq_opr_finfo, ereport, errcode(), errmsg(), ERROR, FmgrInfo::fn_oid, format_type_be(), FunctionCallInvoke, i, if(), InitFunctionCallInfoData, LOCAL_FCINFO, lookup_type_cache(), nitems, OidIsValid, PG_GET_COLLATION, PG_GETARG_ANY_ARRAY_P, PG_RETURN_BOOL, typalign, TypeCacheEntry::typalign, TypeCacheEntry::typbyval, TypeCacheEntry::type_id, TYPECACHE_EQ_OPR_FINFO, and TypeCacheEntry::typlen.

Referenced by array_ne(), and CompareOpclassOptions().

◆ array_extract_slice()

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 
)
static

Definition at line 5078 of file arrayfuncs.c.

5089 {
5090  char *destdataptr = ARR_DATA_PTR(newarray);
5091  bits8 *destnullsptr = ARR_NULLBITMAP(newarray);
5092  char *srcdataptr;
5093  int src_offset,
5094  dest_offset,
5095  prod[MAXDIM],
5096  span[MAXDIM],
5097  dist[MAXDIM],
5098  indx[MAXDIM];
5099  int i,
5100  j,
5101  inc;
5102 
5103  src_offset = ArrayGetOffset(ndim, dim, lb, st);
5104  srcdataptr = array_seek(arraydataptr, 0, arraynullsptr, src_offset,
5105  typlen, typbyval, typalign);
5106  mda_get_prod(ndim, dim, prod);
5107  mda_get_range(ndim, span, st, endp);
5108  mda_get_offset_values(ndim, dist, prod, span);
5109  for (i = 0; i < ndim; i++)
5110  indx[i] = 0;
5111  dest_offset = 0;
5112  j = ndim - 1;
5113  do
5114  {
5115  if (dist[j])
5116  {
5117  /* skip unwanted elements */
5118  srcdataptr = array_seek(srcdataptr, src_offset, arraynullsptr,
5119  dist[j],
5120  typlen, typbyval, typalign);
5121  src_offset += dist[j];
5122  }
5123  inc = array_copy(destdataptr, 1,
5124  srcdataptr, src_offset, arraynullsptr,
5125  typlen, typbyval, typalign);
5126  if (destnullsptr)
5127  array_bitmap_copy(destnullsptr, dest_offset,
5128  arraynullsptr, src_offset,
5129  1);
5130  destdataptr += inc;
5131  srcdataptr += inc;
5132  src_offset++;
5133  dest_offset++;
5134  } while ((j = mda_next_tuple(ndim, indx, span)) != -1);
5135 }
static int array_copy(char *destptr, int nitems, char *srcptr, int offset, bits8 *nullbitmap, int typlen, bool typbyval, char typalign)
Definition: arrayfuncs.c:4917
static char * array_seek(char *ptr, int offset, bits8 *nullbitmap, int nitems, int typlen, bool typbyval, char typalign)
Definition: arrayfuncs.c:4847
void mda_get_offset_values(int n, int *dist, const int *prod, const int *span)
Definition: arrayutils.c:183
int ArrayGetOffset(int n, const int *dim, const int *lb, const int *indx)
Definition: arrayutils.c:32
void mda_get_range(int n, int *span, const int *st, const int *endp)
Definition: arrayutils.c:153
void mda_get_prod(int n, const int *range, int *prod)
Definition: arrayutils.c:167
int mda_next_tuple(int n, int *curr, const int *span)
Definition: arrayutils.c:208

References ARR_DATA_PTR, ARR_NULLBITMAP, array_bitmap_copy(), array_copy(), array_seek(), ArrayGetOffset(), i, j, MAXDIM, mda_get_offset_values(), mda_get_prod(), mda_get_range(), mda_next_tuple(), and typalign.

Referenced by array_get_slice().

◆ array_fill()

Datum array_fill ( PG_FUNCTION_ARGS  )

Definition at line 6012 of file arrayfuncs.c.

6013 {
6014  ArrayType *dims;
6015  ArrayType *result;
6016  Oid elmtype;
6017  Datum value;
6018  bool isnull;
6019 
6020  if (PG_ARGISNULL(1))
6021  ereport(ERROR,
6022  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
6023  errmsg("dimension array or low bound array cannot be null")));
6024 
6025  dims = PG_GETARG_ARRAYTYPE_P(1);
6026 
6027  if (!PG_ARGISNULL(0))
6028  {
6029  value = PG_GETARG_DATUM(0);
6030  isnull = false;
6031  }
6032  else
6033  {
6034  value = 0;
6035  isnull = true;
6036  }
6037 
6038  elmtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
6039  if (!OidIsValid(elmtype))
6040  elog(ERROR, "could not determine data type of input");
6041 
6042  result = array_fill_internal(dims, NULL, value, isnull, elmtype, fcinfo);
6043  PG_RETURN_ARRAYTYPE_P(result);
6044 }
#define PG_GETARG_ARRAYTYPE_P(n)
Definition: array.h:263
#define PG_RETURN_ARRAYTYPE_P(x)
Definition: array.h:265
static ArrayType * array_fill_internal(ArrayType *dims, ArrayType *lbs, Datum value, bool isnull, Oid elmtype, FunctionCallInfo fcinfo)
Definition: arrayfuncs.c:6064
Oid get_fn_expr_argtype(FmgrInfo *flinfo, int argnum)
Definition: fmgr.c:1910
#define PG_ARGISNULL(n)
Definition: fmgr.h:209
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:268
static struct @150 value

References array_fill_internal(), elog, ereport, errcode(), errmsg(), ERROR, get_fn_expr_argtype(), OidIsValid, PG_ARGISNULL, PG_GETARG_ARRAYTYPE_P, PG_GETARG_DATUM, PG_RETURN_ARRAYTYPE_P, and value.

◆ array_fill_internal()

static ArrayType * array_fill_internal ( ArrayType dims,
ArrayType lbs,
Datum  value,
bool  isnull,
Oid  elmtype,
FunctionCallInfo  fcinfo 
)
static

Definition at line 6064 of file arrayfuncs.c.

6067 {
6068  ArrayType *result;
6069  int *dimv;
6070  int *lbsv;
6071  int ndims;
6072  int nitems;
6073  int deflbs[MAXDIM];
6074  int16 elmlen;
6075  bool elmbyval;
6076  char elmalign;
6077  ArrayMetaState *my_extra;
6078 
6079  /*
6080  * Params checks
6081  */
6082  if (ARR_NDIM(dims) > 1)
6083  ereport(ERROR,
6084  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
6085  errmsg("wrong number of array subscripts"),
6086  errdetail("Dimension array must be one dimensional.")));
6087 
6088  if (array_contains_nulls(dims))
6089  ereport(ERROR,
6090  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
6091  errmsg("dimension values cannot be null")));
6092 
6093  dimv = (int *) ARR_DATA_PTR(dims);
6094  ndims = (ARR_NDIM(dims) > 0) ? ARR_DIMS(dims)[0] : 0;
6095 
6096  if (ndims < 0) /* we do allow zero-dimension arrays */
6097  ereport(ERROR,
6098  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6099  errmsg("invalid number of dimensions: %d", ndims)));
6100  if (ndims > MAXDIM)
6101  ereport(ERROR,
6102  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
6103  errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
6104  ndims, MAXDIM)));
6105 
6106  if (lbs != NULL)
6107  {
6108  if (ARR_NDIM(lbs) > 1)
6109  ereport(ERROR,
6110  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
6111  errmsg("wrong number of array subscripts"),
6112  errdetail("Dimension array must be one dimensional.")));
6113 
6114  if (array_contains_nulls(lbs))
6115  ereport(ERROR,
6116  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
6117  errmsg("dimension values cannot be null")));
6118 
6119  if (ndims != ((ARR_NDIM(lbs) > 0) ? ARR_DIMS(lbs)[0] : 0))
6120  ereport(ERROR,
6121  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
6122  errmsg("wrong number of array subscripts"),
6123  errdetail("Low bound array has different size than dimensions array.")));
6124 
6125  lbsv = (int *) ARR_DATA_PTR(lbs);
6126  }
6127  else
6128  {
6129  int i;
6130 
6131  for (i = 0; i < MAXDIM; i++)
6132  deflbs[i] = 1;
6133 
6134  lbsv = deflbs;
6135  }
6136 
6137  /* This checks for overflow of the array dimensions */
6138  nitems = ArrayGetNItems(ndims, dimv);
6139  ArrayCheckBounds(ndims, dimv, lbsv);
6140 
6141  /* fast track for empty array */
6142  if (nitems <= 0)
6143  return construct_empty_array(elmtype);
6144 
6145  /*
6146  * We arrange to look up info about element type only once per series of
6147  * calls, assuming the element type doesn't change underneath us.
6148  */
6149  my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
6150  if (my_extra == NULL)
6151  {
6152  fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
6153  sizeof(ArrayMetaState));
6154  my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
6155  my_extra->element_type = InvalidOid;
6156  }
6157 
6158  if (my_extra->element_type != elmtype)
6159  {
6160  /* Get info about element type */
6161  get_typlenbyvalalign(elmtype,
6162  &my_extra->typlen,
6163  &my_extra->typbyval,
6164  &my_extra->typalign);
6165  my_extra->element_type = elmtype;
6166  }
6167 
6168  elmlen = my_extra->typlen;
6169  elmbyval = my_extra->typbyval;
6170  elmalign = my_extra->typalign;
6171 
6172  /* compute required space */
6173  if (!isnull)
6174  {
6175  int i;
6176  char *p;
6177  int nbytes;
6178  int totbytes;
6179 
6180  /* make sure data is not toasted */
6181  if (elmlen == -1)
6183 
6184  nbytes = att_addlength_datum(0, elmlen, value);
6185  nbytes = att_align_nominal(nbytes, elmalign);
6186  Assert(nbytes > 0);
6187 
6188  totbytes = nbytes * nitems;
6189 
6190  /* check for overflow of multiplication or total request */
6191  if (totbytes / nbytes != nitems ||
6192  !AllocSizeIsValid(totbytes))
6193  ereport(ERROR,
6194  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
6195  errmsg("array size exceeds the maximum allowed (%d)",
6196  (int) MaxAllocSize)));
6197 
6198  /*
6199  * This addition can't overflow, but it might cause us to go past
6200  * MaxAllocSize. We leave it to palloc to complain in that case.
6201  */
6202  totbytes += ARR_OVERHEAD_NONULLS(ndims);
6203 
6204  result = create_array_envelope(ndims, dimv, lbsv, totbytes,
6205  elmtype, 0);
6206 
6207  p = ARR_DATA_PTR(result);
6208  for (i = 0; i < nitems; i++)
6209  p += ArrayCastAndSet(value, elmlen, elmbyval, elmalign, p);
6210  }
6211  else
6212  {
6213  int nbytes;
6214  int dataoffset;
6215 
6216  dataoffset = ARR_OVERHEAD_WITHNULLS(ndims, nitems);
6217  nbytes = dataoffset;
6218 
6219  result = create_array_envelope(ndims, dimv, lbsv, nbytes,
6220  elmtype, dataoffset);
6221 
6222  /* create_array_envelope already zeroed the bitmap, so we're done */
6223  }
6224 
6225  return result;
6226 }
#define ARR_OVERHEAD_WITHNULLS(ndims, nitems)
Definition: array.h:312
#define ARR_OVERHEAD_NONULLS(ndims)
Definition: array.h:310
bool array_contains_nulls(ArrayType *array)
Definition: arrayfuncs.c:3748
ArrayType * construct_empty_array(Oid elmtype)
Definition: arrayfuncs.c:3561
static ArrayType * create_array_envelope(int ndims, int *dimv, int *lbsv, int nbytes, Oid elmtype, int dataoffset)
Definition: arrayfuncs.c:6047
static int ArrayCastAndSet(Datum src, int typlen, bool typbyval, char typalign, char *dest)
Definition: arrayfuncs.c:4808
void ArrayCheckBounds(int ndim, const int *dims, const int *lb)
Definition: arrayutils.c:117
signed short int16
Definition: c.h:480
int errdetail(const char *fmt,...)
Definition: elog.c:1205
#define PG_DETOAST_DATUM(datum)
Definition: fmgr.h:240
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1168
MemoryContext fn_mcxt
Definition: fmgr.h:65
#define att_align_nominal(cur_offset, attalign)
Definition: tupmacs.h:129
#define att_addlength_datum(cur_offset, attlen, attdatum)
Definition: tupmacs.h:145

References AllocSizeIsValid, ARR_DATA_PTR, ARR_DIMS, ARR_NDIM, ARR_OVERHEAD_NONULLS, ARR_OVERHEAD_WITHNULLS, array_contains_nulls(), ArrayCastAndSet(), ArrayCheckBounds(), ArrayGetNItems(), Assert(), att_addlength_datum, att_align_nominal, construct_empty_array(), create_array_envelope(), ArrayMetaState::element_type, ereport, errcode(), errdetail(), errmsg(), ERROR, FunctionCallInfoBaseData::flinfo, FmgrInfo::fn_extra, FmgrInfo::fn_mcxt, get_typlenbyvalalign(), i, if(), InvalidOid, MaxAllocSize, MAXDIM, MemoryContextAlloc(), nitems, PG_DETOAST_DATUM, PointerGetDatum(), ArrayMetaState::typalign, ArrayMetaState::typbyval, ArrayMetaState::typlen, and value.

Referenced by array_fill(), and array_fill_with_lower_bounds().

◆ array_fill_with_lower_bounds()

Datum array_fill_with_lower_bounds ( PG_FUNCTION_ARGS  )

Definition at line 5971 of file arrayfuncs.c.

5972 {
5973  ArrayType *dims;
5974  ArrayType *lbs;
5975  ArrayType *result;
5976  Oid elmtype;
5977  Datum value;
5978  bool isnull;
5979 
5980  if (PG_ARGISNULL(1) || PG_ARGISNULL(2))
5981  ereport(ERROR,
5982  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
5983  errmsg("dimension array or low bound array cannot be null")));
5984 
5985  dims = PG_GETARG_ARRAYTYPE_P(1);
5986  lbs = PG_GETARG_ARRAYTYPE_P(2);
5987 
5988  if (!PG_ARGISNULL(0))
5989  {
5990  value = PG_GETARG_DATUM(0);
5991  isnull = false;
5992  }
5993  else
5994  {
5995  value = 0;
5996  isnull = true;
5997  }
5998 
5999  elmtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
6000  if (!OidIsValid(elmtype))
6001  elog(ERROR, "could not determine data type of input");
6002 
6003  result = array_fill_internal(dims, lbs, value, isnull, elmtype, fcinfo);
6004  PG_RETURN_ARRAYTYPE_P(result);
6005 }

References array_fill_internal(), elog, ereport, errcode(), errmsg(), ERROR, get_fn_expr_argtype(), OidIsValid, PG_ARGISNULL, PG_GETARG_ARRAYTYPE_P, PG_GETARG_DATUM, PG_RETURN_ARRAYTYPE_P, and value.

◆ array_free_iterator()

void array_free_iterator ( ArrayIterator  iterator)

Definition at line 4740 of file arrayfuncs.c.

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

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

Referenced by array_position_common(), and array_positions().

◆ array_ge()

Datum array_ge ( PG_FUNCTION_ARGS  )

Definition at line 3948 of file arrayfuncs.c.

3949 {
3950  PG_RETURN_BOOL(array_cmp(fcinfo) >= 0);
3951 }
static int array_cmp(FunctionCallInfo fcinfo)
Definition: arrayfuncs.c:3966

References array_cmp(), and PG_RETURN_BOOL.

◆ array_get_element()

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

Definition at line 1820 of file arrayfuncs.c.

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

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

Definition at line 1921 of file arrayfuncs.c.

1926 {
1927  ExpandedArrayHeader *eah;
1928  int i,
1929  ndim,
1930  *dim,
1931  *lb,
1932  offset;
1933  Datum *dvalues;
1934  bool *dnulls;
1935 
1936  eah = (ExpandedArrayHeader *) DatumGetEOHP(arraydatum);
1937  Assert(eah->ea_magic == EA_MAGIC);
1938 
1939  /* sanity-check caller's info against object */
1940  Assert(arraytyplen == -1);
1941  Assert(elmlen == eah->typlen);
1942  Assert(elmbyval == eah->typbyval);
1943  Assert(elmalign == eah->typalign);
1944 
1945  ndim = eah->ndims;
1946  dim = eah->dims;
1947  lb = eah->lbound;
1948 
1949  /*
1950  * Return NULL for invalid subscript
1951  */
1952  if (ndim != nSubscripts || ndim <= 0 || ndim > MAXDIM)
1953  {
1954  *isNull = true;
1955  return (Datum) 0;
1956  }
1957  for (i = 0; i < ndim; i++)
1958  {
1959  if (indx[i] < lb[i] || indx[i] >= (dim[i] + lb[i]))
1960  {
1961  *isNull = true;
1962  return (Datum) 0;
1963  }
1964  }
1965 
1966  /*
1967  * Calculate the element number
1968  */
1969  offset = ArrayGetOffset(nSubscripts, dim, lb, indx);
1970 
1971  /*
1972  * Deconstruct array if we didn't already. Note that we apply this even
1973  * if the input is nominally read-only: it should be safe enough.
1974  */
1976 
1977  dvalues = eah->dvalues;
1978  dnulls = eah->dnulls;
1979 
1980  /*
1981  * Check for NULL array element
1982  */
1983  if (dnulls && dnulls[offset])
1984  {
1985  *isNull = true;
1986  return (Datum) 0;
1987  }
1988 
1989  /*
1990  * OK, get the element. It's OK to return a pass-by-ref value as a
1991  * pointer into the expanded array, for the same reason that regular
1992  * array_get_element can return a pointer into flat arrays: the value is
1993  * assumed not to change for as long as the Datum reference can exist.
1994  */
1995  *isNull = false;
1996  return dvalues[offset];
1997 }
#define EA_MAGIC
Definition: array.h:113
ExpandedObjectHeader * DatumGetEOHP(Datum d)
Definition: expandeddatum.c:29

References ArrayGetOffset(), Assert(), DatumGetEOHP(), deconstruct_expanded_array(), ExpandedArrayHeader::dims, ExpandedArrayHeader::dnulls, ExpandedArrayHeader::dvalues, EA_MAGIC, ExpandedArrayHeader::ea_magic, i, ExpandedArrayHeader::lbound, MAXDIM, ExpandedArrayHeader::ndims, ExpandedArrayHeader::typalign, ExpandedArrayHeader::typbyval, and ExpandedArrayHeader::typlen.

Referenced by array_get_element().

◆ array_get_isnull()

static bool array_get_isnull ( const bits8 nullbitmap,
int  offset 
)
static

Definition at line 4762 of file arrayfuncs.c.

4763 {
4764  if (nullbitmap == NULL)
4765  return false; /* assume not null */
4766  if (nullbitmap[offset / 8] & (1 << (offset % 8)))
4767  return false; /* not null */
4768  return true;
4769 }

Referenced by array_get_element(), array_iterate(), array_set_element(), and array_slice_size().

◆ array_get_slice()

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

Definition at line 2030 of file arrayfuncs.c.

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

Datum array_gt ( PG_FUNCTION_ARGS  )

Definition at line 3936 of file arrayfuncs.c.

3937 {
3938  PG_RETURN_BOOL(array_cmp(fcinfo) > 0);
3939 }

References array_cmp(), and PG_RETURN_BOOL.

◆ array_in()

Datum array_in ( PG_FUNCTION_ARGS  )

Definition at line 179 of file arrayfuncs.c.

180 {
181  char *string = PG_GETARG_CSTRING(0); /* external form */
182  Oid element_type = PG_GETARG_OID(1); /* type of an array
183  * element */
184  int32 typmod = PG_GETARG_INT32(2); /* typmod for array elements */
185  Node *escontext = fcinfo->context;
186  int typlen;
187  bool typbyval;
188  char typalign;
189  char typdelim;
190  Oid typioparam;
191  char *p;
192  int nitems;
193  Datum *values;
194  bool *nulls;
195  bool hasnulls;
196  int32 nbytes;
197  int32 dataoffset;
198  ArrayType *retval;
199  int ndim,
200  dim[MAXDIM],
201  lBound[MAXDIM];
202  ArrayMetaState *my_extra;
203 
204  /*
205  * We arrange to look up info about element type, including its input
206  * conversion proc, only once per series of calls, assuming the element
207  * type doesn't change underneath us.
208  */
209  my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
210  if (my_extra == NULL)
211  {
212  fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
213  sizeof(ArrayMetaState));
214  my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
215  my_extra->element_type = ~element_type;
216  }
217 
218  if (my_extra->element_type != element_type)
219  {
220  /*
221  * Get info about element type, including its input conversion proc
222  */
223  get_type_io_data(element_type, IOFunc_input,
224  &my_extra->typlen, &my_extra->typbyval,
225  &my_extra->typalign, &my_extra->typdelim,
226  &my_extra->typioparam, &my_extra->typiofunc);
227  fmgr_info_cxt(my_extra->typiofunc, &my_extra->proc,
228  fcinfo->flinfo->fn_mcxt);
229  my_extra->element_type = element_type;
230  }
231  typlen = my_extra->typlen;
232  typbyval = my_extra->typbyval;
233  typalign = my_extra->typalign;
234  typdelim = my_extra->typdelim;
235  typioparam = my_extra->typioparam;
236 
237  /*
238  * Initialize dim[] and lBound[] for ReadArrayStr, in case there is no
239  * explicit dimension info. (If there is, ReadArrayDimensions will
240  * overwrite this.)
241  */
242  for (int i = 0; i < MAXDIM; i++)
243  {
244  dim[i] = -1; /* indicates "not yet known" */
245  lBound[i] = 1; /* default lower bound */
246  }
247 
248  /*
249  * Start processing the input string.
250  *
251  * If the input string starts with dimension info, read and use that.
252  * Otherwise, we'll determine the dimensions during ReadArrayStr.
253  */
254  p = string;
255  if (!ReadArrayDimensions(&p, &ndim, dim, lBound, string, escontext))
256  return (Datum) 0;
257 
258  if (ndim == 0)
259  {
260  /* No array dimensions, so next character should be a left brace */
261  if (*p != '{')
262  ereturn(escontext, (Datum) 0,
263  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
264  errmsg("malformed array literal: \"%s\"", string),
265  errdetail("Array value must start with \"{\" or dimension information.")));
266  }
267  else
268  {
269  /* If array dimensions are given, expect '=' operator */
270  if (strncmp(p, ASSGN, strlen(ASSGN)) != 0)
271  ereturn(escontext, (Datum) 0,
272  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
273  errmsg("malformed array literal: \"%s\"", string),
274  errdetail("Missing \"%s\" after array dimensions.",
275  ASSGN)));
276  p += strlen(ASSGN);
277  /* Allow whitespace after it */
278  while (scanner_isspace(*p))
279  p++;
280 
281  if (*p != '{')
282  ereturn(escontext, (Datum) 0,
283  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
284  errmsg("malformed array literal: \"%s\"", string),
285  errdetail("Array contents must start with \"{\".")));
286  }
287 
288  /* Parse the value part, in the curly braces: { ... } */
289  if (!ReadArrayStr(&p,
290  &my_extra->proc, typioparam, typmod,
291  typdelim,
292  typlen, typbyval, typalign,
293  &ndim,
294  dim,
295  &nitems,
296  &values, &nulls,
297  string,
298  escontext))
299  return (Datum) 0;
300 
301  /* only whitespace is allowed after the closing brace */
302  while (*p)
303  {
304  if (!scanner_isspace(*p++))
305  ereturn(escontext, (Datum) 0,
306  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
307  errmsg("malformed array literal: \"%s\"", string),
308  errdetail("Junk after closing right brace.")));
309  }
310 
311  /* Empty array? */
312  if (nitems == 0)
314 
315  /*
316  * Check for nulls, compute total data space needed
317  */
318  hasnulls = false;
319  nbytes = 0;
320  for (int i = 0; i < nitems; i++)
321  {
322  if (nulls[i])
323  hasnulls = true;
324  else
325  {
326  /* let's just make sure data is not toasted */
327  if (typlen == -1)
329  nbytes = att_addlength_datum(nbytes, typlen, values[i]);
330  nbytes = att_align_nominal(nbytes, typalign);
331  /* check for overflow of total request */
332  if (!AllocSizeIsValid(nbytes))
333  ereturn(escontext, (Datum) 0,
334  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
335  errmsg("array size exceeds the maximum allowed (%d)",
336  (int) MaxAllocSize)));
337  }
338  }
339  if (hasnulls)
340  {
341  dataoffset = ARR_OVERHEAD_WITHNULLS(ndim, nitems);
342  nbytes += dataoffset;
343  }
344  else
345  {
346  dataoffset = 0; /* marker for no null bitmap */
347  nbytes += ARR_OVERHEAD_NONULLS(ndim);
348  }
349 
350  /*
351  * Construct the final array datum
352  */
353  retval = (ArrayType *) palloc0(nbytes);
354  SET_VARSIZE(retval, nbytes);
355  retval->ndim = ndim;
356  retval->dataoffset = dataoffset;
357 
358  /*
359  * This comes from the array's pg_type.typelem (which points to the base
360  * data type's pg_type.oid) and stores system oids in user tables. This
361  * oid must be preserved by binary upgrades.
362  */
363  retval->elemtype = element_type;
364  memcpy(ARR_DIMS(retval), dim, ndim * sizeof(int));
365  memcpy(ARR_LBOUND(retval), lBound, ndim * sizeof(int));
366 
367  CopyArrayEls(retval,
368  values, nulls, nitems,
369  typlen, typbyval, typalign,
370  true);
371 
372  pfree(values);
373  pfree(nulls);
374 
375  PG_RETURN_ARRAYTYPE_P(retval);
376 }
static bool ReadArrayStr(char **srcptr, FmgrInfo *inputproc, Oid typioparam, int32 typmod, char typdelim, int typlen, bool typbyval, char typalign, int *ndim_p, int *dim, int *nitems_p, Datum **values_p, bool **nulls_p, const char *origStr, Node *escontext)
Definition: arrayfuncs.c:579
static bool ReadArrayDimensions(char **srcptr, int *ndim_p, int *dim, int *lBound, const char *origStr, Node *escontext)
Definition: arrayfuncs.c:402
void CopyArrayEls(ArrayType *array, Datum *values, bool *nulls, int nitems, int typlen, bool typbyval, char typalign, bool freedata)
Definition: arrayfuncs.c:961
#define ASSGN
Definition: arrayfuncs.c:48
static Datum values[MAXATTR]
Definition: bootstrap.c:152
#define ereturn(context, dummy_value,...)
Definition: elog.h:276
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:137
#define PG_GETARG_OID(n)
Definition: fmgr.h:275
#define PG_GETARG_CSTRING(n)
Definition: fmgr.h:277
#define PG_GETARG_INT32(n)
Definition: fmgr.h:269
void get_type_io_data(Oid typid, IOFuncSelector which_func, int16 *typlen, bool *typbyval, char *typalign, char *typdelim, Oid *typioparam, Oid *func)
Definition: lsyscache.c:2281
@ IOFunc_input
Definition: lsyscache.h:35
char string[11]
Definition: preproc-type.c:52
bool scanner_isspace(char ch)
Definition: scansup.c:117
Oid typioparam
Definition: array.h:243
Oid typiofunc
Definition: array.h:244
FmgrInfo proc
Definition: array.h:245
char typdelim
Definition: array.h:242
Definition: nodes.h:129

References AllocSizeIsValid, ARR_DIMS, ARR_LBOUND, ARR_OVERHEAD_NONULLS, ARR_OVERHEAD_WITHNULLS, ASSGN, att_addlength_datum, att_align_nominal, construct_empty_array(), CopyArrayEls(), ArrayType::dataoffset, ArrayMetaState::element_type, ArrayType::elemtype, ereturn, errcode(), errdetail(), errmsg(), fmgr_info_cxt(), FmgrInfo::fn_mcxt, get_type_io_data(), i, if(), IOFunc_input, MaxAllocSize, MAXDIM, MemoryContextAlloc(), ArrayType::ndim, nitems, palloc0(), pfree(), PG_DETOAST_DATUM, PG_GETARG_CSTRING, PG_GETARG_INT32, PG_GETARG_OID, PG_RETURN_ARRAYTYPE_P, PointerGetDatum(), ArrayMetaState::proc, ReadArrayDimensions(), ReadArrayStr(), scanner_isspace(), SET_VARSIZE, typalign, ArrayMetaState::typalign, ArrayMetaState::typbyval, ArrayMetaState::typdelim, ArrayMetaState::typiofunc, ArrayMetaState::typioparam, ArrayMetaState::typlen, and values.

Referenced by extract_variadic_args().

◆ array_insert_slice()

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 
)
static

Definition at line 5151 of file arrayfuncs.c.

5162 {
5163  char *destPtr = ARR_DATA_PTR(destArray);
5164  char *origPtr = ARR_DATA_PTR(origArray);
5165  char *srcPtr = ARR_DATA_PTR(srcArray);
5166  bits8 *destBitmap = ARR_NULLBITMAP(destArray);
5167  bits8 *origBitmap = ARR_NULLBITMAP(origArray);
5168  bits8 *srcBitmap = ARR_NULLBITMAP(srcArray);
5169  int orignitems = ArrayGetNItems(ARR_NDIM(origArray),
5170  ARR_DIMS(origArray));
5171  int dest_offset,
5172  orig_offset,
5173  src_offset,
5174  prod[MAXDIM],
5175  span[MAXDIM],
5176  dist[MAXDIM],
5177  indx[MAXDIM];
5178  int i,
5179  j,
5180  inc;
5181 
5182  dest_offset = ArrayGetOffset(ndim, dim, lb, st);
5183  /* copy items before the slice start */
5184  inc = array_copy(destPtr, dest_offset,
5185  origPtr, 0, origBitmap,
5186  typlen, typbyval, typalign);
5187  destPtr += inc;
5188  origPtr += inc;
5189  if (destBitmap)
5190  array_bitmap_copy(destBitmap, 0, origBitmap, 0, dest_offset);
5191  orig_offset = dest_offset;
5192  mda_get_prod(ndim, dim, prod);
5193  mda_get_range(ndim, span, st, endp);
5194  mda_get_offset_values(ndim, dist, prod, span);
5195  for (i = 0; i < ndim; i++)
5196  indx[i] = 0;
5197  src_offset = 0;
5198  j = ndim - 1;
5199  do
5200  {
5201  /* Copy/advance over elements between here and next part of slice */
5202  if (dist[j])
5203  {
5204  inc = array_copy(destPtr, dist[j],
5205  origPtr, orig_offset, origBitmap,
5206  typlen, typbyval, typalign);
5207  destPtr += inc;
5208  origPtr += inc;
5209  if (destBitmap)
5210  array_bitmap_copy(destBitmap, dest_offset,
5211  origBitmap, orig_offset,
5212  dist[j]);
5213  dest_offset += dist[j];
5214  orig_offset += dist[j];
5215  }
5216  /* Copy new element at this slice position */
5217  inc = array_copy(destPtr, 1,
5218  srcPtr, src_offset, srcBitmap,
5219  typlen, typbyval, typalign);
5220  if (destBitmap)
5221  array_bitmap_copy(destBitmap, dest_offset,
5222  srcBitmap, src_offset,
5223  1);
5224  destPtr += inc;
5225  srcPtr += inc;
5226  dest_offset++;
5227  src_offset++;
5228  /* Advance over old element at this slice position */
5229  origPtr = array_seek(origPtr, orig_offset, origBitmap, 1,
5230  typlen, typbyval, typalign);
5231  orig_offset++;
5232  } while ((j = mda_next_tuple(ndim, indx, span)) != -1);
5233 
5234  /* don't miss any data at the end */
5235  array_copy(destPtr, orignitems - orig_offset,
5236  origPtr, orig_offset, origBitmap,
5237  typlen, typbyval, typalign);
5238  if (destBitmap)
5239  array_bitmap_copy(destBitmap, dest_offset,
5240  origBitmap, orig_offset,
5241  orignitems - orig_offset);
5242 }

References ARR_DATA_PTR, ARR_DIMS, ARR_NDIM, ARR_NULLBITMAP, array_bitmap_copy(), array_copy(), array_seek(), ArrayGetNItems(), ArrayGetOffset(), i, j, MAXDIM, mda_get_offset_values(), mda_get_prod(), mda_get_range(), mda_next_tuple(), and typalign.

Referenced by array_set_slice().

◆ array_iterate()

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

Definition at line 4657 of file arrayfuncs.c.

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

Datum array_larger ( PG_FUNCTION_ARGS  )

Definition at line 5866 of file arrayfuncs.c.

5867 {
5868  if (array_cmp(fcinfo) > 0)
5870  else
5872 }
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:353

References array_cmp(), PG_GETARG_DATUM, and PG_RETURN_DATUM.

◆ array_le()

Datum array_le ( PG_FUNCTION_ARGS  )

Definition at line 3942 of file arrayfuncs.c.

3943 {
3944  PG_RETURN_BOOL(array_cmp(fcinfo) <= 0);
3945 }

References array_cmp(), and PG_RETURN_BOOL.

◆ array_length()

Datum array_length ( PG_FUNCTION_ARGS  )

Definition at line 1763 of file arrayfuncs.c.

1764 {
1766  int reqdim = PG_GETARG_INT32(1);
1767  int *dimv;
1768  int result;
1769 
1770  /* Sanity check: does it look like an array at all? */
1771  if (AARR_NDIM(v) <= 0 || AARR_NDIM(v) > MAXDIM)
1772  PG_RETURN_NULL();
1773 
1774  /* Sanity check: was the requested dim valid */
1775  if (reqdim <= 0 || reqdim > AARR_NDIM(v))
1776  PG_RETURN_NULL();
1777 
1778  dimv = AARR_DIMS(v);
1779 
1780  result = dimv[reqdim - 1];
1781 
1782  PG_RETURN_INT32(result);
1783 }

References AARR_DIMS, AARR_NDIM, MAXDIM, PG_GETARG_ANY_ARRAY_P, PG_GETARG_INT32, PG_RETURN_INT32, and PG_RETURN_NULL.

Referenced by trim_array().

◆ array_lower()

Datum array_lower ( PG_FUNCTION_ARGS  )

Definition at line 1706 of file arrayfuncs.c.

1707 {
1709  int reqdim = PG_GETARG_INT32(1);
1710  int *lb;
1711  int result;
1712 
1713  /* Sanity check: does it look like an array at all? */
1714  if (AARR_NDIM(v) <= 0 || AARR_NDIM(v) > MAXDIM)
1715  PG_RETURN_NULL();
1716 
1717  /* Sanity check: was the requested dim valid */
1718  if (reqdim <= 0 || reqdim > AARR_NDIM(v))
1719  PG_RETURN_NULL();
1720 
1721  lb = AARR_LBOUND(v);
1722  result = lb[reqdim - 1];
1723 
1724  PG_RETURN_INT32(result);
1725 }

References AARR_LBOUND, AARR_NDIM, MAXDIM, PG_GETARG_ANY_ARRAY_P, PG_GETARG_INT32, PG_RETURN_INT32, and PG_RETURN_NULL.

◆ array_lt()

Datum array_lt ( PG_FUNCTION_ARGS  )

Definition at line 3930 of file arrayfuncs.c.

3931 {
3932  PG_RETURN_BOOL(array_cmp(fcinfo) < 0);
3933 }

References array_cmp(), and PG_RETURN_BOOL.

◆ array_map()

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

Definition at line 3194 of file arrayfuncs.c.

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

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_ndims()

Datum array_ndims ( PG_FUNCTION_ARGS  )

Definition at line 1652 of file arrayfuncs.c.

1653 {
1655 
1656  /* Sanity check: does it look like an array at all? */
1657  if (AARR_NDIM(v) <= 0 || AARR_NDIM(v) > MAXDIM)
1658  PG_RETURN_NULL();
1659 
1661 }

References AARR_NDIM, MAXDIM, PG_GETARG_ANY_ARRAY_P, PG_RETURN_INT32, and PG_RETURN_NULL.

◆ array_ne()

Datum array_ne ( PG_FUNCTION_ARGS  )

Definition at line 3924 of file arrayfuncs.c.

3925 {
3927 }
Datum array_eq(PG_FUNCTION_ARGS)
Definition: arrayfuncs.c:3795

References array_eq(), DatumGetBool(), and PG_RETURN_BOOL.

◆ array_nelems_size()

static int array_nelems_size ( char *  ptr,
int  offset,
bits8 nullbitmap,
int  nitems,
int  typlen,
bool  typbyval,
char  typalign 
)
static

Definition at line 4895 of file arrayfuncs.c.

4897 {
4898  return array_seek(ptr, offset, nullbitmap, nitems,
4899  typlen, typbyval, typalign) - ptr;
4900 }

References array_seek(), nitems, and typalign.

Referenced by array_copy(), and array_set_slice().

◆ array_out()

Datum array_out ( PG_FUNCTION_ARGS  )

Definition at line 1016 of file arrayfuncs.c.

1017 {
1019  Oid element_type = AARR_ELEMTYPE(v);
1020  int typlen;
1021  bool typbyval;
1022  char typalign;
1023  char typdelim;
1024  char *p,
1025  *tmp,
1026  *retval,
1027  **values,
1028  dims_str[(MAXDIM * 33) + 2];
1029 
1030  /*
1031  * 33 per dim since we assume 15 digits per number + ':' +'[]'
1032  *
1033  * +2 allows for assignment operator + trailing null
1034  */
1035  bool *needquotes,
1036  needdims = false;
1037  size_t overall_length;
1038  int nitems,
1039  i,
1040  j,
1041  k,
1042  indx[MAXDIM];
1043  int ndim,
1044  *dims,
1045  *lb;
1046  array_iter iter;
1047  ArrayMetaState *my_extra;
1048 
1049  /*
1050  * We arrange to look up info about element type, including its output
1051  * conversion proc, only once per series of calls, assuming the element
1052  * type doesn't change underneath us.
1053  */
1054  my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
1055  if (my_extra == NULL)
1056  {
1057  fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
1058  sizeof(ArrayMetaState));
1059  my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
1060  my_extra->element_type = ~element_type;
1061  }
1062 
1063  if (my_extra->element_type != element_type)
1064  {
1065  /*
1066  * Get info about element type, including its output conversion proc
1067  */
1068  get_type_io_data(element_type, IOFunc_output,
1069  &my_extra->typlen, &my_extra->typbyval,
1070  &my_extra->typalign, &my_extra->typdelim,
1071  &my_extra->typioparam, &my_extra->typiofunc);
1072  fmgr_info_cxt(my_extra->typiofunc, &my_extra->proc,
1073  fcinfo->flinfo->fn_mcxt);
1074  my_extra->element_type = element_type;
1075  }
1076  typlen = my_extra->typlen;
1077  typbyval = my_extra->typbyval;
1078  typalign = my_extra->typalign;
1079  typdelim = my_extra->typdelim;
1080 
1081  ndim = AARR_NDIM(v);
1082  dims = AARR_DIMS(v);
1083  lb = AARR_LBOUND(v);
1084  nitems = ArrayGetNItems(ndim, dims);
1085 
1086  if (nitems == 0)
1087  {
1088  retval = pstrdup("{}");
1089  PG_RETURN_CSTRING(retval);
1090  }
1091 
1092  /*
1093  * we will need to add explicit dimensions if any dimension has a lower
1094  * bound other than one
1095  */
1096  for (i = 0; i < ndim; i++)
1097  {
1098  if (lb[i] != 1)
1099  {
1100  needdims = true;
1101  break;
1102  }
1103  }
1104 
1105  /*
1106  * Convert all values to string form, count total space needed (including
1107  * any overhead such as escaping backslashes), and detect whether each
1108  * item needs double quotes.
1109  */
1110  values = (char **) palloc(nitems * sizeof(char *));
1111  needquotes = (bool *) palloc(nitems * sizeof(bool));
1112  overall_length = 0;
1113 
1114  array_iter_setup(&iter, v);
1115 
1116  for (i = 0; i < nitems; i++)
1117  {
1118  Datum itemvalue;
1119  bool isnull;
1120  bool needquote;
1121 
1122  /* Get source element, checking for NULL */
1123  itemvalue = array_iter_next(&iter, &isnull, i,
1124  typlen, typbyval, typalign);
1125 
1126  if (isnull)
1127  {
1128  values[i] = pstrdup("NULL");
1129  overall_length += 4;
1130  needquote = false;
1131  }
1132  else
1133  {
1134  values[i] = OutputFunctionCall(&my_extra->proc, itemvalue);
1135 
1136  /* count data plus backslashes; detect chars needing quotes */
1137  if (values[i][0] == '\0')
1138  needquote = true; /* force quotes for empty string */
1139  else if (pg_strcasecmp(values[i], "NULL") == 0)
1140  needquote = true; /* force quotes for literal NULL */
1141  else
1142  needquote = false;
1143 
1144  for (tmp = values[i]; *tmp != '\0'; tmp++)
1145  {
1146  char ch = *tmp;
1147 
1148  overall_length += 1;
1149  if (ch == '"' || ch == '\\')
1150  {
1151  needquote = true;
1152  overall_length += 1;
1153  }
1154  else if (ch == '{' || ch == '}' || ch == typdelim ||
1155  scanner_isspace(ch))
1156  needquote = true;
1157  }
1158  }
1159 
1160  needquotes[i] = needquote;
1161 
1162  /* Count the pair of double quotes, if needed */
1163  if (needquote)
1164  overall_length += 2;
1165  /* and the comma (or other typdelim delimiter) */
1166  overall_length += 1;
1167  }
1168 
1169  /*
1170  * The very last array element doesn't have a typdelim delimiter after it,
1171  * but that's OK; that space is needed for the trailing '\0'.
1172  *
1173  * Now count total number of curly brace pairs in output string.
1174  */
1175  for (i = j = 0, k = 1; i < ndim; i++)
1176  {
1177  j += k, k *= dims[i];
1178  }
1179  overall_length += 2 * j;
1180 
1181  /* Format explicit dimensions if required */
1182  dims_str[0] = '\0';
1183  if (needdims)
1184  {
1185  char *ptr = dims_str;
1186 
1187  for (i = 0; i < ndim; i++)
1188  {
1189  sprintf(ptr, "[%d:%d]", lb[i], lb[i] + dims[i] - 1);
1190  ptr += strlen(ptr);
1191  }
1192  *ptr++ = *ASSGN;
1193  *ptr = '\0';
1194  overall_length += ptr - dims_str;
1195  }
1196 
1197  /* Now construct the output string */
1198  retval = (char *) palloc(overall_length);
1199  p = retval;
1200 
1201 #define APPENDSTR(str) (strcpy(p, (str)), p += strlen(p))
1202 #define APPENDCHAR(ch) (*p++ = (ch), *p = '\0')
1203 
1204  if (needdims)
1205  APPENDSTR(dims_str);
1206  APPENDCHAR('{');
1207  for (i = 0; i < ndim; i++)
1208  indx[i] = 0;
1209  j = 0;
1210  k = 0;
1211  do
1212  {
1213  for (i = j; i < ndim - 1; i++)
1214  APPENDCHAR('{');
1215 
1216  if (needquotes[k])
1217  {
1218  APPENDCHAR('"');
1219  for (tmp = values[k]; *tmp; tmp++)
1220  {
1221  char ch = *tmp;
1222 
1223  if (ch == '"' || ch == '\\')
1224  *p++ = '\\';
1225  *p++ = ch;
1226  }
1227  *p = '\0';
1228  APPENDCHAR('"');
1229  }
1230  else
1231  APPENDSTR(values[k]);
1232  pfree(values[k++]);
1233 
1234  for (i = ndim - 1; i >= 0; i--)
1235  {
1236  if (++(indx[i]) < dims[i])
1237  {
1238  APPENDCHAR(typdelim);
1239  break;
1240  }
1241  else
1242  {
1243  indx[i] = 0;
1244  APPENDCHAR('}');
1245  }
1246  }
1247  j = i;
1248  } while (j != -1);
1249 
1250 #undef APPENDSTR
1251 #undef APPENDCHAR
1252 
1253  /* Assert that we calculated the string length accurately */
1254  Assert(overall_length == (p - retval + 1));
1255 
1256  pfree(values);
1257  pfree(needquotes);
1258 
1259  PG_RETURN_CSTRING(retval);
1260 }
#define APPENDSTR(str)
#define APPENDCHAR(ch)
char * OutputFunctionCall(FmgrInfo *flinfo, Datum val)
Definition: fmgr.c:1683
#define PG_RETURN_CSTRING(x)
Definition: fmgr.h:362
@ IOFunc_output
Definition: lsyscache.h:36
char * pstrdup(const char *in)
Definition: mcxt.c:1683
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36

References AARR_DIMS, AARR_ELEMTYPE, AARR_LBOUND, AARR_NDIM, APPENDCHAR, APPENDSTR, array_iter_next(), array_iter_setup(), ArrayGetNItems(), Assert(), ASSGN, ArrayMetaState::element_type, fmgr_info_cxt(), FmgrInfo::fn_mcxt, get_type_io_data(), i, if(), IOFunc_output, j, MAXDIM, MemoryContextAlloc(), nitems, OutputFunctionCall(), palloc(), pfree(), PG_GETARG_ANY_ARRAY_P, PG_RETURN_CSTRING, pg_strcasecmp(), ArrayMetaState::proc, pstrdup(), scanner_isspace(), sprintf, typalign, ArrayMetaState::typalign, ArrayMetaState::typbyval, ArrayMetaState::typdelim, ArrayMetaState::typiofunc, ArrayMetaState::typioparam, ArrayMetaState::typlen, and values.

Referenced by anyarray_out(), and anycompatiblearray_out().

◆ array_recv()

Datum array_recv ( PG_FUNCTION_ARGS  )

Definition at line 1271 of file arrayfuncs.c.

1272 {
1274  Oid spec_element_type = PG_GETARG_OID(1); /* type of an array
1275  * element */
1276  int32 typmod = PG_GETARG_INT32(2); /* typmod for array elements */
1277  Oid element_type;
1278  int typlen;
1279  bool typbyval;
1280  char typalign;
1281  Oid typioparam;
1282  int i,
1283  nitems;
1284  Datum *dataPtr;
1285  bool *nullsPtr;
1286  bool hasnulls;
1287  int32 nbytes;
1288  int32 dataoffset;
1289  ArrayType *retval;
1290  int ndim,
1291  flags,
1292  dim[MAXDIM],
1293  lBound[MAXDIM];
1294  ArrayMetaState *my_extra;
1295 
1296  /* Get the array header information */
1297  ndim = pq_getmsgint(buf, 4);
1298  if (ndim < 0) /* we do allow zero-dimension arrays */
1299  ereport(ERROR,
1300  (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
1301  errmsg("invalid number of dimensions: %d", ndim)));
1302  if (ndim > MAXDIM)
1303  ereport(ERROR,
1304  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1305  errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
1306  ndim, MAXDIM)));
1307 
1308  flags = pq_getmsgint(buf, 4);
1309  if (flags != 0 && flags != 1)
1310  ereport(ERROR,
1311  (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
1312  errmsg("invalid array flags")));
1313 
1314  /* Check element type recorded in the data */
1315  element_type = pq_getmsgint(buf, sizeof(Oid));
1316 
1317  /*
1318  * From a security standpoint, it doesn't matter whether the input's
1319  * element type matches what we expect: the element type's receive
1320  * function has to be robust enough to cope with invalid data. However,
1321  * from a user-friendliness standpoint, it's nicer to complain about type
1322  * mismatches than to throw "improper binary format" errors. But there's
1323  * a problem: only built-in types have OIDs that are stable enough to
1324  * believe that a mismatch is a real issue. So complain only if both OIDs
1325  * are in the built-in range. Otherwise, carry on with the element type
1326  * we "should" be getting.
1327  */
1328  if (element_type != spec_element_type)
1329  {
1330  if (element_type < FirstGenbkiObjectId &&
1331  spec_element_type < FirstGenbkiObjectId)
1332  ereport(ERROR,
1333  (errcode(ERRCODE_DATATYPE_MISMATCH),
1334  errmsg("binary data has array element type %u (%s) instead of expected %u (%s)",
1335  element_type,
1336  format_type_extended(element_type, -1,
1338  spec_element_type,
1339  format_type_extended(spec_element_type, -1,
1341  element_type = spec_element_type;
1342  }
1343 
1344  for (i = 0; i < ndim; i++)
1345  {
1346  dim[i] = pq_getmsgint(buf, 4);
1347  lBound[i] = pq_getmsgint(buf, 4);
1348  }
1349 
1350  /* This checks for overflow of array dimensions */
1351  nitems = ArrayGetNItems(ndim, dim);
1352  ArrayCheckBounds(ndim, dim, lBound);
1353 
1354  /*
1355  * We arrange to look up info about element type, including its receive
1356  * conversion proc, only once per series of calls, assuming the element
1357  * type doesn't change underneath us.
1358  */
1359  my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
1360  if (my_extra == NULL)
1361  {
1362  fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
1363  sizeof(ArrayMetaState));
1364  my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
1365  my_extra->element_type = ~element_type;
1366  }
1367 
1368  if (my_extra->element_type != element_type)
1369  {
1370  /* Get info about element type, including its receive proc */
1371  get_type_io_data(element_type, IOFunc_receive,
1372  &my_extra->typlen, &my_extra->typbyval,
1373  &my_extra->typalign, &my_extra->typdelim,
1374  &my_extra->typioparam, &my_extra->typiofunc);
1375  if (!OidIsValid(my_extra->typiofunc))
1376  ereport(ERROR,
1377  (errcode(ERRCODE_UNDEFINED_FUNCTION),
1378  errmsg("no binary input function available for type %s",
1379  format_type_be(element_type))));
1380  fmgr_info_cxt(my_extra->typiofunc, &my_extra->proc,
1381  fcinfo->flinfo->fn_mcxt);
1382  my_extra->element_type = element_type;
1383  }
1384 
1385  if (nitems == 0)
1386  {
1387  /* Return empty array ... but not till we've validated element_type */
1389  }
1390 
1391  typlen = my_extra->typlen;
1392  typbyval = my_extra->typbyval;
1393  typalign = my_extra->typalign;
1394  typioparam = my_extra->typioparam;
1395 
1396  dataPtr = (Datum *) palloc(nitems * sizeof(Datum));
1397  nullsPtr = (bool *) palloc(nitems * sizeof(bool));
1399  &my_extra->proc, typioparam, typmod,
1400  typlen, typbyval, typalign,
1401  dataPtr, nullsPtr,
1402  &hasnulls, &nbytes);
1403  if (hasnulls)
1404  {
1405  dataoffset = ARR_OVERHEAD_WITHNULLS(ndim, nitems);
1406  nbytes += dataoffset;
1407  }
1408  else
1409  {
1410  dataoffset = 0; /* marker for no null bitmap */
1411  nbytes += ARR_OVERHEAD_NONULLS(ndim);
1412  }
1413  retval = (ArrayType *) palloc0(nbytes);
1414  SET_VARSIZE(retval, nbytes);
1415  retval->ndim = ndim;
1416  retval->dataoffset = dataoffset;
1417  retval->elemtype = element_type;
1418  memcpy(ARR_DIMS(retval), dim, ndim * sizeof(int));
1419  memcpy(ARR_LBOUND(retval), lBound, ndim * sizeof(int));
1420 
1421  CopyArrayEls(retval,
1422  dataPtr, nullsPtr, nitems,
1423  typlen, typbyval, typalign,
1424  true);
1425 
1426  pfree(dataPtr);
1427  pfree(nullsPtr);
1428 
1429  PG_RETURN_ARRAYTYPE_P(retval);
1430 }
static void ReadArrayBinary(StringInfo buf, int nitems, FmgrInfo *receiveproc, Oid typioparam, int32 typmod, int typlen, bool typbyval, char typalign, Datum *values, bool *nulls, bool *hasnulls, int32 *nbytes)
Definition: arrayfuncs.c:1454
#define FORMAT_TYPE_ALLOW_INVALID
Definition: builtins.h:125
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
char * format_type_extended(Oid type_oid, int32 typemod, bits16 flags)
Definition: format_type.c:112
@ IOFunc_receive
Definition: lsyscache.h:37
unsigned int pq_getmsgint(StringInfo msg, int b)
Definition: pqformat.c:415
StringInfoData * StringInfo
Definition: stringinfo.h:54
#define FirstGenbkiObjectId
Definition: transam.h:195

References ARR_DIMS, ARR_LBOUND, ARR_OVERHEAD_NONULLS, ARR_OVERHEAD_WITHNULLS, ArrayCheckBounds(), ArrayGetNItems(), buf, construct_empty_array(), CopyArrayEls(), ArrayType::dataoffset, ArrayMetaState::element_type, ArrayType::elemtype, ereport, errcode(), errmsg(), ERROR, FirstGenbkiObjectId, fmgr_info_cxt(), FmgrInfo::fn_mcxt, FORMAT_TYPE_ALLOW_INVALID, format_type_be(), format_type_extended(), get_type_io_data(), i, if(), IOFunc_receive, MAXDIM, MemoryContextAlloc(), ArrayType::ndim, nitems, OidIsValid, palloc(), palloc0(), pfree(), PG_GETARG_INT32, PG_GETARG_OID, PG_GETARG_POINTER, PG_RETURN_ARRAYTYPE_P, pq_getmsgint(), ArrayMetaState::proc, ReadArrayBinary(), SET_VARSIZE, typalign, ArrayMetaState::typalign, ArrayMetaState::typbyval, ArrayMetaState::typdelim, ArrayMetaState::typiofunc, ArrayMetaState::typioparam, and ArrayMetaState::typlen.

Referenced by int2vectorrecv(), and oidvectorrecv().

◆ array_ref()

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

Definition at line 3139 of file arrayfuncs.c.

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

References array_get_element(), and PointerGetDatum().

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

◆ array_remove()

Datum array_remove ( PG_FUNCTION_ARGS  )

Definition at line 6618 of file arrayfuncs.c.

6619 {
6620  ArrayType *array;
6621  Datum search = PG_GETARG_DATUM(1);
6622  bool search_isnull = PG_ARGISNULL(1);
6623 
6624  if (PG_ARGISNULL(0))
6625  PG_RETURN_NULL();
6626  array = PG_GETARG_ARRAYTYPE_P(0);
6627 
6628  array = array_replace_internal(array,
6629  search, search_isnull,
6630  (Datum) 0, true,
6631  true, PG_GET_COLLATION(),
6632  fcinfo);
6633  PG_RETURN_ARRAYTYPE_P(array);
6634 }
static ArrayType * array_replace_internal(ArrayType *array, Datum search, bool search_isnull, Datum replace, bool replace_isnull, bool remove, Oid collation, FunctionCallInfo fcinfo)
Definition: arrayfuncs.c:6360

References array_replace_internal(), PG_ARGISNULL, PG_GET_COLLATION, PG_GETARG_ARRAYTYPE_P, PG_GETARG_DATUM, PG_RETURN_ARRAYTYPE_P, and PG_RETURN_NULL.

◆ array_replace()

Datum array_replace ( PG_FUNCTION_ARGS  )

Definition at line 6640 of file arrayfuncs.c.

6641 {
6642  ArrayType *array;
6643  Datum search = PG_GETARG_DATUM(1);
6644  bool search_isnull = PG_ARGISNULL(1);
6645  Datum replace = PG_GETARG_DATUM(2);
6646  bool replace_isnull = PG_ARGISNULL(2);
6647 
6648  if (PG_ARGISNULL(0))
6649  PG_RETURN_NULL();
6650  array = PG_GETARG_ARRAYTYPE_P(0);
6651 
6652  array = array_replace_internal(array,
6653  search, search_isnull,
6654  replace, replace_isnull,
6655  false, PG_GET_COLLATION(),
6656  fcinfo);
6657  PG_RETURN_ARRAYTYPE_P(array);
6658 }

References array_replace_internal(), PG_ARGISNULL, PG_GET_COLLATION, PG_GETARG_ARRAYTYPE_P, PG_GETARG_DATUM, PG_RETURN_ARRAYTYPE_P, and PG_RETURN_NULL.

◆ array_replace_internal()

static ArrayType * array_replace_internal ( ArrayType array,
Datum  search,
bool  search_isnull,
Datum  replace,
bool  replace_isnull,
bool  remove,
Oid  collation,
FunctionCallInfo  fcinfo 
)
static

Definition at line 6360 of file arrayfuncs.c.

6365 {
6366  LOCAL_FCINFO(locfcinfo, 2);
6367  ArrayType *result;
6368  Oid element_type;
6369  Datum *values;
6370  bool *nulls;
6371  int *dim;
6372  int ndim;
6373  int nitems,
6374  nresult;
6375  int i;
6376  int32 nbytes = 0;
6377  int32 dataoffset;
6378  bool hasnulls;
6379  int typlen;
6380  bool typbyval;
6381  char typalign;
6382  char *arraydataptr;
6383  bits8 *bitmap;
6384  int bitmask;
6385  bool changed = false;
6386  TypeCacheEntry *typentry;
6387 
6388  element_type = ARR_ELEMTYPE(array);
6389  ndim = ARR_NDIM(array);
6390  dim = ARR_DIMS(array);
6391  nitems = ArrayGetNItems(ndim, dim);
6392 
6393  /* Return input array unmodified if it is empty */
6394  if (nitems <= 0)
6395  return array;
6396 
6397  /*
6398  * We can't remove elements from multi-dimensional arrays, since the
6399  * result might not be rectangular.
6400  */
6401  if (remove && ndim > 1)
6402  ereport(ERROR,
6403  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6404  errmsg("removing elements from multidimensional arrays is not supported")));
6405 
6406  /*
6407  * We arrange to look up the equality function only once per series of
6408  * calls, assuming the element type doesn't change underneath us.
6409  */
6410  typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
6411  if (typentry == NULL ||
6412  typentry->type_id != element_type)
6413  {
6414  typentry = lookup_type_cache(element_type,
6416  if (!OidIsValid(typentry->eq_opr_finfo.fn_oid))
6417  ereport(ERROR,
6418  (errcode(ERRCODE_UNDEFINED_FUNCTION),
6419  errmsg("could not identify an equality operator for type %s",
6420  format_type_be(element_type))));
6421  fcinfo->flinfo->fn_extra = (void *) typentry;
6422  }
6423  typlen = typentry->typlen;
6424  typbyval = typentry->typbyval;
6425  typalign = typentry->typalign;
6426 
6427  /*
6428  * Detoast values if they are toasted. The replacement value must be
6429  * detoasted for insertion into the result array, while detoasting the
6430  * search value only once saves cycles.
6431  */
6432  if (typlen == -1)
6433  {
6434  if (!search_isnull)
6435  search = PointerGetDatum(PG_DETOAST_DATUM(search));
6436  if (!replace_isnull)
6437  replace = PointerGetDatum(PG_DETOAST_DATUM(replace));
6438  }
6439 
6440  /* Prepare to apply the comparison operator */
6441  InitFunctionCallInfoData(*locfcinfo, &typentry->eq_opr_finfo, 2,
6442  collation, NULL, NULL);
6443 
6444  /* Allocate temporary arrays for new values */
6445  values = (Datum *) palloc(nitems * sizeof(Datum));
6446  nulls = (bool *) palloc(nitems * sizeof(bool));
6447 
6448  /* Loop over source data */
6449  arraydataptr = ARR_DATA_PTR(array);
6450  bitmap = ARR_NULLBITMAP(array);
6451  bitmask = 1;
6452  hasnulls = false;
6453  nresult = 0;
6454 
6455  for (i = 0; i < nitems; i++)
6456  {
6457  Datum elt;
6458  bool isNull;
6459  bool oprresult;
6460  bool skip = false;
6461 
6462  /* Get source element, checking for NULL */
6463  if (bitmap && (*bitmap & bitmask) == 0)
6464  {
6465  isNull = true;
6466  /* If searching for NULL, we have a match */
6467  if (search_isnull)
6468  {
6469  if (remove)
6470  {
6471  skip = true;
6472  changed = true;
6473  }
6474  else if (!replace_isnull)
6475  {
6476  values[nresult] = replace;
6477  isNull = false;
6478  changed = true;
6479  }
6480  }
6481  }
6482  else
6483  {
6484  isNull = false;
6485  elt = fetch_att(arraydataptr, typbyval, typlen);
6486  arraydataptr = att_addlength_datum(arraydataptr, typlen, elt);
6487  arraydataptr = (char *) att_align_nominal(arraydataptr, typalign);
6488 
6489  if (search_isnull)
6490  {
6491  /* no match possible, keep element */
6492  values[nresult] = elt;
6493  }
6494  else
6495  {
6496  /*
6497  * Apply the operator to the element pair; treat NULL as false
6498  */
6499  locfcinfo->args[0].value = elt;
6500  locfcinfo->args[0].isnull = false;
6501  locfcinfo->args[1].value = search;
6502  locfcinfo->args[1].isnull = false;
6503  locfcinfo->isnull = false;
6504  oprresult = DatumGetBool(FunctionCallInvoke(locfcinfo));
6505  if (locfcinfo->isnull || !oprresult)
6506  {
6507  /* no match, keep element */
6508  values[nresult] = elt;
6509  }
6510  else
6511  {
6512  /* match, so replace or delete */
6513  changed = true;
6514  if (remove)
6515  skip = true;
6516  else
6517  {
6518  values[nresult] = replace;
6519  isNull = replace_isnull;
6520  }
6521  }
6522  }
6523  }
6524 
6525  if (!skip)
6526  {
6527  nulls[nresult] = isNull;
6528  if (isNull)
6529  hasnulls = true;
6530  else
6531  {
6532  /* Update total result size */
6533  nbytes = att_addlength_datum(nbytes, typlen, values[nresult]);
6534  nbytes = att_align_nominal(nbytes, typalign);
6535  /* check for overflow of total request */
6536  if (!AllocSizeIsValid(nbytes))
6537  ereport(ERROR,
6538  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
6539  errmsg("array size exceeds the maximum allowed (%d)",
6540  (int) MaxAllocSize)));
6541  }
6542  nresult++;
6543  }
6544 
6545  /* advance bitmap pointer if any */
6546  if (bitmap)
6547  {
6548  bitmask <<= 1;
6549  if (bitmask == 0x100)
6550  {
6551  bitmap++;
6552  bitmask = 1;
6553  }
6554  }
6555  }
6556 
6557  /*
6558  * If not changed just return the original array
6559  */
6560  if (!changed)
6561  {
6562  pfree(values);
6563  pfree(nulls);
6564  return array;
6565  }
6566 
6567  /* If all elements were removed return an empty array */
6568  if (nresult == 0)
6569  {
6570  pfree(values);
6571  pfree(nulls);
6572  return construct_empty_array(element_type);
6573  }
6574 
6575  /* Allocate and initialize the result array */
6576  if (hasnulls)
6577  {
6578  dataoffset = ARR_OVERHEAD_WITHNULLS(ndim, nresult);
6579  nbytes += dataoffset;
6580  }
6581  else
6582  {
6583  dataoffset = 0; /* marker for no null bitmap */
6584  nbytes += ARR_OVERHEAD_NONULLS(ndim);
6585  }
6586  result = (ArrayType *) palloc0(nbytes);
6587  SET_VARSIZE(result, nbytes);
6588  result->ndim = ndim;
6589  result->dataoffset = dataoffset;
6590  result->elemtype = element_type;
6591  memcpy(ARR_DIMS(result), ARR_DIMS(array), ndim * sizeof(int));
6592  memcpy(ARR_LBOUND(result), ARR_LBOUND(array), ndim * sizeof(int));
6593 
6594  if (remove)
6595  {
6596  /* Adjust the result length */
6597  ARR_DIMS(result)[0] = nresult;
6598  }
6599 
6600  /* Insert data into result array */
6601  CopyArrayEls(result,
6602  values, nulls, nresult,
6603  typlen, typbyval, typalign,
6604  false);
6605 
6606  pfree(values);
6607  pfree(nulls);
6608 
6609  return result;
6610 }
static const struct exclude_list_item skip[]
Definition: pg_checksums.c:108

References AllocSizeIsValid, ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_LBOUND, ARR_NDIM, ARR_NULLBITMAP, ARR_OVERHEAD_NONULLS, ARR_OVERHEAD_WITHNULLS, ArrayGetNItems(), att_addlength_datum, att_align_nominal, construct_empty_array(), CopyArrayEls(), ArrayType::dataoffset, DatumGetBool(), ArrayType::elemtype, TypeCacheEntry::eq_opr_finfo, ereport, errcode(), errmsg(), ERROR, fetch_att(), FunctionCallInfoBaseData::flinfo, FmgrInfo::fn_extra, FmgrInfo::fn_oid, format_type_be(), FunctionCallInvoke, i, if(), InitFunctionCallInfoData, LOCAL_FCINFO, lookup_type_cache(), MaxAllocSize, ArrayType::ndim, nitems, OidIsValid, palloc(), palloc0(), pfree(), PG_DETOAST_DATUM, PointerGetDatum(), SET_VARSIZE, skip, typalign, TypeCacheEntry::typalign, TypeCacheEntry::typbyval, TypeCacheEntry::type_id, TYPECACHE_EQ_OPR_FINFO, TypeCacheEntry::typlen, and values.

Referenced by array_remove(), and array_replace().

◆ array_seek()

static char * array_seek ( char *  ptr,
int  offset,
bits8 nullbitmap,
int  nitems,
int  typlen,
bool  typbyval,
char  typalign 
)
static

Definition at line 4847 of file arrayfuncs.c.

4849 {
4850  int bitmask;
4851  int i;
4852 
4853  /* easy if fixed-size elements and no NULLs */
4854  if (typlen > 0 && !nullbitmap)
4855  return ptr + nitems * ((Size) att_align_nominal(typlen, typalign));
4856 
4857  /* seems worth having separate loops for NULL and no-NULLs cases */
4858  if (nullbitmap)
4859  {
4860  nullbitmap += offset / 8;
4861  bitmask = 1 << (offset % 8);
4862 
4863  for (i = 0; i < nitems; i++)
4864  {
4865  if (*nullbitmap & bitmask)
4866  {
4867  ptr = att_addlength_pointer(ptr, typlen, ptr);
4868  ptr = (char *) att_align_nominal(ptr, typalign);
4869  }
4870  bitmask <<= 1;
4871  if (bitmask == 0x100)
4872  {
4873  nullbitmap++;
4874  bitmask = 1;
4875  }
4876  }
4877  }
4878  else
4879  {
4880  for (i = 0; i < nitems; i++)
4881  {
4882  ptr = att_addlength_pointer(ptr, typlen, ptr);
4883  ptr = (char *) att_align_nominal(ptr, typalign);
4884  }
4885  }
4886  return ptr;
4887 }
size_t Size
Definition: c.h:592

References att_addlength_pointer, att_align_nominal, i, nitems, and typalign.

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

◆ array_send()

Datum array_send ( PG_FUNCTION_ARGS  )

Definition at line 1548 of file arrayfuncs.c.

1549 {
1551  Oid element_type = AARR_ELEMTYPE(v);
1552  int typlen;
1553  bool typbyval;
1554  char typalign;
1555  int nitems,
1556  i;
1557  int ndim,
1558  *dim,
1559  *lb;
1561  array_iter iter;
1562  ArrayMetaState *my_extra;
1563 
1564  /*
1565  * We arrange to look up info about element type, including its send
1566  * conversion proc, only once per series of calls, assuming the element
1567  * type doesn't change underneath us.
1568  */
1569  my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
1570  if (my_extra == NULL)
1571  {
1572  fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
1573  sizeof(ArrayMetaState));
1574  my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
1575  my_extra->element_type = ~element_type;
1576  }
1577 
1578  if (my_extra->element_type != element_type)
1579  {
1580  /* Get info about element type, including its send proc */
1581  get_type_io_data(element_type, IOFunc_send,
1582  &my_extra->typlen, &my_extra->typbyval,
1583  &my_extra->typalign, &my_extra->typdelim,
1584  &my_extra->typioparam, &my_extra->typiofunc);
1585  if (!OidIsValid(my_extra->typiofunc))
1586  ereport(ERROR,
1587  (errcode(ERRCODE_UNDEFINED_FUNCTION),
1588  errmsg("no binary output function available for type %s",
1589  format_type_be(element_type))));
1590  fmgr_info_cxt(my_extra->typiofunc, &my_extra->proc,
1591  fcinfo->flinfo->fn_mcxt);
1592  my_extra->element_type = element_type;
1593  }
1594  typlen = my_extra->typlen;
1595  typbyval = my_extra->typbyval;
1596  typalign = my_extra->typalign;
1597 
1598  ndim = AARR_NDIM(v);
1599  dim = AARR_DIMS(v);
1600  lb = AARR_LBOUND(v);
1601  nitems = ArrayGetNItems(ndim, dim);
1602 
1603  pq_begintypsend(&buf);
1604 
1605  /* Send the array header information */
1606  pq_sendint32(&buf, ndim);
1607  pq_sendint32(&buf, AARR_HASNULL(v) ? 1 : 0);
1608  pq_sendint32(&buf, element_type);
1609  for (i = 0; i < ndim; i++)
1610  {
1611  pq_sendint32(&buf, dim[i]);
1612  pq_sendint32(&buf, lb[i]);
1613  }
1614 
1615  /* Send the array elements using the element's own sendproc */
1616  array_iter_setup(&iter, v);
1617 
1618  for (i = 0; i < nitems; i++)
1619  {
1620  Datum itemvalue;
1621  bool isnull;
1622 
1623  /* Get source element, checking for NULL */
1624  itemvalue = array_iter_next(&iter, &isnull, i,
1625  typlen, typbyval, typalign);
1626 
1627  if (isnull)
1628  {
1629  /* -1 length means a NULL */
1630  pq_sendint32(&buf, -1);
1631  }
1632  else
1633  {
1634  bytea *outputbytes;
1635 
1636  outputbytes = SendFunctionCall(&my_extra->proc, itemvalue);
1637  pq_sendint32(&buf, VARSIZE(outputbytes) - VARHDRSZ);
1638  pq_sendbytes(&buf, VARDATA(outputbytes),
1639  VARSIZE(outputbytes) - VARHDRSZ);
1640  pfree(outputbytes);
1641  }
1642  }
1643 
1645 }
#define AARR_HASNULL(a)
Definition: array.h:331
#define VARHDRSZ
Definition: c.h:679
bytea * SendFunctionCall(FmgrInfo *flinfo, Datum val)
Definition: fmgr.c:1744
#define PG_RETURN_BYTEA_P(x)
Definition: fmgr.h:371
@ IOFunc_send
Definition: lsyscache.h:38
void pq_sendbytes(StringInfo buf, const void *data, int datalen)
Definition: pqformat.c:126
void pq_begintypsend(StringInfo buf)
Definition: pqformat.c:326
bytea * pq_endtypsend(StringInfo buf)
Definition: pqformat.c:346
static void pq_sendint32(StringInfo buf, uint32 i)
Definition: pqformat.h:144
Definition: c.h:674
#define VARDATA(PTR)
Definition: varatt.h:278
#define VARSIZE(PTR)
Definition: varatt.h:279

References AARR_DIMS, AARR_ELEMTYPE, AARR_HASNULL, AARR_LBOUND, AARR_NDIM, array_iter_next(), array_iter_setup(), ArrayGetNItems(), buf, ArrayMetaState::element_type, ereport, errcode(), errmsg(), ERROR, fmgr_info_cxt(), FmgrInfo::fn_mcxt, format_type_be(), get_type_io_data(), i, if(), IOFunc_send, MemoryContextAlloc(), nitems, OidIsValid, pfree(), PG_GETARG_ANY_ARRAY_P, PG_RETURN_BYTEA_P, pq_begintypsend(), pq_endtypsend(), pq_sendbytes(), pq_sendint32(), ArrayMetaState::proc, SendFunctionCall(), typalign, ArrayMetaState::typalign, ArrayMetaState::typbyval, ArrayMetaState::typdelim, ArrayMetaState::typiofunc, ArrayMetaState::typioparam, ArrayMetaState::typlen, VARDATA, VARHDRSZ, and VARSIZE.

Referenced by anyarray_send(), anycompatiblearray_send(), int2vectorsend(), and oidvectorsend().

◆ array_set()

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

Definition at line 3156 of file arrayfuncs.c.

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

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

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

◆ array_set_element()

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

Definition at line 2201 of file arrayfuncs.c.

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

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

Definition at line 2501 of file arrayfuncs.c.

2506 {
2507  ExpandedArrayHeader *eah;
2508  Datum *dvalues;
2509  bool *dnulls;
2510  int i,
2511  ndim,
2512  dim[MAXDIM],
2513  lb[MAXDIM],
2514  offset;
2515  bool dimschanged,
2516  newhasnulls;
2517  int addedbefore,
2518  addedafter;
2519  char *oldValue;
2520 
2521  /* Convert to R/W object if not so already */
2522  eah = DatumGetExpandedArray(arraydatum);
2523 
2524  /* Sanity-check caller's info against object; we don't use it otherwise */
2525  Assert(arraytyplen == -1);
2526  Assert(elmlen == eah->typlen);
2527  Assert(elmbyval == eah->typbyval);
2528  Assert(elmalign == eah->typalign);
2529 
2530  /*
2531  * Copy dimension info into local storage. This allows us to modify the
2532  * dimensions if needed, while not messing up the expanded value if we
2533  * fail partway through.
2534  */
2535  ndim = eah->ndims;
2536  Assert(ndim >= 0 && ndim <= MAXDIM);
2537  memcpy(dim, eah->dims, ndim * sizeof(int));
2538  memcpy(lb, eah->lbound, ndim * sizeof(int));
2539  dimschanged = false;
2540 
2541  /*
2542  * if number of dims is zero, i.e. an empty array, create an array with
2543  * nSubscripts dimensions, and set the lower bounds to the supplied
2544  * subscripts.
2545  */
2546  if (ndim == 0)
2547  {
2548  /*
2549  * Allocate adequate space for new dimension info. This is harmless
2550  * if we fail later.
2551  */
2552  Assert(nSubscripts > 0 && nSubscripts <= MAXDIM);
2553  eah->dims = (int *) MemoryContextAllocZero(eah->hdr.eoh_context,
2554  nSubscripts * sizeof(int));
2555  eah->lbound = (int *) MemoryContextAllocZero(eah->hdr.eoh_context,
2556  nSubscripts * sizeof(int));
2557 
2558  /* Update local copies of dimension info */
2559  ndim = nSubscripts;
2560  for (i = 0; i < nSubscripts; i++)
2561  {
2562  dim[i] = 0;
2563  lb[i] = indx[i];
2564  }
2565  dimschanged = true;
2566  }
2567  else if (ndim != nSubscripts)
2568  ereport(ERROR,
2569  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
2570  errmsg("wrong number of array subscripts")));
2571 
2572  /*
2573  * Deconstruct array if we didn't already. (Someday maybe add a special
2574  * case path for fixed-length, no-nulls cases, where we can overwrite an
2575  * element in place without ever deconstructing. But today is not that
2576  * day.)
2577  */
2579 
2580  /*
2581  * Copy new element into array's context, if needed (we assume it's
2582  * already detoasted, so no junk should be created). Doing this before
2583  * we've made any significant changes ensures that our behavior is sane
2584  * even when the source is a reference to some element of this same array.
2585  * If we fail further down, this memory is leaked, but that's reasonably
2586  * harmless.
2587  */
2588  if (!eah->typbyval && !isNull)
2589  {
2591 
2592  dataValue = datumCopy(dataValue, false, eah->typlen);
2593  MemoryContextSwitchTo(oldcxt);
2594  }
2595 
2596  dvalues = eah->dvalues;
2597  dnulls = eah->dnulls;
2598 
2599  newhasnulls = ((dnulls != NULL) || isNull);
2600  addedbefore = addedafter = 0;
2601 
2602  /*
2603  * Check subscripts (this logic must match array_set_element). We assume
2604  * the existing subscripts passed ArrayCheckBounds, so that dim[i] + lb[i]
2605  * can be computed without overflow. But we must beware of other
2606  * overflows in our calculations of new dim[] values.
2607  */
2608  if (ndim == 1)
2609  {
2610  if (indx[0] < lb[0])
2611  {
2612  /* addedbefore = lb[0] - indx[0]; */
2613  /* dim[0] += addedbefore; */
2614  if (pg_sub_s32_overflow(lb[0], indx[0], &addedbefore) ||
2615  pg_add_s32_overflow(dim[0], addedbefore, &dim[0]))
2616  ereport(ERROR,
2617  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
2618  errmsg("array size exceeds the maximum allowed (%d)",
2619  (int) MaxArraySize)));
2620  lb[0] = indx[0];
2621  dimschanged = true;
2622  if (addedbefore > 1)
2623  newhasnulls = true; /* will insert nulls */
2624  }
2625  if (indx[0] >= (dim[0] + lb[0]))
2626  {
2627  /* addedafter = indx[0] - (dim[0] + lb[0]) + 1; */
2628  /* dim[0] += addedafter; */
2629  if (pg_sub_s32_overflow(indx[0], dim[0] + lb[0], &addedafter) ||
2630  pg_add_s32_overflow(addedafter, 1, &addedafter) ||
2631  pg_add_s32_overflow(dim[0], addedafter, &dim[0]))
2632  ereport(ERROR,
2633  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
2634  errmsg("array size exceeds the maximum allowed (%d)",
2635  (int) MaxArraySize)));
2636  dimschanged = true;
2637  if (addedafter > 1)
2638  newhasnulls = true; /* will insert nulls */
2639  }
2640  }
2641  else
2642  {
2643  /*
2644  * XXX currently we do not support extending multi-dimensional arrays
2645  * during assignment
2646  */
2647  for (i = 0; i < ndim; i++)
2648  {
2649  if (indx[i] < lb[i] ||
2650  indx[i] >= (dim[i] + lb[i]))
2651  ereport(ERROR,
2652  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
2653  errmsg("array subscript out of range")));
2654  }
2655  }
2656 
2657  /* Check for overflow of the array dimensions */
2658  if (dimschanged)
2659  {
2660  (void) ArrayGetNItems(ndim, dim);
2661  ArrayCheckBounds(ndim, dim, lb);
2662  }
2663 
2664  /* Now we can calculate linear offset of target item in array */
2665  offset = ArrayGetOffset(nSubscripts, dim, lb, indx);
2666 
2667  /* Physically enlarge existing dvalues/dnulls arrays if needed */
2668  if (dim[0] > eah->dvalueslen)
2669  {
2670  /* We want some extra space if we're enlarging */
2671  int newlen = dim[0] + dim[0] / 8;
2672 
2673  newlen = Max(newlen, dim[0]); /* integer overflow guard */
2674  eah->dvalues = dvalues = (Datum *)
2675  repalloc(dvalues, newlen * sizeof(Datum));
2676  if (dnulls)
2677  eah->dnulls = dnulls = (bool *)
2678  repalloc(dnulls, newlen * sizeof(bool));
2679  eah->dvalueslen = newlen;
2680  }
2681 
2682  /*
2683  * If we need a nulls bitmap and don't already have one, create it, being
2684  * sure to mark all existing entries as not null.
2685  */
2686  if (newhasnulls && dnulls == NULL)
2687  eah->dnulls = dnulls = (bool *)
2689  eah->dvalueslen * sizeof(bool));
2690 
2691  /*
2692  * We now have all the needed space allocated, so we're ready to make
2693  * irreversible changes. Be very wary of allowing failure below here.
2694  */
2695 
2696  /* Flattened value will no longer represent array accurately */
2697  eah->fvalue = NULL;
2698  /* And we don't know the flattened size either */
2699  eah->flat_size = 0;
2700 
2701  /* Update dimensionality info if needed */
2702  if (dimschanged)
2703  {
2704  eah->ndims = ndim;
2705  memcpy(eah->dims, dim, ndim * sizeof(int));
2706  memcpy(eah->lbound, lb, ndim * sizeof(int));
2707  }
2708 
2709  /* Reposition items if needed, and fill addedbefore items with nulls */
2710  if (addedbefore > 0)
2711  {
2712  memmove(dvalues + addedbefore, dvalues, eah->nelems * sizeof(Datum));
2713  for (i = 0; i < addedbefore; i++)
2714  dvalues[i] = (Datum) 0;
2715  if (dnulls)
2716  {
2717  memmove(dnulls + addedbefore, dnulls, eah->nelems * sizeof(bool));
2718  for (i = 0; i < addedbefore; i++)
2719  dnulls[i] = true;
2720  }
2721  eah->nelems += addedbefore;
2722  }
2723 
2724  /* fill addedafter items with nulls */
2725  if (addedafter > 0)
2726  {
2727  for (i = 0; i < addedafter; i++)
2728  dvalues[eah->nelems + i] = (Datum) 0;
2729  if (dnulls)
2730  {
2731  for (i = 0; i < addedafter; i++)
2732  dnulls[eah->nelems + i] = true;
2733  }
2734  eah->nelems += addedafter;
2735  }
2736 
2737  /* Grab old element value for pfree'ing, if needed. */
2738  if (!eah->typbyval && (dnulls == NULL || !dnulls[offset]))
2739  oldValue = (char *) DatumGetPointer(dvalues[offset]);
2740  else
2741  oldValue = NULL;
2742 
2743  /* And finally we can insert the new element. */
2744  dvalues[offset] = dataValue;
2745  if (dnulls)
2746  dnulls[offset] = isNull;
2747 
2748  /*
2749  * Free old element if needed; this keeps repeated element replacements
2750  * from bloating the array's storage. If the pfree somehow fails, it
2751  * won't corrupt the array.
2752  */
2753  if (oldValue)
2754  {
2755  /* Don't try to pfree a part of the original flat array */
2756  if (oldValue < eah->fstartptr || oldValue >= eah->fendptr)
2757  pfree(oldValue);
2758  }
2759 
2760  /* Done, return standard TOAST pointer for object */
2761  return EOHPGetRWDatum(&eah->hdr);
2762 }
ExpandedArrayHeader * DatumGetExpandedArray(Datum d)
static Datum EOHPGetRWDatum(const struct ExpandedObjectHeader *eohptr)
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1202
char * fendptr
Definition: array.h:167
ExpandedObjectHeader hdr
Definition: array.h:118
ArrayType * fvalue
Definition: array.h:165
MemoryContext eoh_context

References ArrayCheckBounds(), ArrayGetNItems(), ArrayGetOffset(), Assert(), datumCopy(), DatumGetExpandedArray(), DatumGetPointer(), deconstruct_expanded_array(), ExpandedArrayHeader::dims, ExpandedArrayHeader::dnulls, ExpandedArrayHeader::dvalues, ExpandedArrayHeader::dvalueslen, ExpandedObjectHeader::eoh_context, EOHPGetRWDatum(), ereport, errcode(), errmsg(), ERROR, ExpandedArrayHeader::fendptr, ExpandedArrayHeader::flat_size, ExpandedArrayHeader::fvalue, ExpandedArrayHeader::hdr, i, ExpandedArrayHeader::lbound, Max, MaxArraySize, MAXDIM, MemoryContextAllocZero(), MemoryContextSwitchTo(), ExpandedArrayHeader::ndims, ExpandedArrayHeader::nelems, pfree(), pg_add_s32_overflow(), pg_sub_s32_overflow(), repalloc(), ExpandedArrayHeader::typalign, ExpandedArrayHeader::typbyval, and ExpandedArrayHeader::typlen.

Referenced by array_set_element().

◆ array_set_isnull()

static void array_set_isnull ( bits8 nullbitmap,
int  offset,
bool  isNull 
)
static

Definition at line 4779 of file arrayfuncs.c.

4780 {
4781  int bitmask;
4782 
4783  nullbitmap += offset / 8;
4784  bitmask = 1 << (offset % 8);
4785  if (isNull)
4786  *nullbitmap &= ~bitmask;
4787  else
4788  *nullbitmap |= bitmask;
4789 }

Referenced by array_set_element().

◆ array_set_slice()

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

Definition at line 2806 of file arrayfuncs.c.

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

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().

◆ array_slice_size()

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 
)
static

Definition at line 5018 of file arrayfuncs.c.

5022 {
5023  int src_offset,
5024  span[MAXDIM],
5025  prod[MAXDIM],
5026  dist[MAXDIM],
5027  indx[MAXDIM];
5028  char *ptr;
5029  int i,
5030  j,
5031  inc;
5032  int count = 0;
5033 
5034  mda_get_range(ndim, span, st, endp);
5035 
5036  /* Pretty easy for fixed element length without nulls ... */
5037  if (typlen > 0 && !arraynullsptr)
5038  return ArrayGetNItems(ndim, span) * att_align_nominal(typlen, typalign);
5039 
5040  /* Else gotta do it the hard way */
5041  src_offset = ArrayGetOffset(ndim, dim, lb, st);
5042  ptr = array_seek(arraydataptr, 0, arraynullsptr, src_offset,
5043  typlen, typbyval, typalign);
5044  mda_get_prod(ndim, dim, prod);
5045  mda_get_offset_values(ndim, dist, prod, span);
5046  for (i = 0; i < ndim; i++)
5047  indx[i] = 0;
5048  j = ndim - 1;
5049  do
5050  {
5051  if (dist[j])
5052  {
5053  ptr = array_seek(ptr, src_offset, arraynullsptr, dist[j],
5054  typlen, typbyval, typalign);
5055  src_offset += dist[j];
5056  }
5057  if (!array_get_isnull(arraynullsptr, src_offset))
5058  {
5059  inc = att_addlength_pointer(0, typlen, ptr);
5060  inc = att_align_nominal(inc, typalign);
5061  ptr += inc;
5062  count += inc;
5063  }
5064  src_offset++;
5065  } while ((j = mda_next_tuple(ndim, indx, span)) != -1);
5066  return count;
5067 }

References array_get_isnull(), array_seek(), ArrayGetNItems(), ArrayGetOffset(), att_addlength_pointer, att_align_nominal, i, j, MAXDIM, mda_get_offset_values(), mda_get_prod(), mda_get_range(), mda_next_tuple(), and typalign.

Referenced by array_get_slice(), and array_set_slice().

◆ array_smaller()

Datum array_smaller ( PG_FUNCTION_ARGS  )

Definition at line 5875 of file arrayfuncs.c.

5876 {
5877  if (array_cmp(fcinfo) < 0)
5879  else
5881 }

References array_cmp(), PG_GETARG_DATUM, and PG_RETURN_DATUM.

◆ array_unnest()

Datum array_unnest ( PG_FUNCTION_ARGS  )

Definition at line 6233 of file arrayfuncs.c.

6234 {
6235  typedef struct
6236  {
6237  array_iter iter;
6238  int nextelem;
6239  int numelems;
6240  int16 elmlen;
6241  bool elmbyval;
6242  char elmalign;
6243  } array_unnest_fctx;
6244 
6245  FuncCallContext *funcctx;
6246  array_unnest_fctx *fctx;
6247  MemoryContext oldcontext;
6248 
6249  /* stuff done only on the first call of the function */
6250  if (SRF_IS_FIRSTCALL())
6251  {
6252  AnyArrayType *arr;
6253 
6254  /* create a function context for cross-call persistence */
6255  funcctx = SRF_FIRSTCALL_INIT();
6256 
6257  /*
6258  * switch to memory context appropriate for multiple function calls
6259  */
6260  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
6261 
6262  /*
6263  * Get the array value and detoast if needed. We can't do this
6264  * earlier because if we have to detoast, we want the detoasted copy
6265  * to be in multi_call_memory_ctx, so it will go away when we're done
6266  * and not before. (If no detoast happens, we assume the originally
6267  * passed array will stick around till then.)
6268  */
6269  arr = PG_GETARG_ANY_ARRAY_P(0);
6270 
6271  /* allocate memory for user context */
6272  fctx = (array_unnest_fctx *) palloc(sizeof(array_unnest_fctx));
6273 
6274  /* initialize state */
6275  array_iter_setup(&fctx->iter, arr);
6276  fctx->nextelem = 0;
6277  fctx->numelems = ArrayGetNItems(AARR_NDIM(arr), AARR_DIMS(arr));
6278 
6279  if (VARATT_IS_EXPANDED_HEADER(arr))
6280  {
6281  /* we can just grab the type data from expanded array */
6282  fctx->elmlen = arr->xpn.typlen;
6283  fctx->elmbyval = arr->xpn.typbyval;
6284  fctx->elmalign = arr->xpn.typalign;
6285  }
6286  else
6288  &fctx->elmlen,
6289  &fctx->elmbyval,
6290  &fctx->elmalign);
6291 
6292  funcctx->user_fctx = fctx;
6293  MemoryContextSwitchTo(oldcontext);
6294  }
6295 
6296  /* stuff done on every call of the function */
6297  funcctx = SRF_PERCALL_SETUP();
6298  fctx = funcctx->user_fctx;
6299 
6300  if (fctx->nextelem < fctx->numelems)
6301  {
6302  int offset = fctx->nextelem++;
6303  Datum elem;
6304 
6305  elem = array_iter_next(&fctx->iter, &fcinfo->isnull, offset,
6306  fctx->elmlen, fctx->elmbyval, fctx->elmalign);
6307 
6308  SRF_RETURN_NEXT(funcctx, elem);
6309  }
6310  else
6311  {
6312  /* do when there is no more left */
6313  SRF_RETURN_DONE(funcctx);
6314  }
6315 }
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:304
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:308
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:310
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:306
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:328
void * user_fctx
Definition: funcapi.h:82
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:101

References AARR_DIMS, AARR_ELEMTYPE, AARR_NDIM, array_iter_next(), array_iter_setup(), ArrayGetNItems(), get_typlenbyvalalign(), MemoryContextSwitchTo(), FuncCallContext::multi_call_memory_ctx, palloc(), PG_GETARG_ANY_ARRAY_P, SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, ExpandedArrayHeader::typalign, ExpandedArrayHeader::typbyval, ExpandedArrayHeader::typlen, FuncCallContext::user_fctx, VARATT_IS_EXPANDED_HEADER, and AnyArrayType::xpn.

◆ array_unnest_support()

Datum array_unnest_support ( PG_FUNCTION_ARGS  )

Definition at line 6324 of file arrayfuncs.c.

6325 {
6326  Node *rawreq = (Node *) PG_GETARG_POINTER(0);
6327  Node *ret = NULL;
6328 
6329  if (IsA(rawreq, SupportRequestRows))
6330  {
6331  /* Try to estimate the number of rows returned */
6332  SupportRequestRows *req = (SupportRequestRows *) rawreq;
6333 
6334  if (is_funcclause(req->node)) /* be paranoid */
6335  {
6336  List *args = ((FuncExpr *) req->node)->args;
6337  Node *arg1;
6338 
6339  /* We can use estimated argument values here */
6341 
6342  req->rows = estimate_array_length(req->root, arg1);
6343  ret = (Node *) req;
6344  }
6345  }
6346 
6347  PG_RETURN_POINTER(ret);
6348 }
Node * estimate_expression_value(PlannerInfo *root, Node *node)
Definition: clauses.c:2375
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
static bool is_funcclause(const void *clause)
Definition: nodeFuncs.h:67
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
#define linitial(l)
Definition: pg_list.h:178
double estimate_array_length(PlannerInfo *root, Node *arrayexpr)
Definition: selfuncs.c:2136
Definition: pg_list.h:54
struct PlannerInfo * root
Definition: supportnodes.h:163

References generate_unaccent_rules::args, estimate_array_length(), estimate_expression_value(), is_funcclause(), IsA, linitial, SupportRequestRows::node, PG_GETARG_POINTER, PG_RETURN_POINTER, SupportRequestRows::root, and SupportRequestRows::rows.

◆ array_upper()

Datum array_upper ( PG_FUNCTION_ARGS  )

Definition at line 1733 of file arrayfuncs.c.

1734 {
1736  int reqdim = PG_GETARG_INT32(1);
1737  int *dimv,
1738  *lb;
1739  int result;
1740 
1741  /* Sanity check: does it look like an array at all? */
1742  if (AARR_NDIM(v) <= 0 || AARR_NDIM(v) > MAXDIM)
1743  PG_RETURN_NULL();
1744 
1745  /* Sanity check: was the requested dim valid */
1746  if (reqdim <= 0 || reqdim > AARR_NDIM(v))
1747  PG_RETURN_NULL();
1748 
1749  lb = AARR_LBOUND(v);
1750  dimv = AARR_DIMS(v);
1751 
1752  result = dimv[reqdim - 1] + lb[reqdim - 1] - 1;
1753 
1754  PG_RETURN_INT32(result);
1755 }

References AARR_DIMS, AARR_LBOUND, AARR_NDIM, MAXDIM, PG_GETARG_ANY_ARRAY_P, PG_GETARG_INT32, PG_RETURN_INT32, and PG_RETURN_NULL.

◆ ArrayCast()

static Datum ArrayCast ( char *  value,
bool  byval,
int  len 
)
static

Definition at line 4797 of file arrayfuncs.c.

4798 {
4799  return fetch_att(value, byval, len);
4800 }
const void size_t len

References fetch_att(), len, and value.

Referenced by array_get_element().

◆ ArrayCastAndSet()

static int ArrayCastAndSet ( Datum  src,
int  typlen,
bool  typbyval,
char  typalign,
char *  dest 
)
static

Definition at line 4808 of file arrayfuncs.c.

4813 {
4814  int inc;
4815 
4816  if (typlen > 0)
4817  {
4818  if (typbyval)
4819  store_att_byval(dest, src, typlen);
4820  else
4821  memmove(dest, DatumGetPointer(src), typlen);
4822  inc = att_align_nominal(typlen, typalign);
4823  }
4824  else
4825  {
4826  Assert(!typbyval);
4827  inc = att_addlength_datum(0, typlen, src);
4828  memmove(dest, DatumGetPointer(src), inc);
4829  inc = att_align_nominal(inc, typalign);
4830  }
4831 
4832  return inc;
4833 }
static void store_att_byval(void *T, Datum newdatum, int attlen)
Definition: tupmacs.h:183

References Assert(), att_addlength_datum, att_align_nominal, DatumGetPointer(), generate_unaccent_rules::dest, store_att_byval(), and typalign.

Referenced by array_fill_internal(), array_set_element(), and CopyArrayEls().

◆ arraycontained()

Datum arraycontained ( PG_FUNCTION_ARGS  )

Definition at line 4541 of file arrayfuncs.c.

4542 {
4543  AnyArrayType *array1 = PG_GETARG_ANY_ARRAY_P(0);
4544  AnyArrayType *array2 = PG_GETARG_ANY_ARRAY_P(1);
4545  Oid collation = PG_GET_COLLATION();
4546  bool result;
4547 
4548  result = array_contain_compare(array1, array2, collation, true,
4549  &fcinfo->flinfo->fn_extra);
4550 
4551  /* Avoid leaking memory when handed toasted input. */
4552  AARR_FREE_IF_COPY(array1, 0);
4553  AARR_FREE_IF_COPY(array2, 1);
4554 
4555  PG_RETURN_BOOL(result);
4556 }
static bool array_contain_compare(AnyArrayType *array1, AnyArrayType *array2, Oid collation, bool matchall, void **fn_extra)
Definition: arrayfuncs.c:4362

References AARR_FREE_IF_COPY, array_contain_compare(), PG_GET_COLLATION, PG_GETARG_ANY_ARRAY_P, and PG_RETURN_BOOL.

◆ arraycontains()

Datum arraycontains ( PG_FUNCTION_ARGS  )

Definition at line 4523 of file arrayfuncs.c.

4524 {
4525  AnyArrayType *array1 = PG_GETARG_ANY_ARRAY_P(0);
4526  AnyArrayType *array2 = PG_GETARG_ANY_ARRAY_P(1);
4527  Oid collation = PG_GET_COLLATION();
4528  bool result;
4529 
4530  result = array_contain_compare(array2, array1, collation, true,
4531  &fcinfo->flinfo->fn_extra);
4532 
4533  /* Avoid leaking memory when handed toasted input. */
4534  AARR_FREE_IF_COPY(array1, 0);
4535  AARR_FREE_IF_COPY(array2, 1);
4536 
4537  PG_RETURN_BOOL(result);
4538 }

References AARR_FREE_IF_COPY, array_contain_compare(), PG_GET_COLLATION, PG_GETARG_ANY_ARRAY_P, and PG_RETURN_BOOL.

◆ arrayoverlap()

Datum arrayoverlap ( PG_FUNCTION_ARGS  )

Definition at line 4505 of file arrayfuncs.c.

4506 {
4507  AnyArrayType *array1 = PG_GETARG_ANY_ARRAY_P(0);
4508  AnyArrayType *array2 = PG_GETARG_ANY_ARRAY_P(1);
4509  Oid collation = PG_GET_COLLATION();
4510  bool result;
4511 
4512  result = array_contain_compare(array1, array2, collation, false,
4513  &fcinfo->flinfo->fn_extra);
4514 
4515  /* Avoid leaking memory when handed toasted input. */
4516  AARR_FREE_IF_COPY(array1, 0);
4517  AARR_FREE_IF_COPY(array2, 1);
4518 
4519  PG_RETURN_BOOL(result);
4520 }

References AARR_FREE_IF_COPY, array_contain_compare(), PG_GET_COLLATION, PG_GETARG_ANY_ARRAY_P, and PG_RETURN_BOOL.

◆ btarraycmp()

Datum btarraycmp ( PG_FUNCTION_ARGS  )

Definition at line 3954 of file arrayfuncs.c.

3955 {
3956  PG_RETURN_INT32(array_cmp(fcinfo));
3957 }

References array_cmp(), and PG_RETURN_INT32.

◆ construct_array()

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

Definition at line 3354 of file arrayfuncs.c.

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

References construct_md_array().

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

◆ construct_array_builtin()

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

Definition at line 3374 of file arrayfuncs.c.

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

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

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

◆ construct_empty_array()

◆ construct_empty_expanded_array()

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

Definition at line 3578 of file arrayfuncs.c.

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

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

Referenced by fetch_array_arg_replace_nulls().

◆ construct_md_array()

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

Definition at line 3475 of file arrayfuncs.c.

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

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

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

◆ CopyArrayEls()

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

Definition at line 961 of file arrayfuncs.c.

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

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

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

◆ create_array_envelope()

static ArrayType * create_array_envelope ( int  ndims,
int *  dimv,
int *  lbsv,
int  nbytes,
Oid  elmtype,
int  dataoffset 
)
static

Definition at line 6047 of file arrayfuncs.c.

6049 {
6050  ArrayType *result;
6051 
6052  result = (ArrayType *) palloc0(nbytes);
6053  SET_VARSIZE(result, nbytes);
6054  result->ndim = ndims;
6055  result->dataoffset = dataoffset;
6056  result->elemtype = elmtype;
6057  memcpy(ARR_DIMS(result), dimv, ndims * sizeof(int));
6058  memcpy(ARR_LBOUND(result), lbsv, ndims * sizeof(int));
6059 
6060  return result;
6061 }

References ARR_DIMS, ARR_LBOUND, ArrayType::dataoffset, ArrayType::elemtype, ArrayType::ndim, palloc0(), and SET_VARSIZE.

Referenced by array_fill_internal().

◆ deconstruct_array()

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

Definition at line 3612 of file arrayfuncs.c.

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

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

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

◆ deconstruct_array_builtin()

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

Definition at line 3678 of file arrayfuncs.c.

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

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

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

◆ generate_subscripts()

Datum generate_subscripts ( PG_FUNCTION_ARGS  )

Definition at line 5896 of file arrayfuncs.c.

5897 {
5898  FuncCallContext *funcctx;
5899  MemoryContext oldcontext;
5901 
5902  /* stuff done only on the first call of the function */
5903  if (SRF_IS_FIRSTCALL())
5904  {
5906  int reqdim = PG_GETARG_INT32(1);
5907  int *lb,
5908  *dimv;
5909 
5910  /* create a function context for cross-call persistence */
5911  funcctx = SRF_FIRSTCALL_INIT();
5912 
5913  /* Sanity check: does it look like an array at all? */
5914  if (AARR_NDIM(v) <= 0 || AARR_NDIM(v) > MAXDIM)
5915  SRF_RETURN_DONE(funcctx);
5916 
5917  /* Sanity check: was the requested dim valid */
5918  if (reqdim <= 0 || reqdim > AARR_NDIM(v))
5919  SRF_RETURN_DONE(funcctx);
5920 
5921  /*
5922  * switch to memory context appropriate for multiple function calls
5923  */
5924  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
5926 
5927  lb = AARR_LBOUND(v);
5928  dimv = AARR_DIMS(v);
5929 
5930  fctx->lower = lb[reqdim - 1];
5931  fctx->upper = dimv[reqdim - 1] + lb[reqdim - 1] - 1;
5932  fctx->reverse = (PG_NARGS() < 3) ? false : PG_GETARG_BOOL(2);
5933 
5934  funcctx->user_fctx = fctx;
5935 
5936  MemoryContextSwitchTo(oldcontext);
5937  }
5938 
5939  funcctx = SRF_PERCALL_SETUP();
5940 
5941  fctx = funcctx->user_fctx;
5942 
5943  if (fctx->lower <= fctx->upper)
5944  {
5945  if (!fctx->reverse)
5946  SRF_RETURN_NEXT(funcctx, Int32GetDatum(fctx->lower++));
5947  else
5948  SRF_RETURN_NEXT(funcctx, Int32GetDatum(fctx->upper--));
5949  }
5950  else
5951  /* done when there are no more elements left */
5952  SRF_RETURN_DONE(funcctx);
5953 }
#define PG_NARGS()
Definition: fmgr.h:203
#define PG_GETARG_BOOL(n)
Definition: fmgr.h:274
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212

References AARR_DIMS, AARR_LBOUND, AARR_NDIM, Int32GetDatum(), generate_subscripts_fctx::lower, MAXDIM, MemoryContextSwitchTo(), FuncCallContext::multi_call_memory_ctx, palloc(), PG_GETARG_ANY_ARRAY_P, PG_GETARG_BOOL, PG_GETARG_INT32, PG_NARGS, generate_subscripts_fctx::reverse, SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, generate_subscripts_fctx::upper, and FuncCallContext::user_fctx.

Referenced by generate_subscripts_nodir().

◆ generate_subscripts_nodir()

Datum generate_subscripts_nodir ( PG_FUNCTION_ARGS  )

Definition at line 5960 of file arrayfuncs.c.

5961 {
5962  /* just call the other one -- it can handle both cases */
5963  return generate_subscripts(fcinfo);
5964 }
Datum generate_subscripts(PG_FUNCTION_ARGS)
Definition: arrayfuncs.c:5896

References generate_subscripts().

◆ hash_array()

Datum hash_array ( PG_FUNCTION_ARGS  )

Definition at line 4139 of file arrayfuncs.c.

4140 {
4141  LOCAL_FCINFO(locfcinfo, 1);
4142  AnyArrayType *array = PG_GETARG_ANY_ARRAY_P(0);
4143  int ndims = AARR_NDIM(array);
4144  int *dims = AARR_DIMS(array);
4145  Oid element_type = AARR_ELEMTYPE(array);
4146  uint32 result = 1;
4147  int nitems;
4148  TypeCacheEntry *typentry;
4149  int typlen;
4150  bool typbyval;
4151  char typalign;
4152  int i;
4153  array_iter iter;
4154 
4155  /*
4156  * We arrange to look up the hash function only once per series of calls,
4157  * assuming the element type doesn't change underneath us. The typcache
4158  * is used so that we have no memory leakage when being used as an index
4159  * support function.
4160  */
4161  typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
4162  if (typentry == NULL ||
4163  typentry->type_id != element_type)
4164  {
4165  typentry = lookup_type_cache(element_type,
4167  if (!OidIsValid(typentry->hash_proc_finfo.fn_oid) && element_type != RECORDOID)
4168  ereport(ERROR,
4169  (errcode(ERRCODE_UNDEFINED_FUNCTION),
4170  errmsg("could not identify a hash function for type %s",
4171  format_type_be(element_type))));
4172 
4173  /*
4174  * The type cache doesn't believe that record is hashable (see
4175  * cache_record_field_properties()), but since we're here, we're
4176  * committed to hashing, so we can assume it does. Worst case, if any
4177  * components of the record don't support hashing, we will fail at
4178  * execution.
4179  */
4180  if (element_type == RECORDOID)
4181  {
4182  MemoryContext oldcontext;
4183  TypeCacheEntry *record_typentry;
4184 
4185  oldcontext = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt);
4186 
4187  /*
4188  * Make fake type cache entry structure. Note that we can't just
4189  * modify typentry, since that points directly into the type
4190  * cache.
4191  */
4192  record_typentry = palloc0(sizeof(*record_typentry));
4193  record_typentry->type_id = element_type;
4194 
4195  /* fill in what we need below */
4196  record_typentry->typlen = typentry->typlen;
4197  record_typentry->typbyval = typentry->typbyval;
4198  record_typentry->typalign = typentry->typalign;
4199  fmgr_info(F_HASH_RECORD, &record_typentry->hash_proc_finfo);
4200 
4201  MemoryContextSwitchTo(oldcontext);
4202 
4203  typentry = record_typentry;
4204  }
4205 
4206  fcinfo->flinfo->fn_extra = (void *) typentry;
4207  }
4208 
4209  typlen = typentry->typlen;
4210  typbyval = typentry->typbyval;
4211  typalign = typentry->typalign;
4212 
4213  /*
4214  * apply the hash function to each array element.
4215  */
4216  InitFunctionCallInfoData(*locfcinfo, &typentry->hash_proc_finfo, 1,
4217  PG_GET_COLLATION(), NULL, NULL);
4218 
4219  /* Loop over source data */
4220  nitems = ArrayGetNItems(ndims, dims);
4221  array_iter_setup(&iter, array);
4222 
4223  for (i = 0; i < nitems; i++)
4224  {
4225  Datum elt;
4226  bool isnull;
4227  uint32 elthash;
4228 
4229  /* Get element, checking for NULL */
4230  elt = array_iter_next(&iter, &isnull, i, typlen, typbyval, typalign);
4231 
4232  if (isnull)
4233  {
4234  /* Treat nulls as having hashvalue 0 */
4235  elthash = 0;
4236  }
4237  else
4238  {
4239  /* Apply the hash function */
4240  locfcinfo->args[0].value = elt;
4241  locfcinfo->args[0].isnull = false;
4242  elthash = DatumGetUInt32(FunctionCallInvoke(locfcinfo));
4243  /* We don't expect hash functions to return null */
4244  Assert(!locfcinfo->isnull);
4245  }
4246 
4247  /*
4248  * Combine hash values of successive elements by multiplying the
4249  * current value by 31 and adding on the new element's hash value.
4250  *
4251  * The result is a sum in which each element's hash value is
4252  * multiplied by a different power of 31. This is modulo 2^32
4253  * arithmetic, and the powers of 31 modulo 2^32 form a cyclic group of
4254  * order 2^27. So for arrays of up to 2^27 elements, each element's
4255  * hash value is multiplied by a different (odd) number, resulting in
4256  * a good mixing of all the elements' hash values.
4257  */
4258  result = (result << 5) - result + elthash;
4259  }
4260 
4261  /* Avoid leaking memory when handed toasted input. */
4262  AARR_FREE_IF_COPY(array, 0);
4263 
4264  PG_RETURN_UINT32(result);
4265 }
unsigned int uint32
Definition: c.h:493
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:127
#define PG_RETURN_UINT32(x)
Definition: fmgr.h:355
static uint32 DatumGetUInt32(Datum X)
Definition: postgres.h:222
FmgrInfo hash_proc_finfo
Definition: typcache.h:77
#define TYPECACHE_HASH_PROC_FINFO
Definition: typcache.h:144

References AARR_DIMS, AARR_ELEMTYPE, AARR_FREE_IF_COPY, AARR_NDIM, array_iter_next(), array_iter_setup(), ArrayGetNItems(), Assert(), DatumGetUInt32(), ereport, errcode(), errmsg(), ERROR, fmgr_info(), FmgrInfo::fn_oid, format_type_be(), FunctionCallInvoke, TypeCacheEntry::hash_proc_finfo, i, if(), InitFunctionCallInfoData, LOCAL_FCINFO, lookup_type_cache(), MemoryContextSwitchTo(), nitems, OidIsValid, palloc0(), PG_GET_COLLATION, PG_GETARG_ANY_ARRAY_P, PG_RETURN_UINT32, typalign, TypeCacheEntry::typalign, TypeCacheEntry::typbyval, TypeCacheEntry::type_id, TYPECACHE_HASH_PROC_FINFO, and TypeCacheEntry::typlen.

◆ hash_array_extended()

Datum hash_array_extended ( PG_FUNCTION_ARGS  )

Definition at line 4272 of file arrayfuncs.c.

4273 {
4274  LOCAL_FCINFO(locfcinfo, 2);
4275  AnyArrayType *array = PG_GETARG_ANY_ARRAY_P(0);
4276  uint64 seed = PG_GETARG_INT64(1);
4277  int ndims = AARR_NDIM(array);
4278  int *dims = AARR_DIMS(array);
4279  Oid element_type = AARR_ELEMTYPE(array);
4280  uint64 result = 1;
4281  int nitems;
4282  TypeCacheEntry *typentry;
4283  int typlen;
4284  bool typbyval;
4285  char typalign;
4286  int i;
4287  array_iter iter;
4288 
4289  typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
4290  if (typentry == NULL ||
4291  typentry->type_id != element_type)
4292  {
4293  typentry = lookup_type_cache(element_type,
4295  if (!OidIsValid(typentry->hash_extended_proc_finfo.fn_oid))
4296  ereport(ERROR,
4297  (errcode(ERRCODE_UNDEFINED_FUNCTION),
4298  errmsg("could not identify an extended hash function for type %s",
4299  format_type_be(element_type))));
4300  fcinfo->flinfo->fn_extra = (void *) typentry;
4301  }
4302  typlen = typentry->typlen;
4303  typbyval = typentry->typbyval;
4304  typalign = typentry->typalign;
4305 
4306  InitFunctionCallInfoData(*locfcinfo, &typentry->hash_extended_proc_finfo, 2,
4307  PG_GET_COLLATION(), NULL, NULL);
4308 
4309  /* Loop over source data */
4310  nitems = ArrayGetNItems(ndims, dims);
4311  array_iter_setup(&iter, array);
4312 
4313  for (i = 0; i < nitems; i++)
4314  {
4315  Datum elt;
4316  bool isnull;
4317  uint64 elthash;
4318 
4319  /* Get element, checking for NULL */
4320  elt = array_iter_next(&iter, &isnull, i, typlen, typbyval, typalign);
4321 
4322  if (isnull)
4323  {
4324  elthash = 0;
4325  }
4326  else
4327  {
4328  /* Apply the hash function */
4329  locfcinfo->args[0].value = elt;
4330  locfcinfo->args[0].isnull = false;
4331  locfcinfo->args[1].value = Int64GetDatum(seed);
4332  locfcinfo->args[1].isnull = false;
4333  elthash = DatumGetUInt64(FunctionCallInvoke(locfcinfo));
4334  /* We don't expect hash functions to return null */
4335  Assert(!locfcinfo->isnull);
4336  }
4337 
4338  result = (result << 5) - result + elthash;
4339  }
4340 
4341  AARR_FREE_IF_COPY(array, 0);
4342 
4343  PG_RETURN_UINT64(result);
4344 }
Datum Int64GetDatum(int64 X)
Definition: fmgr.c:1807
#define PG_GETARG_INT64(n)
Definition: fmgr.h:283
#define PG_RETURN_UINT64(x)
Definition: fmgr.h:369
static uint64 DatumGetUInt64(Datum X)
Definition: postgres.h:419
FmgrInfo hash_extended_proc_finfo
Definition: typcache.h:78
#define TYPECACHE_HASH_EXTENDED_PROC_FINFO
Definition: typcache.h:152

References AARR_DIMS, AARR_ELEMTYPE, AARR_FREE_IF_COPY, AARR_NDIM, array_iter_next(), array_iter_setup(), ArrayGetNItems(), Assert(), DatumGetUInt64(), ereport, errcode(), errmsg(), ERROR, FmgrInfo::fn_oid, format_type_be(), FunctionCallInvoke, TypeCacheEntry::hash_extended_proc_finfo, i, if(), InitFunctionCallInfoData, Int64GetDatum(), LOCAL_FCINFO, lookup_type_cache(), nitems, OidIsValid, PG_GET_COLLATION, PG_GETARG_ANY_ARRAY_P, PG_GETARG_INT64, PG_RETURN_UINT64, typalign, TypeCacheEntry::typalign, TypeCacheEntry::typbyval, TypeCacheEntry::type_id, TYPECACHE_HASH_EXTENDED_PROC_FINFO, and TypeCacheEntry::typlen.

◆ initArrayResult()

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

Definition at line 5274 of file arrayfuncs.c.

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

References initArrayResultWithSize().

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

◆ initArrayResultAny()

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

Definition at line 5763 of file arrayfuncs.c.

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

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

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

◆ initArrayResultArr()

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

Definition at line 5485 of file arrayfuncs.c.

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

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

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

◆ initArrayResultWithSize()

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

Definition at line 5291 of file arrayfuncs.c.

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

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

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

◆ makeArrayResult()

Datum makeArrayResult ( ArrayBuildState astate,
MemoryContext  rcontext 
)

Definition at line 5401 of file arrayfuncs.c.

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

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

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

◆ makeArrayResultAny()

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

Definition at line 5836 of file arrayfuncs.c.

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

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

Referenced by ExecScanSubPlan(), and ExecSetParamPlan().

◆ makeArrayResultArr()

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

Definition at line 5684 of file arrayfuncs.c.

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

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

Referenced by array_agg_array_finalfn(), and makeArrayResultAny().

◆ makeMdArrayResult()

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

Definition at line 5433 of file arrayfuncs.c.

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

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

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

◆ ReadArrayBinary()

static void ReadArrayBinary ( StringInfo  buf,
int  nitems,
FmgrInfo receiveproc,
Oid  typioparam,
int32  typmod,
int  typlen,
bool  typbyval,
char  typalign,
Datum values,
bool nulls,
bool hasnulls,
int32 nbytes 
)
static

Definition at line 1454 of file arrayfuncs.c.

1466 {
1467  int i;
1468  bool hasnull;
1469  int32 totbytes;
1470 
1471  for (i = 0; i < nitems; i++)
1472  {
1473  int itemlen;
1474  StringInfoData elem_buf;
1475 
1476  /* Get and check the item length */
1477  itemlen = pq_getmsgint(buf, 4);
1478  if (itemlen < -1 || itemlen > (buf->len - buf->cursor))
1479  ereport(ERROR,
1480  (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
1481  errmsg("insufficient data left in message")));
1482 
1483  if (itemlen == -1)
1484  {
1485  /* -1 length means NULL */
1486  values[i] = ReceiveFunctionCall(receiveproc, NULL,
1487  typioparam, typmod);
1488  nulls[i] = true;
1489  continue;
1490  }
1491 
1492  /*
1493  * Rather than copying data around, we just initialize a StringInfo
1494  * pointing to the correct portion of the message buffer.
1495  */
1496  initReadOnlyStringInfo(&elem_buf, &buf->data[buf->cursor], itemlen);
1497 
1498  buf->cursor += itemlen;
1499 
1500  /* Now call the element's receiveproc */
1501  values[i] = ReceiveFunctionCall(receiveproc, &elem_buf,
1502  typioparam, typmod);
1503  nulls[i] = false;
1504 
1505  /* Trouble if it didn't eat the whole buffer */
1506  if (elem_buf.cursor != itemlen)
1507  ereport(ERROR,
1508  (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
1509  errmsg("improper binary format in array element %d",
1510  i + 1)));
1511  }
1512 
1513  /*
1514  * Check for nulls, compute total data space needed
1515  */
1516  hasnull = false;
1517  totbytes = 0;
1518  for (i = 0; i < nitems; i++)
1519  {
1520  if (nulls[i])
1521  hasnull = true;
1522  else
1523  {
1524  /* let's just make sure data is not toasted */
1525  if (typlen == -1)
1527  totbytes = att_addlength_datum(totbytes, typlen, values[i]);
1528  totbytes = att_align_nominal(totbytes, typalign);
1529  /* check for overflow of total request */
1530  if (!AllocSizeIsValid(totbytes))
1531  ereport(ERROR,
1532  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1533  errmsg("array size exceeds the maximum allowed (%d)",
1534  (int) MaxAllocSize)));
1535  }
1536  }
1537  *hasnulls = hasnull;
1538  *nbytes = totbytes;
1539 }
Datum ReceiveFunctionCall(FmgrInfo *flinfo, StringInfo buf, Oid typioparam, int32 typmod)
Definition: fmgr.c:1697
static void initReadOnlyStringInfo(StringInfo str, char *data, int len)
Definition: stringinfo.h:130

References AllocSizeIsValid, att_addlength_datum, att_align_nominal, buf, StringInfoData::cursor, ereport, errcode(), errmsg(), ERROR, i, initReadOnlyStringInfo(), MaxAllocSize, nitems, PG_DETOAST_DATUM, PointerGetDatum(), pq_getmsgint(), ReceiveFunctionCall(), typalign, and values.

Referenced by array_recv().

◆ ReadArrayDimensions()

static bool ReadArrayDimensions ( char **  srcptr,
int *  ndim_p,
int *  dim,
int *  lBound,
const char *  origStr,
Node escontext 
)
static

Definition at line 402 of file arrayfuncs.c.

404 {
405  char *p = *srcptr;
406  int ndim;
407 
408  /*
409  * Dimension info takes the form of one or more [n] or [m:n] items. This
410  * loop iterates once per dimension item.
411  */
412  ndim = 0;
413  for (;;)
414  {
415  char *q;
416  int ub;
417  int i;
418 
419  /*
420  * Note: we currently allow whitespace between, but not within,
421  * dimension items.
422  */
423  while (scanner_isspace(*p))
424  p++;
425  if (*p != '[')
426  break; /* no more dimension items */
427  p++;
428  if (ndim >= MAXDIM)
429  ereturn(escontext, false,
430  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
431  errmsg("number of array dimensions exceeds the maximum allowed (%d)",
432  MAXDIM)));
433 
434  q = p;
435  if (!ReadDimensionInt(&p, &i, origStr, escontext))
436  return false;
437  if (p == q) /* no digits? */
438  ereturn(escontext, false,
439  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
440  errmsg("malformed array literal: \"%s\"", origStr),
441  errdetail("\"[\" must introduce explicitly-specified array dimensions.")));
442 
443  if (*p == ':')
444  {
445  /* [m:n] format */
446  lBound[ndim] = i;
447  p++;
448  q = p;
449  if (!ReadDimensionInt(&p, &ub, origStr, escontext))
450  return false;
451  if (p == q) /* no digits? */
452  ereturn(escontext, false,
453  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
454  errmsg("malformed array literal: \"%s\"", origStr),
455  errdetail("Missing array dimension value.")));
456  }
457  else
458  {
459  /* [n] format */
460  lBound[ndim] = 1;
461  ub = i;
462  }
463  if (*p != ']')
464  ereturn(escontext, false,
465  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
466  errmsg("malformed array literal: \"%s\"", origStr),
467  errdetail("Missing \"%s\" after array dimensions.",
468  "]")));
469  p++;
470 
471  /*
472  * Note: we could accept ub = lb-1 to represent a zero-length
473  * dimension. However, that would result in an empty array, for which
474  * we don't keep any dimension data, so that e.g. [1:0] and [101:100]
475  * would be equivalent. Given the lack of field demand, there seems
476  * little point in allowing such cases.
477  */
478  if (ub < lBound[ndim])
479  ereturn(escontext, false,
480  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
481  errmsg("upper bound cannot be less than lower bound")));
482 
483  /* Upper bound of INT_MAX must be disallowed, cf ArrayCheckBounds() */
484  if (ub == INT_MAX)
485  ereturn(escontext, false,
486  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
487  errmsg("array upper bound is too large: %d", ub)));
488 
489  /* Compute "ub - lBound[ndim] + 1", detecting overflow */
490  if (pg_sub_s32_overflow(ub, lBound[ndim], &ub) ||
491  pg_add_s32_overflow(ub, 1, &ub))
492  ereturn(escontext, false,
493  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
494  errmsg("array size exceeds the maximum allowed (%d)",
495  (int) MaxArraySize)));
496 
497  dim[ndim] = ub;
498  ndim++;
499  }
500 
501  *srcptr = p;
502  *ndim_p = ndim;
503  return true;
504 }
static bool ReadDimensionInt(char **srcptr, int *result, const char *origStr, Node *escontext)
Definition: arrayfuncs.c:519

References ereturn, errcode(), errdetail(), errmsg(), i, MaxArraySize, MAXDIM, pg_add_s32_overflow(), pg_sub_s32_overflow(), ReadDimensionInt(), and scanner_isspace().

Referenced by array_in().

◆ ReadArrayStr()

static bool ReadArrayStr ( char **  srcptr,
FmgrInfo inputproc,
Oid  typioparam,
int32  typmod,
char  typdelim,
int  typlen,
bool  typbyval,
char  typalign,
int *  ndim_p,
int *  dim,
int *  nitems_p,
Datum **  values_p,
bool **  nulls_p,
const char *  origStr,
Node escontext 
)
static

Definition at line 579 of file arrayfuncs.c.

594 {
595  int ndim = *ndim_p;
596  bool dimensions_specified = (ndim != 0);
597  int maxitems;
598  Datum *values;
599  bool *nulls;
600  StringInfoData elembuf;
601  int nest_level;
602  int nitems;
603  bool ndim_frozen;
604  bool expect_delim;
605  int nelems[MAXDIM];
606 
607  /* Allocate some starting output workspace; we'll enlarge as needed */
608  maxitems = 16;
609  values = palloc_array(Datum, maxitems);
610  nulls = palloc_array(bool, maxitems);
611 
612  /* Allocate workspace to hold (string representation of) one element */
613  initStringInfo(&elembuf);
614 
615  /* Loop below assumes first token is ATOK_LEVEL_START */
616  Assert(**srcptr == '{');
617 
618  /* Parse tokens until we reach the matching right brace */
619  nest_level = 0;
620  nitems = 0;
621  ndim_frozen = dimensions_specified;
622  expect_delim = false;
623  do
624  {
625  ArrayToken tok;
626 
627  tok = ReadArrayToken(srcptr, &elembuf, typdelim, origStr, escontext);
628 
629  switch (tok)
630  {
631  case ATOK_LEVEL_START:
632  /* Can't write left brace where delim is expected */
633  if (expect_delim)
634  ereturn(escontext, false,
635  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
636  errmsg("malformed array literal: \"%s\"", origStr),
637  errdetail("Unexpected \"%c\" character.", '{')));
638 
639  /* Initialize element counting in the new level */
640  if (nest_level >= MAXDIM)
641  ereturn(escontext, false,
642  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
643  errmsg("number of array dimensions exceeds the maximum allowed (%d)",
644  MAXDIM)));
645 
646  nelems[nest_level] = 0;
647  nest_level++;
648  if (nest_level > ndim)
649  {
650  /* Can't increase ndim once it's frozen */
651  if (ndim_frozen)
652  goto dimension_error;
653  ndim = nest_level;
654  }
655  break;
656 
657  case ATOK_LEVEL_END:
658  /* Can't get here with nest_level == 0 */
659  Assert(nest_level > 0);
660 
661  /*
662  * We allow a right brace to terminate an empty sub-array,
663  * otherwise it must occur where we expect a delimiter.
664  */
665  if (nelems[nest_level - 1] > 0 && !expect_delim)
666  ereturn(escontext, false,
667  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
668  errmsg("malformed array literal: \"%s\"", origStr),
669  errdetail("Unexpected \"%c\" character.",
670  '}')));
671  nest_level--;
672  /* Nested sub-arrays count as elements of outer level */
673  if (nest_level > 0)
674  nelems[nest_level - 1]++;
675 
676  /*
677  * Note: if we had dimensionality info, then dim[nest_level]
678  * is initially non-negative, and we'll check each sub-array's
679  * length against that.
680  */
681  if (dim[nest_level] < 0)
682  {
683  /* Save length of first sub-array of this level */
684  dim[nest_level] = nelems[nest_level];
685  }
686  else if (nelems[nest_level] != dim[nest_level])
687  {
688  /* Subsequent sub-arrays must have same length */
689  goto dimension_error;
690  }
691 
692  /*
693  * Must have a delim or another right brace following, unless
694  * we have reached nest_level 0, where this won't matter.
695  */
696  expect_delim = true;
697  break;
698 
699  case ATOK_DELIM:
700  if (!expect_delim)
701  ereturn(escontext, false,
702  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
703  errmsg("malformed array literal: \"%s\"", origStr),
704  errdetail("Unexpected \"%c\" character.",
705  typdelim)));
706  expect_delim = false;
707  break;
708 
709  case ATOK_ELEM:
710  case ATOK_ELEM_NULL:
711  /* Can't get here with nest_level == 0 */
712  Assert(nest_level > 0);
713 
714  /* Disallow consecutive ELEM tokens */
715  if (expect_delim)
716  ereturn(escontext, false,
717  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
718  errmsg("malformed array literal: \"%s\"", origStr),
719  errdetail("Unexpected array element.")));
720 
721  /* Enlarge the values/nulls arrays if needed */
722  if (nitems >= maxitems)
723  {
724  if (maxitems >= MaxArraySize)
725  ereturn(escontext, false,
726  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
727  errmsg("array size exceeds the maximum allowed (%d)",
728  (int) MaxArraySize)));
729  maxitems = Min(maxitems * 2, MaxArraySize);
730  values = repalloc_array(values, Datum, maxitems);
731  nulls = repalloc_array(nulls, bool, maxitems);
732  }
733 
734  /* Read the element's value, or check that NULL is allowed */
735  if (!InputFunctionCallSafe(inputproc,
736  (tok == ATOK_ELEM_NULL) ? NULL : elembuf.data,
737  typioparam, typmod,
738  escontext,
739  &values[nitems]))
740  return false;
741  nulls[nitems] = (tok == ATOK_ELEM_NULL);
742  nitems++;
743 
744  /*
745  * Once we have found an element, the number of dimensions can
746  * no longer increase, and subsequent elements must all be at
747  * the same nesting depth.
748  */
749  ndim_frozen = true;
750  if (nest_level != ndim)
751  goto dimension_error;
752  /* Count the new element */
753  nelems[nest_level - 1]++;
754 
755  /* Must have a delim or a right brace following */
756  expect_delim = true;
757  break;
758 
759  case ATOK_ERROR:
760  return false;
761  }
762  } while (nest_level > 0);
763 
764  /* Clean up and return results */
765  pfree(elembuf.data);
766 
767  *ndim_p = ndim;
768  *nitems_p = nitems;
769  *values_p = values;
770  *nulls_p = nulls;
771  return true;
772 
773 dimension_error:
774  if (dimensions_specified)
775  ereturn(escontext, false,
776  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
777  errmsg("malformed array literal: \"%s\"", origStr),
778  errdetail("Specified array dimensions do not match array contents.")));
779  else
780  ereturn(escontext, false,
781  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
782  errmsg("malformed array literal: \"%s\"", origStr),
783  errdetail("Multidimensional arrays must have sub-arrays with matching dimensions.")));
784 }
static ArrayToken ReadArrayToken(char **srcptr, StringInfo elembuf, char typdelim, const char *origStr, Node *escontext)
Definition: arrayfuncs.c:796
#define repalloc_array(pointer, type, count)
Definition: fe_memutils.h:66
#define palloc_array(type, count)
Definition: fe_memutils.h:64
bool InputFunctionCallSafe(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod, fmNodePtr escontext, Datum *result)
Definition: fmgr.c:1585
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59

References Assert(), ATOK_DELIM, ATOK_ELEM, ATOK_ELEM_NULL, ATOK_ERROR, ATOK_LEVEL_END, ATOK_LEVEL_START, StringInfoData::data, ereturn, errcode(), errdetail(), errmsg(), initStringInfo(), InputFunctionCallSafe(), MaxArraySize, MAXDIM, Min, nitems, palloc_array, pfree(), ReadArrayToken(), repalloc_array, and values.

Referenced by array_in().

◆ ReadArrayToken()

static ArrayToken ReadArrayToken ( char **  srcptr,
StringInfo  elembuf,
char  typdelim,
const char *  origStr,
Node escontext 
)
static

Definition at line 796 of file arrayfuncs.c.

798 {
799  char *p = *srcptr;
800  int dstlen;
801  bool has_escapes;
802 
803  resetStringInfo(elembuf);
804 
805  /* Identify token type. Loop advances over leading whitespace. */
806  for (;;)
807  {
808  switch (*p)
809  {
810  case '\0':
811  goto ending_error;
812  case '{':
813  *srcptr = p + 1;
814  return ATOK_LEVEL_START;
815  case '}':
816  *srcptr = p + 1;
817  return ATOK_LEVEL_END;
818  case '"':
819  p++;
820  goto quoted_element;
821  default:
822  if (*p == typdelim)
823  {
824  *srcptr = p + 1;
825  return ATOK_DELIM;
826  }
827  if (scanner_isspace(*p))
828  {
829  p++;
830  continue;
831  }
832  goto unquoted_element;
833  }
834  }
835 
836 quoted_element:
837  for (;;)
838  {
839  switch (*p)
840  {
841  case '\0':
842  goto ending_error;
843  case '\\':
844  /* Skip backslash, copy next character as-is. */
845  p++;
846  if (*p == '\0')
847  goto ending_error;
848  appendStringInfoChar(elembuf, *p++);
849  break;
850  case '"':
851 
852  /*
853  * If next non-whitespace isn't typdelim or a brace, complain
854  * about incorrect quoting. While we could leave such cases
855  * to be detected as incorrect token sequences, the resulting
856  * message wouldn't be as helpful. (We could also give the
857  * incorrect-quoting error when next is '{', but treating that
858  * as a token sequence error seems better.)
859  */
860  while (*(++p) != '\0')
861  {
862  if (*p == typdelim || *p == '}' || *p == '{')
863  {
864  *srcptr = p;
865  return ATOK_ELEM;
866  }
867  if (!scanner_isspace(*p))
868  ereturn(escontext, ATOK_ERROR,
869  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
870  errmsg("malformed array literal: \"%s\"", origStr),
871  errdetail("Incorrectly quoted array element.")));
872  }
873  goto ending_error;
874  default:
875  appendStringInfoChar(elembuf, *p++);
876  break;
877  }
878  }
879 
880 unquoted_element:
881 
882  /*
883  * We don't include trailing whitespace in the result. dstlen tracks how
884  * much of the output string is known to not be trailing whitespace.
885  */
886  dstlen = 0;
887  has_escapes = false;
888  for (;;)
889  {
890  switch (*p)
891  {
892  case '\0':
893  goto ending_error;
894  case '{':
895  ereturn(escontext, ATOK_ERROR,
896  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
897  errmsg("malformed array literal: \"%s\"", origStr),
898  errdetail("Unexpected \"%c\" character.",
899  '{')));
900  case '"':
901  /* Must double-quote all or none of an element. */
902  ereturn(escontext, ATOK_ERROR,
903  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
904  errmsg("malformed array literal: \"%s\"", origStr),
905  errdetail("Incorrectly quoted array element.")));
906  case '\\':
907  /* Skip backslash, copy next character as-is. */
908  p++;
909  if (*p == '\0')
910  goto ending_error;
911  appendStringInfoChar(elembuf, *p++);
912  dstlen = elembuf->len; /* treat it as non-whitespace */
913  has_escapes = true;
914  break;
915  default:
916  /* End of elem? */
917  if (*p == typdelim || *p == '}')
918  {
919  /* hack: truncate the output string to dstlen */
920  elembuf->data[dstlen] = '\0';
921  elembuf->len = dstlen;
922  *srcptr = p;
923  /* Check if it's unquoted "NULL" */
924  if (Array_nulls && !has_escapes &&
925  pg_strcasecmp(elembuf->data, "NULL") == 0)
926  return ATOK_ELEM_NULL;
927  else
928  return ATOK_ELEM;
929  }
930  appendStringInfoChar(elembuf, *p);
931  if (!scanner_isspace(*p))
932  dstlen = elembuf->len;
933  p++;
934  break;
935  }
936  }
937 
938 ending_error:
939  ereturn(escontext, ATOK_ERROR,
940  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
941  errmsg("malformed array literal: \"%s\"", origStr),
942  errdetail("Unexpected end of input.")));
943 }
bool Array_nulls
Definition: arrayfuncs.c:43
void resetStringInfo(StringInfo str)
Definition: stringinfo.c:78
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:194

References appendStringInfoChar(), Array_nulls, ATOK_DELIM, ATOK_ELEM, ATOK_ELEM_NULL, ATOK_ERROR, ATOK_LEVEL_END, ATOK_LEVEL_START, StringInfoData::data, ereturn, errcode(), errdetail(), errmsg(), StringInfoData::len, pg_strcasecmp(), resetStringInfo(), and scanner_isspace().

Referenced by ReadArrayStr().

◆ ReadDimensionInt()

static bool ReadDimensionInt ( char **  srcptr,
int *  result,
const char *  origStr,
Node escontext 
)
static

Definition at line 519 of file arrayfuncs.c.

521 {
522  char *p = *srcptr;
523  long l;
524 
525  /* don't accept leading whitespace */
526  if (!isdigit((unsigned char) *p) && *p != '-' && *p != '+')
527  {
528  *result = 0;
529  return true;
530  }
531 
532  errno = 0;
533  l = strtol(p, srcptr, 10);
534 
535  if (errno == ERANGE || l > PG_INT32_MAX || l < PG_INT32_MIN)
536  ereturn(escontext, false,
537  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
538  errmsg("array bound is out of integer range")));
539 
540  *result = (int) l;
541  return true;
542 }
#define PG_INT32_MAX
Definition: c.h:576
#define PG_INT32_MIN
Definition: c.h:575

References ereturn, errcode(), errmsg(), PG_INT32_MAX, and PG_INT32_MIN.

Referenced by ReadArrayDimensions().

◆ trim_array()

Datum trim_array ( PG_FUNCTION_ARGS  )

Definition at line 6901 of file arrayfuncs.c.

6902 {
6904  int n = PG_GETARG_INT32(1);
6905  int array_length = (ARR_NDIM(v) > 0) ? ARR_DIMS(v)[0] : 0;
6906  int16 elmlen;
6907  bool elmbyval;
6908  char elmalign;
6909  int lower[MAXDIM];
6910  int upper[MAXDIM];
6911  bool lowerProvided[MAXDIM];
6912  bool upperProvided[MAXDIM];
6913  Datum result;
6914 
6915  /* Per spec, throw an error if out of bounds */
6916  if (n < 0 || n > array_length)
6917  ereport(ERROR,
6918  (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
6919  errmsg("number of elements to trim must be between 0 and %d",
6920  array_length)));
6921 
6922  /* Set all the bounds as unprovided except the first upper bound */
6923  memset(lowerProvided, false, sizeof(lowerProvided));
6924  memset(upperProvided, false, sizeof(upperProvided));
6925  if (ARR_NDIM(v) > 0)
6926  {
6927  upper[0] = ARR_LBOUND(v)[0] + array_length - n - 1;
6928  upperProvided[0] = true;
6929  }
6930 
6931  /* Fetch the needed information about the element type */
6932  get_typlenbyvalalign(ARR_ELEMTYPE(v), &elmlen, &elmbyval, &elmalign);
6933 
6934  /* Get the slice */
6935  result = array_get_slice(PointerGetDatum(v), 1,
6936  upper, lower, upperProvided, lowerProvided,
6937  -1, elmlen, elmbyval, elmalign);
6938 
6939  PG_RETURN_DATUM(result);
6940 }
Datum array_length(PG_FUNCTION_ARGS)
Definition: arrayfuncs.c:1763
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: arrayfuncs.c:2030
Datum lower(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:49
Datum upper(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:80

References ARR_DIMS, ARR_ELEMTYPE, ARR_LBOUND, ARR_NDIM, array_get_slice(), array_length(), ereport, errcode(), errmsg(), ERROR, get_typlenbyvalalign(), lower(), MAXDIM, PG_GETARG_ARRAYTYPE_P, PG_GETARG_INT32, PG_RETURN_DATUM, PointerGetDatum(), and upper().

◆ width_bucket_array()

Datum width_bucket_array ( PG_FUNCTION_ARGS  )

Definition at line 6669 of file arrayfuncs.c.

6670 {
6671  Datum operand = PG_GETARG_DATUM(0);
6672  ArrayType *thresholds = PG_GETARG_ARRAYTYPE_P(1);
6673  Oid collation = PG_GET_COLLATION();
6674  Oid element_type = ARR_ELEMTYPE(thresholds);
6675  int result;
6676 
6677  /* Check input */
6678  if (ARR_NDIM(thresholds) > 1)
6679  ereport(ERROR,
6680  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
6681  errmsg("thresholds must be one-dimensional array")));
6682 
6683  if (array_contains_nulls(thresholds))
6684  ereport(ERROR,
6685  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
6686  errmsg("thresholds array must not contain NULLs")));
6687 
6688  /* We have a dedicated implementation for float8 data */
6689  if (element_type == FLOAT8OID)
6690  result = width_bucket_array_float8(operand, thresholds);
6691  else
6692  {
6693  TypeCacheEntry *typentry;
6694 
6695  /* Cache information about the input type */
6696  typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
6697  if (typentry == NULL ||
6698  typentry->type_id != element_type)
6699  {
6700  typentry = lookup_type_cache(element_type,
6702  if (!OidIsValid(typentry->cmp_proc_finfo.fn_oid))
6703  ereport(ERROR,
6704  (errcode(ERRCODE_UNDEFINED_FUNCTION),
6705  errmsg("could not identify a comparison function for type %s",
6706  format_type_be(element_type))));
6707  fcinfo->flinfo->fn_extra = (void *) typentry;
6708  }
6709 
6710  /*
6711  * We have separate implementation paths for fixed- and variable-width
6712  * types, since indexing the array is a lot cheaper in the first case.
6713  */
6714  if (typentry->typlen > 0)
6715  result = width_bucket_array_fixed(operand, thresholds,
6716  collation, typentry);
6717  else
6718  result = width_bucket_array_variable(operand, thresholds,
6719  collation, typentry);
6720  }
6721 
6722  /* Avoid leaking memory when handed toasted input. */
6723  PG_FREE_IF_COPY(thresholds, 1);
6724 
6725  PG_RETURN_INT32(result);
6726 }
static int width_bucket_array_float8(Datum operand, ArrayType *thresholds)
Definition: arrayfuncs.c:6732
static int width_bucket_array_fixed(Datum operand, ArrayType *thresholds, Oid collation, TypeCacheEntry *typentry)
Definition: arrayfuncs.c:6776
static int width_bucket_array_variable(Datum operand, ArrayType *thresholds, Oid collation, TypeCacheEntry *typentry)
Definition: arrayfuncs.c:6831
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:260

References ARR_ELEMTYPE, ARR_NDIM, array_contains_nulls(), TypeCacheEntry::cmp_proc_finfo, ereport, errcode(), errmsg(), ERROR, FmgrInfo::fn_oid, format_type_be(), if(), lookup_type_cache(), OidIsValid, PG_FREE_IF_COPY, PG_GET_COLLATION, PG_GETARG_ARRAYTYPE_P, PG_GETARG_DATUM, PG_RETURN_INT32, TypeCacheEntry::type_id, TYPECACHE_CMP_PROC_FINFO, TypeCacheEntry::typlen, width_bucket_array_fixed(), width_bucket_array_float8(), and width_bucket_array_variable().

◆ width_bucket_array_fixed()

static int width_bucket_array_fixed ( Datum  operand,
ArrayType thresholds,
Oid  collation,
TypeCacheEntry typentry 
)
static

Definition at line 6776 of file arrayfuncs.c.

6780 {
6781  LOCAL_FCINFO(locfcinfo, 2);
6782  char *thresholds_data;
6783  int typlen = typentry->typlen;
6784  bool typbyval = typentry->typbyval;
6785  int left;
6786  int right;
6787 
6788  /*
6789  * Since we know the array contains no NULLs, we can just index it
6790  * directly.
6791  */
6792  thresholds_data = (char *) ARR_DATA_PTR(thresholds);
6793 
6794  InitFunctionCallInfoData(*locfcinfo, &typentry->cmp_proc_finfo, 2,
6795  collation, NULL, NULL);
6796 
6797  /* Find the bucket */
6798  left = 0;
6799  right = ArrayGetNItems(ARR_NDIM(thresholds), ARR_DIMS(thresholds));
6800  while (left < right)
6801  {
6802  int mid = (left + right) / 2;
6803  char *ptr;
6804  int32 cmpresult;
6805 
6806  ptr = thresholds_data + mid * typlen;
6807 
6808  locfcinfo->args[0].value = operand;
6809  locfcinfo->args[0].isnull = false;
6810  locfcinfo->args[1].value = fetch_att(ptr, typbyval, typlen);
6811  locfcinfo->args[1].isnull = false;
6812 
6813  cmpresult = DatumGetInt32(FunctionCallInvoke(locfcinfo));
6814 
6815  /* We don't expect comparison support functions to return null */
6816  Assert(!locfcinfo->isnull);
6817 
6818  if (cmpresult < 0)
6819  right = mid;
6820  else
6821  left = mid + 1;
6822  }
6823 
6824  return left;
6825 }

References ARR_DATA_PTR, ARR_DIMS, ARR_NDIM, ArrayGetNItems(), Assert(), TypeCacheEntry::cmp_proc_finfo, DatumGetInt32(), fetch_att(), FunctionCallInvoke, InitFunctionCallInfoData, LOCAL_FCINFO, TypeCacheEntry::typbyval, and TypeCacheEntry::typlen.

Referenced by width_bucket_array().

◆ width_bucket_array_float8()

static int width_bucket_array_float8 ( Datum  operand,
ArrayType thresholds 
)
static

Definition at line 6732 of file arrayfuncs.c.

6733 {
6734  float8 op = DatumGetFloat8(operand);
6735  float8 *thresholds_data;
6736  int left;
6737  int right;
6738 
6739  /*
6740  * Since we know the array contains no NULLs, we can just index it
6741  * directly.
6742  */
6743  thresholds_data = (float8 *) ARR_DATA_PTR(thresholds);
6744 
6745  left = 0;
6746  right = ArrayGetNItems(ARR_NDIM(thresholds), ARR_DIMS(thresholds));
6747 
6748  /*
6749  * If the probe value is a NaN, it's greater than or equal to all possible
6750  * threshold values (including other NaNs), so we need not search. Note
6751  * that this would give the same result as searching even if the array
6752  * contains multiple NaNs (as long as they're correctly sorted), since the
6753  * loop logic will find the rightmost of multiple equal threshold values.
6754  */
6755  if (isnan(op))
6756  return right;
6757 
6758  /* Find the bucket */
6759  while (left < right)
6760  {
6761  int mid = (left + right) / 2;
6762 
6763  if (isnan(thresholds_data[mid]) || op < thresholds_data[mid])
6764  right = mid;
6765  else
6766  left = mid + 1;
6767  }
6768 
6769  return left;
6770 }
static float8 DatumGetFloat8(Datum X)
Definition: postgres.h:494

References ARR_DATA_PTR, ARR_DIMS, ARR_NDIM, ArrayGetNItems(), and DatumGetFloat8().

Referenced by width_bucket_array().

◆ width_bucket_array_variable()

static int width_bucket_array_variable ( Datum  operand,
ArrayType thresholds,
Oid  collation,
TypeCacheEntry typentry 
)
static

Definition at line 6831 of file arrayfuncs.c.

6835 {
6836  LOCAL_FCINFO(locfcinfo, 2);
6837  char *thresholds_data;
6838  int typlen = typentry->typlen;
6839  bool typbyval = typentry->typbyval;
6840  char typalign = typentry->typalign;
6841  int left;
6842  int right;
6843 
6844  thresholds_data = (char *) ARR_DATA_PTR(thresholds);
6845 
6846  InitFunctionCallInfoData(*locfcinfo, &typentry->cmp_proc_finfo, 2,
6847  collation, NULL, NULL);
6848 
6849  /* Find the bucket */
6850  left = 0;
6851  right = ArrayGetNItems(ARR_NDIM(thresholds), ARR_DIMS(thresholds));
6852  while (left < right)
6853  {
6854  int mid = (left + right) / 2;
6855  char *ptr;
6856  int i;
6857  int32 cmpresult;
6858 
6859  /* Locate mid'th array element by advancing from left element */
6860  ptr = thresholds_data;
6861  for (i = left; i < mid; i++)
6862  {
6863  ptr = att_addlength_pointer(ptr, typlen, ptr);
6864  ptr = (char *) att_align_nominal(ptr, typalign);
6865  }
6866 
6867  locfcinfo->args[0].value = operand;
6868  locfcinfo->args[0].isnull = false;
6869  locfcinfo->args[1].value = fetch_att(ptr, typbyval, typlen);
6870  locfcinfo->args[1].isnull = false;
6871 
6872  cmpresult = DatumGetInt32(FunctionCallInvoke(locfcinfo));
6873 
6874  /* We don't expect comparison support functions to return null */
6875  Assert(!locfcinfo->isnull);
6876 
6877  if (cmpresult < 0)
6878  right = mid;
6879  else
6880  {
6881  left = mid + 1;
6882 
6883  /*
6884  * Move the thresholds pointer to match new "left" index, so we
6885  * don't have to seek over those elements again. This trick
6886  * ensures we do only O(N) array indexing work, not O(N^2).
6887  */
6888  ptr = att_addlength_pointer(ptr, typlen, ptr);
6889  thresholds_data = (char *) att_align_nominal(ptr, typalign);
6890  }
6891  }
6892 
6893  return left;
6894 }

References ARR_DATA_PTR, ARR_DIMS, ARR_NDIM, ArrayGetNItems(), Assert(), att_addlength_pointer, att_align_nominal, TypeCacheEntry::cmp_proc_finfo, DatumGetInt32(), fetch_att(), FunctionCallInvoke, i, InitFunctionCallInfoData, LOCAL_FCINFO, typalign, TypeCacheEntry::typalign, TypeCacheEntry::typbyval, and TypeCacheEntry::typlen.

Referenced by width_bucket_array().

Variable Documentation

◆ Array_nulls

bool Array_nulls = true

Definition at line 43 of file arrayfuncs.c.

Referenced by ReadArrayToken().