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

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

5819 {
5820  if (astate == NULL)
5821  astate = initArrayResultAny(input_type, rcontext, true);
5822 
5823  if (astate->scalarstate)
5824  (void) accumArrayResult(astate->scalarstate,
5825  dvalue, disnull,
5826  input_type, rcontext);
5827  else
5828  (void) accumArrayResultArr(astate->arraystate,
5829  dvalue, disnull,
5830  input_type, rcontext);
5831 
5832  return astate;
5833 }
ArrayBuildState * accumArrayResult(ArrayBuildState *astate, Datum dvalue, bool disnull, Oid element_type, MemoryContext rcontext)
Definition: arrayfuncs.c:5338
ArrayBuildStateAny * initArrayResultAny(Oid input_type, MemoryContext rcontext, bool subcontext)
Definition: arrayfuncs.c:5770
ArrayBuildStateArr * accumArrayResultArr(ArrayBuildStateArr *astate, Datum dvalue, bool disnull, Oid array_type, MemoryContext rcontext)
Definition: arrayfuncs.c:5538
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 5538 of file arrayfuncs.c.

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

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

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

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

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

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

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

4927 {
4928  int numbytes;
4929 
4930  numbytes = array_nelems_size(srcptr, offset, nullbitmap, nitems,
4931  typlen, typbyval, typalign);
4932  memcpy(destptr, srcptr, numbytes);
4933  return numbytes;
4934 }
static int array_nelems_size(char *ptr, int offset, bits8 *nullbitmap, int nitems, int typlen, bool typbyval, char typalign)
Definition: arrayfuncs.c:4902

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

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

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

5096 {
5097  char *destdataptr = ARR_DATA_PTR(newarray);
5098  bits8 *destnullsptr = ARR_NULLBITMAP(newarray);
5099  char *srcdataptr;
5100  int src_offset,
5101  dest_offset,
5102  prod[MAXDIM],
5103  span[MAXDIM],
5104  dist[MAXDIM],
5105  indx[MAXDIM];
5106  int i,
5107  j,
5108  inc;
5109 
5110  src_offset = ArrayGetOffset(ndim, dim, lb, st);
5111  srcdataptr = array_seek(arraydataptr, 0, arraynullsptr, src_offset,
5112  typlen, typbyval, typalign);
5113  mda_get_prod(ndim, dim, prod);
5114  mda_get_range(ndim, span, st, endp);
5115  mda_get_offset_values(ndim, dist, prod, span);
5116  for (i = 0; i < ndim; i++)
5117  indx[i] = 0;
5118  dest_offset = 0;
5119  j = ndim - 1;
5120  do
5121  {
5122  if (dist[j])
5123  {
5124  /* skip unwanted elements */
5125  srcdataptr = array_seek(srcdataptr, src_offset, arraynullsptr,
5126  dist[j],
5127  typlen, typbyval, typalign);
5128  src_offset += dist[j];
5129  }
5130  inc = array_copy(destdataptr, 1,
5131  srcdataptr, src_offset, arraynullsptr,
5132  typlen, typbyval, typalign);
5133  if (destnullsptr)
5134  array_bitmap_copy(destnullsptr, dest_offset,
5135  arraynullsptr, src_offset,
5136  1);
5137  destdataptr += inc;
5138  srcdataptr += inc;
5139  src_offset++;
5140  dest_offset++;
5141  } while ((j = mda_next_tuple(ndim, indx, span)) != -1);
5142 }
static int array_copy(char *destptr, int nitems, char *srcptr, int offset, bits8 *nullbitmap, int typlen, bool typbyval, char typalign)
Definition: arrayfuncs.c:4924
static char * array_seek(char *ptr, int offset, bits8 *nullbitmap, int nitems, int typlen, bool typbyval, char typalign)
Definition: arrayfuncs.c:4854
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 6019 of file arrayfuncs.c.

