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

Go to the source code of this file.

Data Structures

struct  ArrayIteratorData
 
struct  generate_subscripts_fctx
 

Macros

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

Typedefs

typedef struct ArrayIteratorData ArrayIteratorData
 
typedef struct generate_subscripts_fctx generate_subscripts_fctx
 

Enumerations

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

Functions

static bool ReadArrayDimensions (char **srcptr, int *ndim_p, int *dim, int *lBound, const char *origStr, Node *escontext)
 
static bool ReadDimensionInt (char **srcptr, int *result, const char *origStr, Node *escontext)
 
static bool ReadArrayStr (char **srcptr, FmgrInfo *inputproc, Oid typioparam, int32 typmod, char typdelim, int typlen, bool typbyval, char typalign, int *ndim_p, int *dim, int *nitems_p, Datum **values_p, bool **nulls_p, const char *origStr, Node *escontext)
 
static ArrayToken ReadArrayToken (char **srcptr, StringInfo elembuf, char typdelim, const char *origStr, Node *escontext)
 
static void ReadArrayBinary (StringInfo buf, int nitems, FmgrInfo *receiveproc, Oid typioparam, int32 typmod, int typlen, bool typbyval, char typalign, Datum *values, bool *nulls, bool *hasnulls, int32 *nbytes)
 
static Datum array_get_element_expanded (Datum arraydatum, int nSubscripts, int *indx, int arraytyplen, int elmlen, bool elmbyval, char elmalign, bool *isNull)
 
static Datum array_set_element_expanded (Datum arraydatum, int nSubscripts, int *indx, Datum dataValue, bool isNull, int arraytyplen, int elmlen, bool elmbyval, char elmalign)
 
static bool array_get_isnull (const bits8 *nullbitmap, int offset)
 
static void array_set_isnull (bits8 *nullbitmap, int offset, bool isNull)
 
static Datum ArrayCast (char *value, bool byval, int len)
 
static int ArrayCastAndSet (Datum src, int typlen, bool typbyval, char typalign, char *dest)
 
static char * array_seek (char *ptr, int offset, bits8 *nullbitmap, int nitems, int typlen, bool typbyval, char typalign)
 
static int array_nelems_size (char *ptr, int offset, bits8 *nullbitmap, int nitems, int typlen, bool typbyval, char typalign)
 
static int array_copy (char *destptr, int nitems, char *srcptr, int offset, bits8 *nullbitmap, int typlen, bool typbyval, char typalign)
 
static int array_slice_size (char *arraydataptr, bits8 *arraynullsptr, int ndim, int *dim, int *lb, int *st, int *endp, int typlen, bool typbyval, char typalign)
 
static void array_extract_slice (ArrayType *newarray, int ndim, int *dim, int *lb, char *arraydataptr, bits8 *arraynullsptr, int *st, int *endp, int typlen, bool typbyval, char typalign)
 
static void array_insert_slice (ArrayType *destArray, ArrayType *origArray, ArrayType *srcArray, int ndim, int *dim, int *lb, int *st, int *endp, int typlen, bool typbyval, char typalign)
 
static int array_cmp (FunctionCallInfo fcinfo)
 
static ArrayTypecreate_array_envelope (int ndims, int *dimv, int *lbsv, int nbytes, Oid elmtype, int dataoffset)
 
static ArrayTypearray_fill_internal (ArrayType *dims, ArrayType *lbs, Datum value, bool isnull, Oid elmtype, FunctionCallInfo fcinfo)
 
static ArrayTypearray_replace_internal (ArrayType *array, Datum search, bool search_isnull, Datum replace, bool replace_isnull, bool remove, Oid collation, FunctionCallInfo fcinfo)
 
static int width_bucket_array_float8 (Datum operand, ArrayType *thresholds)
 
static int width_bucket_array_fixed (Datum operand, ArrayType *thresholds, Oid collation, TypeCacheEntry *typentry)
 
static int width_bucket_array_variable (Datum operand, ArrayType *thresholds, Oid collation, TypeCacheEntry *typentry)
 
Datum array_in (PG_FUNCTION_ARGS)
 
void CopyArrayEls (ArrayType *array, Datum *values, bool *nulls, int nitems, int typlen, bool typbyval, char typalign, bool freedata)
 
