PostgreSQL Source Code  git master
arrayfuncs.c File Reference
#include "postgres.h"
#include <ctype.h>
#include <math.h>
#include "access/htup_details.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 51 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 49 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 58 of file arrayfuncs.c.

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

Function Documentation

◆ accumArrayResult()

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

Definition at line 5332 of file arrayfuncs.c.

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

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

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

◆ accumArrayResultAny()

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

Definition at line 5809 of file arrayfuncs.c.

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

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

Referenced by ExecScanSubPlan(), and ExecSetParamPlan().

◆ accumArrayResultArr()

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

Definition at line 5532 of file arrayfuncs.c.

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

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

Referenced by accumArrayResultAny(), and array_agg_array_transfn().

◆ array_bitmap_copy()

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

Definition at line 4948 of file arrayfuncs.c.

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

References Assert(), and nitems.

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

◆ array_cardinality()

Datum array_cardinality ( PG_FUNCTION_ARGS  )

Definition at line 1791 of file arrayfuncs.c.

1792 {
1794 
1796 }
#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 3967 of file arrayfuncs.c.

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

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

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

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

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

◆ array_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 4918 of file arrayfuncs.c.

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

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

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

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

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

◆ array_dims()

Datum array_dims ( PG_FUNCTION_ARGS  )

Definition at line 1669 of file arrayfuncs.c.

1670 {
1672  char *p;
1673  int i;
1674  int *dimv,
1675  *lb;
1676 
1677  /*
1678  * 33 since we assume 15 digits per number + ':' +'[]'
1679  *
1680  * +1 for trailing null
1681  */
1682  char buf[MAXDIM * 33 + 1];
1683 
1684  /* Sanity check: does it look like an array at all? */
1685  if (AARR_NDIM(v) <= 0 || AARR_NDIM(v) > MAXDIM)
1686  PG_RETURN_NULL();
1687 
1688  dimv = AARR_DIMS(v);
1689  lb = AARR_LBOUND(v);
1690 
1691  p = buf;
1692  for (i = 0; i < AARR_NDIM(v); i++)
1693  {
1694  sprintf(p, "[%d:%d]", lb[i], dimv[i] + lb[i] - 1);
1695  p += strlen(p);
1696  }
1697 
1699 }
#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 3796 of file arrayfuncs.c.

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

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

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

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

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

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

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

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

Referenced by array_position_common(), and array_positions().

◆ array_ge()

Datum array_ge ( PG_FUNCTION_ARGS  )

Definition at line 3949 of file arrayfuncs.c.

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

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

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

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

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

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

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

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

References array_cmp(), and PG_RETURN_BOOL.

◆ array_in()

Datum array_in ( PG_FUNCTION_ARGS  )

Definition at line 180 of file arrayfuncs.c.

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

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

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

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

5868 {
5869  if (array_cmp(fcinfo) > 0)
5871  else
5873 }
#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 3943 of file arrayfuncs.c.

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

References array_cmp(), and PG_RETURN_BOOL.

◆ array_length()

Datum array_length ( PG_FUNCTION_ARGS  )

Definition at line 1764 of file arrayfuncs.c.

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

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

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

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

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

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

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

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

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

3926 {
3928 }
Datum array_eq(PG_FUNCTION_ARGS)
Definition: arrayfuncs.c:3796

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

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

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

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

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

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

References array_get_element(), and PointerGetDatum().

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

◆ array_remove()

Datum array_remove ( PG_FUNCTION_ARGS  )

Definition at line 6619 of file arrayfuncs.c.

6620 {
6621  ArrayType *array;
6622  Datum search = PG_GETARG_DATUM(1);
6623  bool search_isnull = PG_ARGISNULL(1);
6624 
6625  if (PG_ARGISNULL(0))
6626  PG_RETURN_NULL();
6627  array = PG_GETARG_ARRAYTYPE_P(0);
6628 
6629  array = array_replace_internal(array,
6630  search, search_isnull,
6631  (Datum) 0, true,
6632  true, PG_GET_COLLATION(),
6633  fcinfo);
6634  PG_RETURN_ARRAYTYPE_P(array);
6635 }
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:6361

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

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

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

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

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

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

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

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

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

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

◆ array_set_element()

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

Definition at line 2202 of file arrayfuncs.c.

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

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

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

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

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

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

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

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

5877 {
5878  if (array_cmp(fcinfo) < 0)
5880  else
5882 }

References array_cmp(), PG_GETARG_DATUM, and PG_RETURN_DATUM.

◆ array_unnest()

Datum array_unnest ( PG_FUNCTION_ARGS  )

Definition at line 6234 of file arrayfuncs.c.

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

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

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

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

4799 {
4800  return fetch_att(value, byval, len);
4801 }
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 4809 of file arrayfuncs.c.

4814 {
4815  int inc;
4816 
4817  if (typlen > 0)
4818  {
4819  if (typbyval)
4820  store_att_byval(dest, src, typlen);
4821  else
4822  memmove(dest, DatumGetPointer(src), typlen);
4823  inc = att_align_nominal(typlen, typalign);
4824  }
4825  else
4826  {
4827  Assert(!typbyval);
4828  inc = att_addlength_datum(0, typlen, src);
4829  memmove(dest, DatumGetPointer(src), inc);
4830  inc = att_align_nominal(inc, typalign);
4831  }
4832 
4833  return inc;
4834 }
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 4542 of file arrayfuncs.c.

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