6020 {
6021  ArrayType *dims;
6022  ArrayType *result;
6023  Oid elmtype;
6024  Datum value;
6025  bool isnull;
6026 
6027  if (PG_ARGISNULL(1))
6028  ereport(ERROR,
6029  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
6030  errmsg("dimension array or low bound array cannot be null")));
6031 
6032  dims = PG_GETARG_ARRAYTYPE_P(1);
6033 
6034  if (!PG_ARGISNULL(0))
6035  {
6036  value = PG_GETARG_DATUM(0);
6037  isnull = false;
6038  }
6039  else
6040  {
6041  value = 0;
6042  isnull = true;
6043  }
6044 
6045  elmtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
6046  if (!OidIsValid(elmtype))
6047  elog(ERROR, "could not determine data type of input");
6048 
6049  result = array_fill_internal(dims, NULL, value, isnull, elmtype, fcinfo);
6050  PG_RETURN_ARRAYTYPE_P(result);
6051 }
#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:6071
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 @155 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 6071 of file arrayfuncs.c.

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

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

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

4748 {
4749  if (iterator->slice_ndim > 0)
4750  {
4751  pfree(iterator->slice_values);
4752  pfree(iterator->slice_nulls);
4753  }
4754  pfree(iterator);
4755 }

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

3956 {
3957  PG_RETURN_BOOL(array_cmp(fcinfo) >= 0);
3958 }
static int array_cmp(FunctionCallInfo fcinfo)
Definition: arrayfuncs.c:3973

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:4769
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:4804
#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 4769 of file arrayfuncs.c.

4770 {
4771  if (nullbitmap == NULL)
4772  return false; /* assume not null */
4773  if (nullbitmap[offset / 8] & (1 << (offset % 8)))
4774  return false; /* not null */
4775  return true;
4776 }

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:5025
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:5085
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 3943 of file arrayfuncs.c.

3944 {
3945  PG_RETURN_BOOL(array_cmp(fcinfo) > 0);
3946 }

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:150
#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:2325
@ 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 5158 of file arrayfuncs.c.

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

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

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

5874 {
5875  if (array_cmp(fcinfo) > 0)
5877  else
5879 }
#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 3949 of file arrayfuncs.c.

3950 {
3951  PG_RETURN_BOOL(array_cmp(fcinfo) <= 0);
3952 }

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

3938 {
3939  PG_RETURN_BOOL(array_cmp(fcinfo) < 0);
3940 }

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

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

3932 {
3934 }
Datum array_eq(PG_FUNCTION_ARGS)
Definition: arrayfuncs.c:3802

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

4904 {
4905  return array_seek(ptr, offset, nullbitmap, nitems,
4906  typlen, typbyval, typalign) - ptr;
4907 }

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:1696
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 3146 of file arrayfuncs.c.

3149 {
3150  return array_get_element(PointerGetDatum(array), nSubscripts, indx,
3151  arraytyplen, elmlen, elmbyval, elmalign,
3152  isNull);
3153 }
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 6625 of file arrayfuncs.c.

6626 {
6627  ArrayType *array;
6628  Datum search = PG_GETARG_DATUM(1);
6629  bool search_isnull = PG_ARGISNULL(1);
6630 
6631  if (PG_ARGISNULL(0))
6632  PG_RETURN_NULL();
6633  array = PG_GETARG_ARRAYTYPE_P(0);
6634 
6635  array = array_replace_internal(array,
6636  search, search_isnull,
6637  (Datum) 0, true,
6638  true, PG_GET_COLLATION(),
6639  fcinfo);
6640  PG_RETURN_ARRAYTYPE_P(array);
6641 }
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:6367

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

6648 {
6649  ArrayType *array;
6650  Datum search = PG_GETARG_DATUM(1);
6651  bool search_isnull = PG_ARGISNULL(1);
6652  Datum replace = PG_GETARG_DATUM(2);
6653  bool replace_isnull = PG_ARGISNULL(2);
6654 
6655  if (PG_ARGISNULL(0))
6656  PG_RETURN_NULL();
6657  array = PG_GETARG_ARRAYTYPE_P(0);
6658 
6659  array = array_replace_internal(array,
6660  search, search_isnull,
6661  replace, replace_isnull,
6662  false, PG_GET_COLLATION(),
6663  fcinfo);
6664  PG_RETURN_ARRAYTYPE_P(array);
6665 }

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

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

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

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:692
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:687
#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 3163 of file arrayfuncs.c.