Datum array_out (PG_FUNCTION_ARGS)
 
Datum array_recv (PG_FUNCTION_ARGS)
 
Datum array_send (PG_FUNCTION_ARGS)
 
Datum array_ndims (PG_FUNCTION_ARGS)
 
Datum array_dims (PG_FUNCTION_ARGS)
 
Datum array_lower (PG_FUNCTION_ARGS)
 
Datum array_upper (PG_FUNCTION_ARGS)
 
Datum array_length (PG_FUNCTION_ARGS)
 
Datum array_cardinality (PG_FUNCTION_ARGS)
 
Datum array_get_element (Datum arraydatum, int nSubscripts, int *indx, int arraytyplen, int elmlen, bool elmbyval, char elmalign, bool *isNull)
 
Datum array_get_slice (Datum arraydatum, int nSubscripts, int *upperIndx, int *lowerIndx, bool *upperProvided, bool *lowerProvided, int arraytyplen, int elmlen, bool elmbyval, char elmalign)
 
Datum array_set_element (Datum arraydatum, int nSubscripts, int *indx, Datum dataValue, bool isNull, int arraytyplen, int elmlen, bool elmbyval, char elmalign)
 
Datum array_set_slice (Datum arraydatum, int nSubscripts, int *upperIndx, int *lowerIndx, bool *upperProvided, bool *lowerProvided, Datum srcArrayDatum, bool isNull, int arraytyplen, int elmlen, bool elmbyval, char elmalign)
 
Datum array_ref (ArrayType *array, int nSubscripts, int *indx, int arraytyplen, int elmlen, bool elmbyval, char elmalign, bool *isNull)
 
ArrayTypearray_set (ArrayType *array, int nSubscripts, int *indx, Datum dataValue, bool isNull, int arraytyplen, int elmlen, bool elmbyval, char elmalign)
 
Datum array_map (Datum arrayd, ExprState *exprstate, ExprContext *econtext, Oid retType, ArrayMapState *amstate)
 