3166 {
3168  nSubscripts, indx,
3169  dataValue, isNull,
3170  arraytyplen,
3171  elmlen, elmbyval, elmalign));
3172 }
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:4786
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:1215
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 4786 of file arrayfuncs.c.

4787 {
4788  int bitmask;
4789 
4790  nullbitmap += offset / 8;
4791  bitmask = 1 << (offset % 8);
4792  if (isNull)
4793  *nullbitmap &= ~bitmask;
4794  else
4795  *nullbitmap |= bitmask;
4796 }

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  /* compute "upperIndx[i] - lowerIndx[i] + 1", detecting overflow */
2891  if (pg_sub_s32_overflow(upperIndx[i], lowerIndx[i], &dim[i]) ||
2892  pg_add_s32_overflow(dim[i], 1, &dim[i]))
2893  ereport(ERROR,
2894  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
2895  errmsg("array size exceeds the maximum allowed (%d)",
2896  (int) MaxArraySize)));
2897 
2898  lb[i] = lowerIndx[i];
2899  }
2900 
2901  /* complain if too few source items; we ignore extras, however */
2902  if (nelems < ArrayGetNItems(nSubscripts, dim))
2903  ereport(ERROR,
2904  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
2905  errmsg("source array too small")));
2906 
2907  return PointerGetDatum(construct_md_array(dvalues, dnulls, nSubscripts,
2908  dim, lb, elmtype,
2909  elmlen, elmbyval, elmalign));
2910  }
2911 
2912  if (ndim < nSubscripts || ndim <= 0 || ndim > MAXDIM)
2913  ereport(ERROR,
2914  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
2915  errmsg("wrong number of array subscripts")));
2916 
2917  /* copy dim/lb since we may modify them */
2918  memcpy(dim, ARR_DIMS(array), ndim * sizeof(int));
2919  memcpy(lb, ARR_LBOUND(array), ndim * sizeof(int));
2920 
2921  newhasnulls = (ARR_HASNULL(array) || ARR_HASNULL(srcArray));
2922  addedbefore = addedafter = 0;
2923 
2924  /*
2925  * Check subscripts. We assume the existing subscripts passed
2926  * ArrayCheckBounds, so that dim[i] + lb[i] can be computed without
2927  * overflow. But we must beware of other overflows in our calculations of
2928  * new dim[] values.
2929  */
2930  if (ndim == 1)
2931  {
2932  Assert(nSubscripts == 1);
2933  if (!lowerProvided[0])
2934  lowerIndx[0] = lb[0];
2935  if (!upperProvided[0])
2936  upperIndx[0] = dim[0] + lb[0] - 1;
2937  if (lowerIndx[0] > upperIndx[0])
2938  ereport(ERROR,
2939  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
2940  errmsg("upper bound cannot be less than lower bound")));
2941  if (lowerIndx[0] < lb[0])
2942  {
2943  /* addedbefore = lb[0] - lowerIndx[0]; */
2944  /* dim[0] += addedbefore; */
2945  if (pg_sub_s32_overflow(lb[0], lowerIndx[0], &addedbefore) ||
2946  pg_add_s32_overflow(dim[0], addedbefore, &dim[0]))
2947  ereport(ERROR,
2948  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
2949  errmsg("array size exceeds the maximum allowed (%d)",
2950  (int) MaxArraySize)));
2951  lb[0] = lowerIndx[0];
2952  if (addedbefore > 1)
2953  newhasnulls = true; /* will insert nulls */
2954  }
2955  if (upperIndx[0] >= (dim[0] + lb[0]))
2956  {
2957  /* addedafter = upperIndx[0] - (dim[0] + lb[0]) + 1; */
2958  /* dim[0] += addedafter; */
2959  if (pg_sub_s32_overflow(upperIndx[0], dim[0] + lb[0], &addedafter) ||
2960  pg_add_s32_overflow(addedafter, 1, &addedafter) ||
2961  pg_add_s32_overflow(dim[0], addedafter, &dim[0]))
2962  ereport(ERROR,
2963  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
2964  errmsg("array size exceeds the maximum allowed (%d)",
2965  (int) MaxArraySize)));
2966  if (addedafter > 1)
2967  newhasnulls = true; /* will insert nulls */
2968  }
2969  }
2970  else
2971  {
2972  /*
2973  * XXX currently we do not support extending multi-dimensional arrays
2974  * during assignment
2975  */
2976  for (i = 0; i < nSubscripts; i++)
2977  {
2978  if (!lowerProvided[i])
2979  lowerIndx[i] = lb[i];
2980  if (!upperProvided[i])
2981  upperIndx[i] = dim[i] + lb[i] - 1;
2982  if (lowerIndx[i] > upperIndx[i])
2983  ereport(ERROR,
2984  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
2985  errmsg("upper bound cannot be less than lower bound")));
2986  if (lowerIndx[i] < lb[i] ||
2987  upperIndx[i] >= (dim[i] + lb[i]))
2988  ereport(ERROR,
2989  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
2990  errmsg("array subscript out of range")));
2991  }
2992  /* fill any missing subscript positions with full array range */
2993  for (; i < ndim; i++)
2994  {
2995  lowerIndx[i] = lb[i];
2996  upperIndx[i] = dim[i] + lb[i] - 1;
2997  if (lowerIndx[i] > upperIndx[i])
2998  ereport(ERROR,
2999  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
3000  errmsg("upper bound cannot be less than lower bound")));
3001  }
3002  }
3003 
3004  /* Do this mainly to check for overflow */
3005  nitems = ArrayGetNItems(ndim, dim);
3006  ArrayCheckBounds(ndim, dim, lb);
3007 
3008  /*
3009  * Make sure source array has enough entries. Note we ignore the shape of
3010  * the source array and just read entries serially.
3011  */
3012  mda_get_range(ndim, span, lowerIndx, upperIndx);
3013  nsrcitems = ArrayGetNItems(ndim, span);
3014  if (nsrcitems > ArrayGetNItems(ARR_NDIM(srcArray), ARR_DIMS(srcArray)))
3015  ereport(ERROR,
3016  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
3017  errmsg("source array too small")));
3018 
3019  /*
3020  * Compute space occupied by new entries, space occupied by replaced
3021  * entries, and required space for new array.
3022  */
3023  if (newhasnulls)
3024  overheadlen = ARR_OVERHEAD_WITHNULLS(ndim, nitems);
3025  else
3026  overheadlen = ARR_OVERHEAD_NONULLS(ndim);
3027  newitemsize = array_nelems_size(ARR_DATA_PTR(srcArray), 0,
3028  ARR_NULLBITMAP(srcArray), nsrcitems,
3029  elmlen, elmbyval, elmalign);
3030  oldoverheadlen = ARR_DATA_OFFSET(array);
3031  olddatasize = ARR_SIZE(array) - oldoverheadlen;
3032  if (ndim > 1)
3033  {
3034  /*
3035  * here we do not need to cope with extension of the array; it would
3036  * be a lot more complicated if we had to do so...
3037  */
3038  olditemsize = array_slice_size(ARR_DATA_PTR(array),
3039  ARR_NULLBITMAP(array),
3040  ndim, dim, lb,
3041  lowerIndx, upperIndx,
3042  elmlen, elmbyval, elmalign);
3043  lenbefore = lenafter = 0; /* keep compiler quiet */
3044  itemsbefore = itemsafter = nolditems = 0;
3045  }
3046  else
3047  {
3048  /*
3049  * here we must allow for possibility of slice larger than orig array
3050  * and/or not adjacent to orig array subscripts
3051  */
3052  int oldlb = ARR_LBOUND(array)[0];
3053  int oldub = oldlb + ARR_DIMS(array)[0] - 1;
3054  int slicelb = Max(oldlb, lowerIndx[0]);
3055  int sliceub = Min(oldub, upperIndx[0]);
3056  char *oldarraydata = ARR_DATA_PTR(array);
3057  bits8 *oldarraybitmap = ARR_NULLBITMAP(array);
3058 
3059  /* count/size of old array entries that will go before the slice */
3060  itemsbefore = Min(slicelb, oldub + 1) - oldlb;
3061  lenbefore = array_nelems_size(oldarraydata, 0, oldarraybitmap,
3062  itemsbefore,
3063  elmlen, elmbyval, elmalign);
3064  /* count/size of old array entries that will be replaced by slice */
3065  if (slicelb > sliceub)
3066  {
3067  nolditems = 0;
3068  olditemsize = 0;
3069  }
3070  else
3071  {
3072  nolditems = sliceub - slicelb + 1;
3073  olditemsize = array_nelems_size(oldarraydata + lenbefore,
3074  itemsbefore, oldarraybitmap,
3075  nolditems,
3076  elmlen, elmbyval, elmalign);
3077  }
3078  /* count/size of old array entries that will go after the slice */
3079  itemsafter = oldub + 1 - Max(sliceub + 1, oldlb);
3080  lenafter = olddatasize - lenbefore - olditemsize;
3081  }
3082 
3083  newsize = overheadlen + olddatasize - olditemsize + newitemsize;
3084 
3085  newarray = (ArrayType *) palloc0(newsize);
3086  SET_VARSIZE(newarray, newsize);
3087  newarray->ndim = ndim;
3088  newarray->dataoffset = newhasnulls ? overheadlen : 0;
3089  newarray->elemtype = ARR_ELEMTYPE(array);
3090  memcpy(ARR_DIMS(newarray), dim, ndim * sizeof(int));
3091  memcpy(ARR_LBOUND(newarray), lb, ndim * sizeof(int));
3092 
3093  if (ndim > 1)
3094  {
3095  /*
3096  * here we do not need to cope with extension of the array; it would
3097  * be a lot more complicated if we had to do so...
3098  */
3099  array_insert_slice(newarray, array, srcArray,
3100  ndim, dim, lb,
3101  lowerIndx, upperIndx,
3102  elmlen, elmbyval, elmalign);
3103  }
3104  else
3105  {
3106  /* fill in data */
3107  memcpy((char *) newarray + overheadlen,
3108  (char *) array + oldoverheadlen,
3109  lenbefore);
3110  memcpy((char *) newarray + overheadlen + lenbefore,
3111  ARR_DATA_PTR(srcArray),
3112  newitemsize);
3113  memcpy((char *) newarray + overheadlen + lenbefore + newitemsize,
3114  (char *) array + oldoverheadlen + lenbefore + olditemsize,
3115  lenafter);
3116  /* fill in nulls bitmap if needed */
3117  if (newhasnulls)
3118  {
3119  bits8 *newnullbitmap = ARR_NULLBITMAP(newarray);
3120  bits8 *oldnullbitmap = ARR_NULLBITMAP(array);
3121 
3122  /* palloc0 above already marked any inserted positions as nulls */
3123  array_bitmap_copy(newnullbitmap, addedbefore,
3124  oldnullbitmap, 0,
3125  itemsbefore);
3126  array_bitmap_copy(newnullbitmap, lowerIndx[0] - lb[0],
3127  ARR_NULLBITMAP(srcArray), 0,
3128  nsrcitems);
3129  array_bitmap_copy(newnullbitmap, addedbefore + itemsbefore + nolditems,
3130  oldnullbitmap, itemsbefore + nolditems,
3131  itemsafter);
3132  }
3133  }
3134 
3135  return PointerGetDatum(newarray);
3136 }
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:5158

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

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

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