ArrayTypeconstruct_array (Datum *elems, int nelems, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
 
ArrayTypeconstruct_array_builtin (Datum *elems, int nelems, Oid elmtype)
 
ArrayTypeconstruct_md_array (Datum *elems, bool *nulls, int ndims, int *dims, int *lbs, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
 
ArrayTypeconstruct_empty_array (Oid elmtype)
 
ExpandedArrayHeaderconstruct_empty_expanded_array (Oid element_type, MemoryContext parentcontext, ArrayMetaState *metacache)
 
void deconstruct_array (ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
 
void deconstruct_array_builtin (ArrayType *array, Oid elmtype, Datum **elemsp, bool **nullsp, int *nelemsp)
 
bool array_contains_nulls (ArrayType *array)
 
Datum array_eq (PG_FUNCTION_ARGS)
 
Datum array_ne (PG_FUNCTION_ARGS)
 
Datum array_lt (PG_FUNCTION_ARGS)
 
Datum array_gt (PG_FUNCTION_ARGS)
 
Datum array_le (PG_FUNCTION_ARGS)
 
Datum array_ge (PG_FUNCTION_ARGS)
 
Datum btarraycmp (PG_FUNCTION_ARGS)
 
Datum hash_array (PG_FUNCTION_ARGS)
 
Datum hash_array_extended (PG_FUNCTION_ARGS)
 
static bool array_contain_compare (AnyArrayType *array1, AnyArrayType *array2, Oid collation, bool matchall, void **fn_extra)
 
Datum arrayoverlap (PG_FUNCTION_ARGS)
 
Datum arraycontains (PG_FUNCTION_ARGS)
 
Datum arraycontained (PG_FUNCTION_ARGS)
 
ArrayIterator array_create_iterator (ArrayType *arr, int slice_ndim, ArrayMetaState *mstate)
 
bool array_iterate (ArrayIterator iterator, Datum *value, bool *isnull)
 
void array_free_iterator (ArrayIterator iterator)
 
void array_bitmap_copy (bits8 *destbitmap, int destoffset, const bits8 *srcbitmap, int srcoffset, int nitems)
 
ArrayBuildStateinitArrayResult (Oid element_type, MemoryContext rcontext, bool subcontext)
 
ArrayBuildStateinitArrayResultWithSize (Oid element_type, MemoryContext rcontext, bool subcontext, int initsize)
 
ArrayBuildStateaccumArrayResult (ArrayBuildState *astate, Datum dvalue, bool disnull, Oid element_type, MemoryContext rcontext)
 
Datum makeArrayResult (ArrayBuildState *astate, MemoryContext rcontext)
 
Datum makeMdArrayResult (ArrayBuildState *astate, int ndims, int *dims, int *lbs, MemoryContext rcontext, bool release)
 
ArrayBuildStateArrinitArrayResultArr (Oid array_type, Oid element_type, MemoryContext rcontext, bool subcontext)
 
ArrayBuildStateArraccumArrayResultArr (ArrayBuildStateArr *astate, Datum dvalue, bool disnull, Oid array_type, MemoryContext rcontext)
 
Datum makeArrayResultArr (ArrayBuildStateArr *astate, MemoryContext rcontext, bool release)
 
ArrayBuildStateAnyinitArrayResultAny (Oid input_type, MemoryContext rcontext, bool subcontext)
 
ArrayBuildStateAnyaccumArrayResultAny (ArrayBuildStateAny *astate, Datum dvalue, bool disnull, Oid input_type, MemoryContext rcontext)
 
Datum makeArrayResultAny (ArrayBuildStateAny *astate, MemoryContext rcontext, bool release)
 
Datum array_larger (PG_FUNCTION_ARGS)
 
Datum array_smaller (PG_FUNCTION_ARGS)
 
Datum generate_subscripts (PG_FUNCTION_ARGS)
 
Datum generate_subscripts_nodir (PG_FUNCTION_ARGS)
 
Datum array_fill_with_lower_bounds (PG_FUNCTION_ARGS)
 
Datum array_fill (PG_FUNCTION_ARGS)
 
Datum array_unnest (PG_FUNCTION_ARGS)
 
Datum array_unnest_support (PG_FUNCTION_ARGS)
 
Datum array_remove (PG_FUNCTION_ARGS)
 
Datum array_replace (PG_FUNCTION_ARGS)
 
Datum width_bucket_array (PG_FUNCTION_ARGS)
 
Datum trim_array (PG_FUNCTION_ARGS)
 

Variables

bool Array_nulls = true
 

Macro Definition Documentation

◆ AARR_FREE_IF_COPY

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

Definition at line 50 of file arrayfuncs.c.

◆ APPENDCHAR

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

◆ APPENDSTR

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

◆ ASSGN

#define ASSGN   "="

Definition at line 48 of file arrayfuncs.c.

Typedef Documentation

◆ ArrayIteratorData

◆ generate_subscripts_fctx

Enumeration Type Documentation

◆ ArrayToken

enum ArrayToken
Enumerator
ATOK_LEVEL_START 
ATOK_LEVEL_END 
ATOK_DELIM 
ATOK_ELEM 
ATOK_ELEM_NULL 
ATOK_ERROR 

Definition at line 57 of file arrayfuncs.c.

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

Function Documentation

◆ accumArrayResult()

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

Definition at line 5331 of file arrayfuncs.c.

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

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

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

Referenced by ExecScanSubPlan(), and ExecSetParamPlan().

◆ accumArrayResultArr()

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

Definition at line 5531 of file arrayfuncs.c.

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

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

Referenced by accumArrayResultAny(), and array_agg_array_transfn().

◆ array_bitmap_copy()

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

Definition at line 4947 of file arrayfuncs.c.

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

References Assert, and nitems.

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

◆ array_cardinality()

Datum array_cardinality ( PG_FUNCTION_ARGS  )

Definition at line 1790 of file arrayfuncs.c.

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

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

◆ array_cmp()

static int array_cmp ( FunctionCallInfo  fcinfo)
static

Definition at line 3966 of file arrayfuncs.c.

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

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

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

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

◆ array_contains_nulls()

bool array_contains_nulls ( ArrayType array)

Definition at line 3748 of file arrayfuncs.c.

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

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

Referenced by _arrq_cons(), _lca(), _lt_q_regex(), _ltree_compress(), array_fill_internal(), array_iterator(), array_position_common(), array_positions(), ArrayGetIntegerTypmods(), arrq_cons(), cube_a_f8(), cube_a_f8_f8(), cube_subset(), get_jsonb_path_all(), get_path_all(), getWeights(), lt_q_regex(), pg_isolation_test_session_is_blocked(), pg_logical_slot_get_changes_guts(), sanity_check_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 4917 of file arrayfuncs.c.

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

References array_nelems_size(), nitems, and typalign.

Referenced by array_extract_slice(), and array_insert_slice().

◆ array_create_iterator()

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

Definition at line 4578 of file arrayfuncs.c.

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

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

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

◆ array_dims()

Datum array_dims ( PG_FUNCTION_ARGS  )

Definition at line 1668 of file arrayfuncs.c.

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

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

◆ array_eq()

Datum array_eq ( PG_FUNCTION_ARGS  )

Definition at line 3795 of file arrayfuncs.c.

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

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

Referenced by array_ne(), and CompareOpclassOptions().

◆ array_extract_slice()

static void array_extract_slice ( ArrayType newarray,
int  ndim,
int *  dim,
int *  lb,
char *  arraydataptr,
bits8 arraynullsptr,
int *  st,
int *  endp,
int  typlen,
bool  typbyval,
char  typalign 
)
static

Definition at line 5078 of file arrayfuncs.c.

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

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

Referenced by array_get_slice().

◆ array_fill()

Datum array_fill ( PG_FUNCTION_ARGS  )

Definition at line 6012 of file arrayfuncs.c.

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

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

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

Referenced by array_fill(), and array_fill_with_lower_bounds().

◆ array_fill_with_lower_bounds()

Datum array_fill_with_lower_bounds ( PG_FUNCTION_ARGS  )

Definition at line 5971 of file arrayfuncs.c.

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

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

◆ array_free_iterator()

void array_free_iterator ( ArrayIterator  iterator)

Definition at line 4740 of file arrayfuncs.c.

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

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

Referenced by array_position_common(), and array_positions().

◆ array_ge()

Datum array_ge ( PG_FUNCTION_ARGS  )

Definition at line 3948 of file arrayfuncs.c.

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

References array_cmp(), and PG_RETURN_BOOL.

◆ array_get_element()

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

Definition at line 1820 of file arrayfuncs.c.

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

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

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

◆ array_get_element_expanded()

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

Definition at line 1921 of file arrayfuncs.c.

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

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

Referenced by array_get_element().

◆ array_get_isnull()

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

Definition at line 4762 of file arrayfuncs.c.

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

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

◆ array_get_slice()

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

Definition at line 2030 of file arrayfuncs.c.

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

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

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

◆ array_gt()

Datum array_gt ( PG_FUNCTION_ARGS  )

Definition at line 3936 of file arrayfuncs.c.

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

References array_cmp(), and PG_RETURN_BOOL.

◆ array_in()

Datum array_in ( PG_FUNCTION_ARGS  )

Definition at line 179 of file arrayfuncs.c.

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

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

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

Referenced by array_set_slice().

◆ array_iterate()

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

Definition at line 4657 of file arrayfuncs.c.

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

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

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

◆ array_larger()

Datum array_larger ( PG_FUNCTION_ARGS  )

Definition at line 5866 of file arrayfuncs.c.

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

References array_cmp(), PG_GETARG_DATUM, and PG_RETURN_DATUM.

◆ array_le()

Datum array_le ( PG_FUNCTION_ARGS  )

Definition at line 3942 of file arrayfuncs.c.

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

References array_cmp(), and PG_RETURN_BOOL.

◆ array_length()

Datum array_length ( PG_FUNCTION_ARGS  )

Definition at line 1763 of file arrayfuncs.c.

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

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

Referenced by trim_array().

◆ array_lower()

Datum array_lower ( PG_FUNCTION_ARGS  )

Definition at line 1706 of file arrayfuncs.c.

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

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

◆ array_lt()

Datum array_lt ( PG_FUNCTION_ARGS  )

Definition at line 3930 of file arrayfuncs.c.

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

References array_cmp(), and PG_RETURN_BOOL.

◆ array_map()

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

Definition at line 3194 of file arrayfuncs.c.

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

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

Referenced by ExecEvalArrayCoerce().

◆ array_ndims()

Datum array_ndims ( PG_FUNCTION_ARGS  )

Definition at line 1652 of file arrayfuncs.c.

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

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

◆ array_ne()

Datum array_ne ( PG_FUNCTION_ARGS  )

Definition at line 3924 of file arrayfuncs.c.

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

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

◆ array_nelems_size()

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

Definition at line 4895 of file arrayfuncs.c.

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

References array_seek(), nitems, and typalign.

Referenced by array_copy(), and array_set_slice().

◆ array_out()

Datum array_out ( PG_FUNCTION_ARGS  )

Definition at line 1016 of file arrayfuncs.c.

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

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

Referenced by anyarray_out(), and anycompatiblearray_out().

◆ array_recv()

Datum array_recv ( PG_FUNCTION_ARGS  )

Definition at line 1271 of file arrayfuncs.c.

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

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

Referenced by int2vectorrecv(), and oidvectorrecv().

◆ array_ref()

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

Definition at line 3139 of file arrayfuncs.c.

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

References array_get_element(), and PointerGetDatum().

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

◆ array_remove()

Datum array_remove ( PG_FUNCTION_ARGS  )

Definition at line 6618 of file arrayfuncs.c.

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

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

◆ array_replace()

Datum array_replace ( PG_FUNCTION_ARGS  )

Definition at line 6640 of file arrayfuncs.c.

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

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

◆ array_replace_internal()

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

Definition at line 6360 of file arrayfuncs.c.

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

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

Referenced by array_remove(), and array_replace().

◆ array_seek()

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

Definition at line 4847 of file arrayfuncs.c.

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

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

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

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

◆ array_set_element()

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

Definition at line 2201 of file arrayfuncs.c.

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

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

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

◆ array_set_element_expanded()

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

Definition at line 2501 of file arrayfuncs.c.

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

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

Referenced by array_set_element().

◆ array_set_isnull()

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

Definition at line 4779 of file arrayfuncs.c.

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

Referenced by array_set_element().

◆ array_set_slice()

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

Definition at line 2806 of file arrayfuncs.c.

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

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

Referenced by array_subscript_assign_slice().

◆ array_slice_size()

static int array_slice_size ( char *  arraydataptr,
bits8 arraynullsptr,
int  ndim,
int *  dim,
int *  lb,
int *  st,
int *  endp,
int  typlen,
bool  typbyval,
char  typalign 
)
static

Definition at line 5018 of file arrayfuncs.c.

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

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

Referenced by array_get_slice(), and array_set_slice().

◆ array_smaller()

Datum array_smaller ( PG_FUNCTION_ARGS  )

Definition at line 5875 of file arrayfuncs.c.

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

References array_cmp(), PG_GETARG_DATUM, and PG_RETURN_DATUM.

◆ array_unnest()

Datum array_unnest ( PG_FUNCTION_ARGS  )

Definition at line 6233 of file arrayfuncs.c.

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

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

◆ array_unnest_support()

Datum array_unnest_support ( PG_FUNCTION_ARGS  )

Definition at line 6324 of file arrayfuncs.c.

6325 {
6326  Node *rawreq = (Node *) PG_GETARG_POINTER(0);
6327  Node *ret = NULL;
6328 
6329  if (IsA(rawreq, SupportRequestRows))
6330  {
6331  /* Try to estimate the number of rows returned */
6332  SupportRequestRows *req = (SupportRequestRows *) rawreq;
6333 
6334  if (is_funcclause(req->node)) /* be paranoid */
6335  {
6336  List *args = ((FuncExpr *) req->node)->args;
6337  Node *arg1;
6338 
6339  /* We can use estimated argument values here */
6341 
6342  req->rows = estimate_array_length(req->root, arg1);
6343  ret = (Node *) req;
6344  }
6345  }
6346 
6347  PG_RETURN_POINTER(ret);
6348 }
Node * estimate_expression_value(PlannerInfo *root, Node *node)
Definition: clauses.c: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 4797 of file arrayfuncs.c.

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

References fetch_att(), len, and value.

Referenced by array_get_element().

◆ ArrayCastAndSet()

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

Definition at line 4808 of file arrayfuncs.c.

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

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

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

◆ arraycontained()

Datum arraycontained ( PG_FUNCTION_ARGS  )

Definition at line 4541 of file arrayfuncs.c.

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

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