5883 {
5884  if (array_cmp(fcinfo) < 0)
5886  else
5888 }

References array_cmp(), PG_GETARG_DATUM, and PG_RETURN_DATUM.

◆ array_unnest()

Datum array_unnest ( PG_FUNCTION_ARGS  )

Definition at line 6240 of file arrayfuncs.c.

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

6332 {
6333  Node *rawreq = (Node *) PG_GETARG_POINTER(0);
6334  Node *ret = NULL;
6335 
6336  if (IsA(rawreq, SupportRequestRows))
6337  {
6338  /* Try to estimate the number of rows returned */
6339  SupportRequestRows *req = (SupportRequestRows *) rawreq;
6340 
6341  if (is_funcclause(req->node)) /* be paranoid */
6342  {
6343  List *args = ((FuncExpr *) req->node)->args;
6344  Node *arg1;
6345 
6346  /* We can use estimated argument values here */
6348 
6349  req->rows = estimate_array_length(req->root, arg1);
6350  ret = (Node *) req;
6351  }
6352  }
6353 
6354  PG_RETURN_POINTER(ret);
6355 }
Node * estimate_expression_value(PlannerInfo *root, Node *node)
Definition: clauses.c:2395
#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 4804 of file arrayfuncs.c.

4805 {
4806  return fetch_att(value, byval, len);
4807 }
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 4815 of file arrayfuncs.c.

4820 {
4821  int inc;
4822 
4823  if (typlen > 0)
4824  {
4825  if (typbyval)
4826  store_att_byval(dest, src, typlen);
4827  else
4828  memmove(dest, DatumGetPointer(src), typlen);
4829  inc = att_align_nominal(typlen, typalign);
4830  }
4831  else
4832  {
4833  Assert(!typbyval);
4834  inc = att_addlength_datum(0, typlen, src);
4835  memmove(dest, DatumGetPointer(src), inc);
4836  inc = att_align_nominal(inc, typalign);
4837  }
4838 
4839  return inc;
4840 }
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 4548 of file arrayfuncs.c.

4549 {
4550  AnyArrayType *array1 = PG_GETARG_ANY_ARRAY_P(0);
4551  AnyArrayType *array2 = PG_GETARG_ANY_ARRAY_P(1);
4552  Oid collation = PG_GET_COLLATION();
4553  bool result;
4554 
4555  result = array_contain_compare(array1, array2, collation, true,
4556  &fcinfo->flinfo->fn_extra);
4557 
4558  /* Avoid leaking memory when handed toasted input. */
4559  AARR_FREE_IF_COPY(array1, 0);
4560  AARR_FREE_IF_COPY(array2, 1);
4561 
4562  PG_RETURN_BOOL(result);
4563 }
static bool array_contain_compare(AnyArrayType *array1, AnyArrayType *array2, Oid collation, bool matchall, void **fn_extra)
Definition: arrayfuncs.c:4369

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

4531 {
4532  AnyArrayType *array1 = PG_GETARG_ANY_ARRAY_P(0);
4533  AnyArrayType *array2 = PG_GETARG_ANY_ARRAY_P(1);
4534  Oid collation = PG_GET_COLLATION();
4535  bool result;
4536 
4537  result = array_contain_compare(array2, array1, collation, true,
4538  &fcinfo->flinfo->fn_extra);
4539 
4540  /* Avoid leaking memory when handed toasted input. */
4541  AARR_FREE_IF_COPY(array1, 0);
4542  AARR_FREE_IF_COPY(array2, 1);
4543 
4544  PG_RETURN_BOOL(result);
4545 }

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

4513 {
4514  AnyArrayType *array1 = PG_GETARG_ANY_ARRAY_P(0);
4515  AnyArrayType *array2 = PG_GETARG_ANY_ARRAY_P(1);
4516  Oid collation = PG_GET_COLLATION();
4517  bool result;
4518 
4519  result = array_contain_compare(array1, array2, collation, false,
4520  &fcinfo->flinfo->fn_extra);
4521 
4522  /* Avoid leaking memory when handed toasted input. */
4523  AARR_FREE_IF_COPY(array1, 0);
4524  AARR_FREE_IF_COPY(array2, 1);
4525 
4526  PG_RETURN_BOOL(result);
4527 }

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

3962 {
3963  PG_RETURN_INT32(array_cmp(fcinfo));
3964 }

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

3364 {
3365  int dims[1];
3366  int lbs[1];
3367 
3368  dims[0] = nelems;
3369  lbs[0] = 1;
3370 
3371  return construct_md_array(elems, NULL, 1, dims, lbs,
3372  elmtype, elmlen, elmbyval, elmalign);
3373 }

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

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

3588 {
3589  ArrayType *array = construct_empty_array(element_type);
3590  Datum d;
3591 
3592  d = expand_array(PointerGetDatum(array), parentcontext, metacache);
3593  pfree(array);
3594  return (ExpandedArrayHeader *) DatumGetEOHP(d);
3595 }
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 3482 of file arrayfuncs.c.

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

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

6056 {
6057  ArrayType *result;
6058 
6059  result = (ArrayType *) palloc0(nbytes);
6060  SET_VARSIZE(result, nbytes);
6061  result->ndim = ndims;
6062  result->dataoffset = dataoffset;
6063  result->elemtype = elmtype;
6064  memcpy(ARR_DIMS(result), dimv, ndims * sizeof(int));
6065  memcpy(ARR_LBOUND(result), lbsv, ndims * sizeof(int));
6066 
6067  return result;
6068 }

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

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

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

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

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

5904 {
5905  FuncCallContext *funcctx;
5906  MemoryContext oldcontext;
5908 
5909  /* stuff done only on the first call of the function */
5910  if (SRF_IS_FIRSTCALL())
5911  {
5913  int reqdim = PG_GETARG_INT32(1);
5914  int *lb,
5915  *dimv;
5916 
5917  /* create a function context for cross-call persistence */
5918  funcctx = SRF_FIRSTCALL_INIT();
5919 
5920  /* Sanity check: does it look like an array at all? */
5921  if (AARR_NDIM(v) <= 0 || AARR_NDIM(v) > MAXDIM)
5922  SRF_RETURN_DONE(funcctx);
5923 
5924  /* Sanity check: was the requested dim valid */
5925  if (reqdim <= 0 || reqdim > AARR_NDIM(v))
5926  SRF_RETURN_DONE(funcctx);
5927 
5928  /*
5929  * switch to memory context appropriate for multiple function calls
5930  */
5931  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
5933 
5934  lb = AARR_LBOUND(v);
5935  dimv = AARR_DIMS(v);
5936 
5937  fctx->lower = lb[reqdim - 1];
5938  fctx->upper = dimv[reqdim - 1] + lb[reqdim - 1] - 1;
5939  fctx->reverse = (PG_NARGS() < 3) ? false : PG_GETARG_BOOL(2);
5940 
5941  funcctx->user_fctx = fctx;
5942 
5943  MemoryContextSwitchTo(oldcontext);
5944  }
5945 
5946  funcctx = SRF_PERCALL_SETUP();
5947 
5948  fctx = funcctx->user_fctx;
5949 
5950  if (fctx->lower <= fctx->upper)
5951  {
5952  if (!fctx->reverse)
5953  SRF_RETURN_NEXT(funcctx, Int32GetDatum(fctx->lower++));
5954  else
5955  SRF_RETURN_NEXT(funcctx, Int32GetDatum(fctx->upper--));
5956  }
5957  else
5958  /* done when there are no more elements left */
5959  SRF_RETURN_DONE(funcctx);
5960 }
#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 5967 of file arrayfuncs.c.

5968 {
5969  /* just call the other one -- it can handle both cases */
5970  return generate_subscripts(fcinfo);
5971 }
Datum generate_subscripts(PG_FUNCTION_ARGS)
Definition: arrayfuncs.c:5903

References generate_subscripts().

◆ hash_array()

Datum hash_array ( PG_FUNCTION_ARGS  )

Definition at line 4146 of file arrayfuncs.c.

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

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

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

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

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

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

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

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

5410 {
5411  int ndims;
5412  int dims[1];
5413  int lbs[1];
5414 
5415  /* If no elements were presented, we want to create an empty array */
5416  ndims = (astate->nelems > 0) ? 1 : 0;
5417  dims[0] = astate->nelems;
5418  lbs[0] = 1;
5419 
5420  return makeMdArrayResult(astate, ndims, dims, lbs, rcontext,
5421  astate->private_cxt);
5422 }
Datum makeMdArrayResult(ArrayBuildState *astate, int ndims, int *dims, int *lbs, MemoryContext rcontext, bool release)
Definition: arrayfuncs.c:5440

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

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

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

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

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

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

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:589
#define PG_INT32_MIN
Definition: c.h:588

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

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

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

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

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

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

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

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