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 "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  ArrayParseState {
  ARRAY_NO_LEVEL , ARRAY_LEVEL_STARTED , ARRAY_ELEM_STARTED , ARRAY_ELEM_COMPLETED ,
  ARRAY_QUOTED_ELEM_STARTED , ARRAY_QUOTED_ELEM_COMPLETED , ARRAY_ELEM_DELIMITED , ARRAY_LEVEL_COMPLETED ,
  ARRAY_LEVEL_DELIMITED
}
 

Functions

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

Variables

bool Array_nulls = true
 

Macro Definition Documentation

◆ AARR_FREE_IF_COPY

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

Definition at line 50 of file arrayfuncs.c.

◆ APPENDCHAR

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

◆ APPENDSTR

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

◆ ASSGN

#define ASSGN   "="

Definition at line 48 of file arrayfuncs.c.

Typedef Documentation

◆ ArrayIteratorData

◆ generate_subscripts_fctx

Enumeration Type Documentation

◆ ArrayParseState

Enumerator
ARRAY_NO_LEVEL 
ARRAY_LEVEL_STARTED 
ARRAY_ELEM_STARTED 
ARRAY_ELEM_COMPLETED 
ARRAY_QUOTED_ELEM_STARTED 
ARRAY_QUOTED_ELEM_COMPLETED 
ARRAY_ELEM_DELIMITED 
ARRAY_LEVEL_COMPLETED 
ARRAY_LEVEL_DELIMITED 

Definition at line 56 of file arrayfuncs.c.

57 {
ArrayParseState
Definition: arrayfuncs.c:57
@ ARRAY_LEVEL_COMPLETED
Definition: arrayfuncs.c:65
@ ARRAY_ELEM_DELIMITED
Definition: arrayfuncs.c:64
@ ARRAY_ELEM_STARTED
Definition: arrayfuncs.c:60
@ ARRAY_ELEM_COMPLETED
Definition: arrayfuncs.c:61
@ ARRAY_LEVEL_STARTED
Definition: arrayfuncs.c:59
@ ARRAY_QUOTED_ELEM_STARTED
Definition: arrayfuncs.c:62
@ ARRAY_QUOTED_ELEM_COMPLETED
Definition: arrayfuncs.c:63
@ ARRAY_LEVEL_DELIMITED
Definition: arrayfuncs.c:66
@ ARRAY_NO_LEVEL
Definition: arrayfuncs.c:58

Function Documentation

◆ accumArrayResult()

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

Definition at line 5297 of file arrayfuncs.c.

5301 {
5302  MemoryContext oldcontext;
5303 
5304  if (astate == NULL)
5305  {
5306  /* First time through --- initialize */
5307  astate = initArrayResult(element_type, rcontext, true);
5308  }
5309  else
5310  {
5311  Assert(astate->element_type == element_type);
5312  }
5313 
5314  oldcontext = MemoryContextSwitchTo(astate->mcontext);
5315 
5316  /* enlarge dvalues[]/dnulls[] if needed */
5317  if (astate->nelems >= astate->alen)
5318  {
5319  astate->alen *= 2;
5320  /* give an array-related error if we go past MaxAllocSize */
5321  if (!AllocSizeIsValid(astate->alen * sizeof(Datum)))
5322  ereport(ERROR,
5323  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
5324  errmsg("array size exceeds the maximum allowed (%d)",
5325  (int) MaxAllocSize)));
5326  astate->dvalues = (Datum *)
5327  repalloc(astate->dvalues, astate->alen * sizeof(Datum));
5328  astate->dnulls = (bool *)
5329  repalloc(astate->dnulls, astate->alen * sizeof(bool));
5330  }
5331 
5332  /*
5333  * Ensure pass-by-ref stuff is copied into mcontext; and detoast it too if
5334  * it's varlena. (You might think that detoasting is not needed here
5335  * because construct_md_array can detoast the array elements later.
5336  * However, we must not let construct_md_array modify the ArrayBuildState
5337  * because that would mean array_agg_finalfn damages its input, which is
5338  * verboten. Also, this way frequently saves one copying step.)
5339  */
5340  if (!disnull && !astate->typbyval)
5341  {
5342  if (astate->typlen == -1)
5343  dvalue = PointerGetDatum(PG_DETOAST_DATUM_COPY(dvalue));
5344  else
5345  dvalue = datumCopy(dvalue, astate->typbyval, astate->typlen);
5346  }
5347 
5348  astate->dvalues[astate->nelems] = dvalue;
5349  astate->dnulls[astate->nelems] = disnull;
5350  astate->nelems++;
5351 
5352  MemoryContextSwitchTo(oldcontext);
5353 
5354  return astate;
5355 }
ArrayBuildState * initArrayResult(Oid element_type, MemoryContext rcontext, bool subcontext)
Definition: arrayfuncs.c:5240
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:132
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
#define PG_DETOAST_DATUM_COPY(datum)
Definition: fmgr.h:242
Assert(fmt[strlen(fmt) - 1] !='\n')
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1476
#define AllocSizeIsValid(size)
Definition: memutils.h:42
#define MaxAllocSize
Definition: memutils.h:40
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:138
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
uintptr_t Datum
Definition: postgres.h:64
bool * dnulls
Definition: array.h:184
bool typbyval
Definition: array.h:189
MemoryContext mcontext
Definition: array.h:182
int16 typlen
Definition: array.h:188
Oid element_type
Definition: array.h:187
Datum * dvalues
Definition: array.h:183

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

5778 {
5779  if (astate == NULL)
5780  astate = initArrayResultAny(input_type, rcontext, true);
5781 
5782  if (astate->scalarstate)
5783  (void) accumArrayResult(astate->scalarstate,
5784  dvalue, disnull,
5785  input_type, rcontext);
5786  else
5787  (void) accumArrayResultArr(astate->arraystate,
5788  dvalue, disnull,
5789  input_type, rcontext);
5790 
5791  return astate;
5792 }
ArrayBuildState * accumArrayResult(ArrayBuildState *astate, Datum dvalue, bool disnull, Oid element_type, MemoryContext rcontext)
Definition: arrayfuncs.c:5297
ArrayBuildStateAny * initArrayResultAny(Oid input_type, MemoryContext rcontext, bool subcontext)
Definition: arrayfuncs.c:5729
ArrayBuildStateArr * accumArrayResultArr(ArrayBuildStateArr *astate, Datum dvalue, bool disnull, Oid array_type, MemoryContext rcontext)
Definition: arrayfuncs.c:5497
ArrayBuildStateArr * arraystate
Definition: array.h:223
ArrayBuildState * scalarstate
Definition: array.h:222

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

5501 {
5502  ArrayType *arg;
5503  MemoryContext oldcontext;
5504  int *dims,
5505  *lbs,
5506  ndims,
5507  nitems,
5508  ndatabytes;
5509  char *data;
5510  int i;
5511 
5512  /*
5513  * We disallow accumulating null subarrays. Another plausible definition
5514  * is to ignore them, but callers that want that can just skip calling
5515  * this function.
5516  */
5517  if (disnull)
5518  ereport(ERROR,
5519  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
5520  errmsg("cannot accumulate null arrays")));
5521 
5522  /* Detoast input array in caller's context */
5523  arg = DatumGetArrayTypeP(dvalue);
5524 
5525  if (astate == NULL)
5526  astate = initArrayResultArr(array_type, InvalidOid, rcontext, true);
5527  else
5528  Assert(astate->array_type == array_type);
5529 
5530  oldcontext = MemoryContextSwitchTo(astate->mcontext);
5531 
5532  /* Collect this input's dimensions */
5533  ndims = ARR_NDIM(arg);
5534  dims = ARR_DIMS(arg);
5535  lbs = ARR_LBOUND(arg);
5536  data = ARR_DATA_PTR(arg);
5537  nitems = ArrayGetNItems(ndims, dims);
5538  ndatabytes = ARR_SIZE(arg) - ARR_DATA_OFFSET(arg);
5539 
5540  if (astate->ndims == 0)
5541  {
5542  /* First input; check/save the dimensionality info */
5543 
5544  /* Should we allow empty inputs and just produce an empty output? */
5545  if (ndims == 0)
5546  ereport(ERROR,
5547  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
5548  errmsg("cannot accumulate empty arrays")));
5549  if (ndims + 1 > MAXDIM)
5550  ereport(ERROR,
5551  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
5552  errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
5553  ndims + 1, MAXDIM)));
5554 
5555  /*
5556  * The output array will have n+1 dimensions, with the ones after the
5557  * first matching the input's dimensions.
5558  */
5559  astate->ndims = ndims + 1;
5560  astate->dims[0] = 0;
5561  memcpy(&astate->dims[1], dims, ndims * sizeof(int));
5562  astate->lbs[0] = 1;
5563  memcpy(&astate->lbs[1], lbs, ndims * sizeof(int));
5564 
5565  /* Allocate at least enough data space for this item */
5566  astate->abytes = pg_nextpower2_32(Max(1024, ndatabytes + 1));
5567  astate->data = (char *) palloc(astate->abytes);
5568  }
5569  else
5570  {
5571  /* Second or later input: must match first input's dimensionality */
5572  if (astate->ndims != ndims + 1)
5573  ereport(ERROR,
5574  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
5575  errmsg("cannot accumulate arrays of different dimensionality")));
5576  for (i = 0; i < ndims; i++)
5577  {
5578  if (astate->dims[i + 1] != dims[i] || astate->lbs[i + 1] != lbs[i])
5579  ereport(ERROR,
5580  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
5581  errmsg("cannot accumulate arrays of different dimensionality")));
5582  }
5583 
5584  /* Enlarge data space if needed */
5585  if (astate->nbytes + ndatabytes > astate->abytes)
5586  {
5587  astate->abytes = Max(astate->abytes * 2,
5588  astate->nbytes + ndatabytes);
5589  astate->data = (char *) repalloc(astate->data, astate->abytes);
5590  }
5591  }
5592 
5593  /*
5594  * Copy the data portion of the sub-array. Note we assume that the
5595  * advertised data length of the sub-array is properly aligned. We do not
5596  * have to worry about detoasting elements since whatever's in the
5597  * sub-array should be OK already.
5598  */
5599  memcpy(astate->data + astate->nbytes, data, ndatabytes);
5600  astate->nbytes += ndatabytes;
5601 
5602  /* Deal with null bitmap if needed */
5603  if (astate->nullbitmap || ARR_HASNULL(arg))
5604  {
5605  int newnitems = astate->nitems + nitems;
5606 
5607  if (astate->nullbitmap == NULL)
5608  {
5609  /*
5610  * First input with nulls; we must retrospectively handle any
5611  * previous inputs by marking all their items non-null.
5612  */
5613  astate->aitems = pg_nextpower2_32(Max(256, newnitems + 1));
5614  astate->nullbitmap = (bits8 *) palloc((astate->aitems + 7) / 8);
5615  array_bitmap_copy(astate->nullbitmap, 0,
5616  NULL, 0,
5617  astate->nitems);
5618  }
5619  else if (newnitems > astate->aitems)
5620  {
5621  astate->aitems = Max(astate->aitems * 2, newnitems);
5622  astate->nullbitmap = (bits8 *)
5623  repalloc(astate->nullbitmap, (astate->aitems + 7) / 8);
5624  }
5625  array_bitmap_copy(astate->nullbitmap, astate->nitems,
5626  ARR_NULLBITMAP(arg), 0,
5627  nitems);
5628  }
5629 
5630  astate->nitems += nitems;
5631  astate->dims[0] += 1;
5632 
5633  MemoryContextSwitchTo(oldcontext);
5634 
5635  /* Release detoasted copy if any */
5636  if ((Pointer) arg != DatumGetPointer(dvalue))
5637  pfree(arg);
5638 
5639  return astate;
5640 }
#define ARR_NDIM(a)
Definition: array.h:283
#define ARR_DATA_PTR(a)
Definition: array.h:315
#define MAXDIM
Definition: array.h:75
#define ARR_NULLBITMAP(a)
Definition: array.h:293
#define DatumGetArrayTypeP(X)
Definition: array.h:254
#define ARR_SIZE(a)
Definition: array.h:282
#define ARR_DATA_OFFSET(a)
Definition: array.h:309
#define ARR_DIMS(a)
Definition: array.h:287
#define ARR_HASNULL(a)
Definition: array.h:284
#define ARR_LBOUND(a)
Definition: array.h:289
ArrayBuildStateArr * initArrayResultArr(Oid array_type, Oid element_type, MemoryContext rcontext, bool subcontext)
Definition: arrayfuncs.c:5451
void array_bitmap_copy(bits8 *destbitmap, int destoffset, const bits8 *srcbitmap, int srcoffset, int nitems)
Definition: arrayfuncs.c:4913
int ArrayGetNItems(int ndim, const int *dims)
Definition: arrayutils.c:76
#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:1456
void * palloc(Size size)
Definition: mcxt.c:1226
void * arg
static uint32 pg_nextpower2_32(uint32 num)
Definition: pg_bitutils.h:189
const void * data
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312
#define InvalidOid
Definition: postgres_ext.h:36
bits8 * nullbitmap
Definition: array.h:202
int lbs[MAXDIM]
Definition: array.h:209
MemoryContext mcontext
Definition: array.h:200
int dims[MAXDIM]
Definition: array.h:208

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

4916 {
4917  int destbitmask,
4918  destbitval,
4919  srcbitmask,
4920  srcbitval;
4921 
4922  Assert(destbitmap);
4923  if (nitems <= 0)
4924  return; /* don't risk fetch off end of memory */
4925  destbitmap += destoffset / 8;
4926  destbitmask = 1 << (destoffset % 8);
4927  destbitval = *destbitmap;
4928  if (srcbitmap)
4929  {
4930  srcbitmap += srcoffset / 8;
4931  srcbitmask = 1 << (srcoffset % 8);
4932  srcbitval = *srcbitmap;
4933  while (nitems-- > 0)
4934  {
4935  if (srcbitval & srcbitmask)
4936  destbitval |= destbitmask;
4937  else
4938  destbitval &= ~destbitmask;
4939  destbitmask <<= 1;
4940  if (destbitmask == 0x100)
4941  {
4942  *destbitmap++ = destbitval;
4943  destbitmask = 1;
4944  if (nitems > 0)
4945  destbitval = *destbitmap;
4946  }
4947  srcbitmask <<= 1;
4948  if (srcbitmask == 0x100)
4949  {
4950  srcbitmap++;
4951  srcbitmask = 1;
4952  if (nitems > 0)
4953  srcbitval = *srcbitmap;
4954  }
4955  }
4956  if (destbitmask != 1)
4957  *destbitmap = destbitval;
4958  }
4959  else
4960  {
4961  while (nitems-- > 0)
4962  {
4963  destbitval |= destbitmask;
4964  destbitmask <<= 1;
4965  if (destbitmask == 0x100)
4966  {
4967  *destbitmap++ = destbitval;
4968  destbitmask = 1;
4969  if (nitems > 0)
4970  destbitval = *destbitmap;
4971  }
4972  }
4973  if (destbitmask != 1)
4974  *destbitmap = destbitval;
4975  }
4976 }

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

1805 {
1807 
1809 }
#define AARR_DIMS(a)
Definition: array.h:331
#define PG_GETARG_ANY_ARRAY_P(n)
Definition: array.h:267
#define AARR_NDIM(a)
Definition: array.h:321
#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 3932 of file arrayfuncs.c.

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

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

4330 {
4331  LOCAL_FCINFO(locfcinfo, 2);
4332  bool result = matchall;
4333  Oid element_type = AARR_ELEMTYPE(array1);
4334  TypeCacheEntry *typentry;
4335  int nelems1;
4336  Datum *values2;
4337  bool *nulls2;
4338  int nelems2;
4339  int typlen;
4340  bool typbyval;
4341  char typalign;
4342  int i;
4343  int j;
4344  array_iter it1;
4345 
4346  if (element_type != AARR_ELEMTYPE(array2))
4347  ereport(ERROR,
4348  (errcode(ERRCODE_DATATYPE_MISMATCH),
4349  errmsg("cannot compare arrays of different element types")));
4350 
4351  /*
4352  * We arrange to look up the equality function only once per series of
4353  * calls, assuming the element type doesn't change underneath us. The
4354  * typcache is used so that we have no memory leakage when being used as
4355  * an index support function.
4356  */
4357  typentry = (TypeCacheEntry *) *fn_extra;
4358  if (typentry == NULL ||
4359  typentry->type_id != element_type)
4360  {
4361  typentry = lookup_type_cache(element_type,
4363  if (!OidIsValid(typentry->eq_opr_finfo.fn_oid))
4364  ereport(ERROR,
4365  (errcode(ERRCODE_UNDEFINED_FUNCTION),
4366  errmsg("could not identify an equality operator for type %s",
4367  format_type_be(element_type))));
4368  *fn_extra = (void *) typentry;
4369  }
4370  typlen = typentry->typlen;
4371  typbyval = typentry->typbyval;
4372  typalign = typentry->typalign;
4373 
4374  /*
4375  * Since we probably will need to scan array2 multiple times, it's
4376  * worthwhile to use deconstruct_array on it. We scan array1 the hard way
4377  * however, since we very likely won't need to look at all of it.
4378  */
4379  if (VARATT_IS_EXPANDED_HEADER(array2))
4380  {
4381  /* This should be safe even if input is read-only */
4382  deconstruct_expanded_array(&(array2->xpn));
4383  values2 = array2->xpn.dvalues;
4384  nulls2 = array2->xpn.dnulls;
4385  nelems2 = array2->xpn.nelems;
4386  }
4387  else
4388  deconstruct_array((ArrayType *) array2,
4389  element_type, typlen, typbyval, typalign,
4390  &values2, &nulls2, &nelems2);
4391 
4392  /*
4393  * Apply the comparison operator to each pair of array elements.
4394  */
4395  InitFunctionCallInfoData(*locfcinfo, &typentry->eq_opr_finfo, 2,
4396  collation, NULL, NULL);
4397 
4398  /* Loop over source data */
4399  nelems1 = ArrayGetNItems(AARR_NDIM(array1), AARR_DIMS(array1));
4400  array_iter_setup(&it1, array1);
4401 
4402  for (i = 0; i < nelems1; i++)
4403  {
4404  Datum elt1;
4405  bool isnull1;
4406 
4407  /* Get element, checking for NULL */
4408  elt1 = array_iter_next(&it1, &isnull1, i, typlen, typbyval, typalign);
4409 
4410  /*
4411  * We assume that the comparison operator is strict, so a NULL can't
4412  * match anything. XXX this diverges from the "NULL=NULL" behavior of
4413  * array_eq, should we act like that?
4414  */
4415  if (isnull1)
4416  {
4417  if (matchall)
4418  {
4419  result = false;
4420  break;
4421  }
4422  continue;
4423  }
4424 
4425  for (j = 0; j < nelems2; j++)
4426  {
4427  Datum elt2 = values2[j];
4428  bool isnull2 = nulls2 ? nulls2[j] : false;
4429  bool oprresult;
4430 
4431  if (isnull2)
4432  continue; /* can't match */
4433 
4434  /*
4435  * Apply the operator to the element pair; treat NULL as false
4436  */
4437  locfcinfo->args[0].value = elt1;
4438  locfcinfo->args[0].isnull = false;
4439  locfcinfo->args[1].value = elt2;
4440  locfcinfo->args[1].isnull = false;
4441  locfcinfo->isnull = false;
4442  oprresult = DatumGetBool(FunctionCallInvoke(locfcinfo));
4443  if (!locfcinfo->isnull && oprresult)
4444  break;
4445  }
4446 
4447  if (j < nelems2)
4448  {
4449  /* found a match for elt1 */
4450  if (!matchall)
4451  {
4452  result = true;
4453  break;
4454  }
4455  }
4456  else
4457  {
4458  /* no match for elt1 */
4459  if (matchall)
4460  {
4461  result = false;
4462  break;
4463  }
4464  }
4465  }
4466 
4467  return result;
4468 }
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:3578
int j
Definition: isn.c:74
static bool DatumGetBool(Datum X)
Definition: postgres.h:90
Datum * dvalues
Definition: array.h:139
FmgrInfo eq_opr_finfo
Definition: typcache.h:75
#define TYPECACHE_EQ_OPR_FINFO
Definition: typcache.h:141
ExpandedArrayHeader xpn
Definition: array.h:173

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

3715 {
3716  int nelems;
3717  bits8 *bitmap;
3718  int bitmask;
3719 
3720  /* Easy answer if there's no null bitmap */
3721  if (!ARR_HASNULL(array))
3722  return false;
3723 
3724  nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
3725 
3726  bitmap = ARR_NULLBITMAP(array);
3727 
3728  /* check whole bytes of the bitmap byte-at-a-time */
3729  while (nelems >= 8)
3730  {
3731  if (*bitmap != 0xFF)
3732  return true;
3733  bitmap++;
3734  nelems -= 8;
3735  }
3736 
3737  /* check last partial byte */
3738  bitmask = 1;
3739  while (nelems > 0)
3740  {
3741  if ((*bitmap & bitmask) == 0)
3742  return true;
3743  bitmask <<= 1;
3744  nelems--;
3745  }
3746 
3747  return false;
3748 }

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(), and width_bucket_array().

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

4886 {
4887  int numbytes;
4888 
4889  numbytes = array_nelems_size(srcptr, offset, nullbitmap, nitems,
4890  typlen, typbyval, typalign);
4891  memcpy(destptr, srcptr, numbytes);
4892  return numbytes;
4893 }
static int array_nelems_size(char *ptr, int offset, bits8 *nullbitmap, int nitems, int typlen, bool typbyval, char typalign)
Definition: arrayfuncs.c:4861

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

4545 {
4546  ArrayIterator iterator = palloc0(sizeof(ArrayIteratorData));
4547 
4548  /*
4549  * Sanity-check inputs --- caller should have got this right already
4550  */
4551  Assert(PointerIsValid(arr));
4552  if (slice_ndim < 0 || slice_ndim > ARR_NDIM(arr))
4553  elog(ERROR, "invalid arguments to array_create_iterator");
4554 
4555  /*
4556  * Remember basic info about the array and its element type
4557  */
4558  iterator->arr = arr;
4559  iterator->nullbitmap = ARR_NULLBITMAP(arr);
4560  iterator->nitems = ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr));
4561 
4562  if (mstate != NULL)
4563  {
4564  Assert(mstate->element_type == ARR_ELEMTYPE(arr));
4565 
4566  iterator->typlen = mstate->typlen;
4567  iterator->typbyval = mstate->typbyval;
4568  iterator->typalign = mstate->typalign;
4569  }
4570  else
4572  &iterator->typlen,
4573  &iterator->typbyval,
4574  &iterator->typalign);
4575 
4576  /*
4577  * Remember the slicing parameters.
4578  */
4579  iterator->slice_ndim = slice_ndim;
4580 
4581  if (slice_ndim > 0)
4582  {
4583  /*
4584  * Get pointers into the array's dims and lbound arrays to represent
4585  * the dims/lbound arrays of a slice. These are the same as the
4586  * rightmost N dimensions of the array.
4587  */
4588  iterator->slice_dims = ARR_DIMS(arr) + ARR_NDIM(arr) - slice_ndim;
4589  iterator->slice_lbound = ARR_LBOUND(arr) + ARR_NDIM(arr) - slice_ndim;
4590 
4591  /*
4592  * Compute number of elements in a slice.
4593  */
4594  iterator->slice_len = ArrayGetNItems(slice_ndim,
4595  iterator->slice_dims);
4596 
4597  /*
4598  * Create workspace for building sub-arrays.
4599  */
4600  iterator->slice_values = (Datum *)
4601  palloc(iterator->slice_len * sizeof(Datum));
4602  iterator->slice_nulls = (bool *)
4603  palloc(iterator->slice_len * sizeof(bool));
4604  }
4605 
4606  /*
4607  * Initialize our data pointer and linear element number. These will
4608  * advance through the array during array_iterate().
4609  */
4610  iterator->data_ptr = ARR_DATA_PTR(arr);
4611  iterator->current_item = 0;
4612 
4613  return iterator;
4614 }
#define ARR_ELEMTYPE(a)
Definition: array.h:285
#define PointerIsValid(pointer)
Definition: c.h:752
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2253
void * palloc0(Size size)
Definition: mcxt.c:1257
ArrayType * arr
Definition: arrayfuncs.c:73
bool * slice_nulls
Definition: arrayfuncs.c:86
Datum * slice_values
Definition: arrayfuncs.c:85
bits8 * nullbitmap
Definition: arrayfuncs.c:74
char typalign
Definition: array.h:234
int16 typlen
Definition: array.h:232
Oid element_type
Definition: array.h:231
bool typbyval
Definition: array.h:233

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

1683 {
1685  char *p;
1686  int i;
1687  int *dimv,
1688  *lb;
1689 
1690  /*
1691  * 33 since we assume 15 digits per number + ':' +'[]'
1692  *
1693  * +1 for trailing null
1694  */
1695  char buf[MAXDIM * 33 + 1];
1696 
1697  /* Sanity check: does it look like an array at all? */
1698  if (AARR_NDIM(v) <= 0 || AARR_NDIM(v) > MAXDIM)
1699  PG_RETURN_NULL();
1700 
1701  dimv = AARR_DIMS(v);
1702  lb = AARR_LBOUND(v);
1703 
1704  p = buf;
1705  for (i = 0; i < AARR_NDIM(v); i++)
1706  {
1707  sprintf(p, "[%d:%d]", lb[i], dimv[i] + lb[i] - 1);
1708  p += strlen(p);
1709  }
1710 
1712 }
#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:67
#define sprintf
Definition: port.h:240
text * cstring_to_text(const char *s)
Definition: varlena.c:182

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

3762 {
3763  LOCAL_FCINFO(locfcinfo, 2);
3764  AnyArrayType *array1 = PG_GETARG_ANY_ARRAY_P(0);
3765  AnyArrayType *array2 = PG_GETARG_ANY_ARRAY_P(1);
3766  Oid collation = PG_GET_COLLATION();
3767  int ndims1 = AARR_NDIM(array1);
3768  int ndims2 = AARR_NDIM(array2);
3769  int *dims1 = AARR_DIMS(array1);
3770  int *dims2 = AARR_DIMS(array2);
3771  int *lbs1 = AARR_LBOUND(array1);
3772  int *lbs2 = AARR_LBOUND(array2);
3773  Oid element_type = AARR_ELEMTYPE(array1);
3774  bool result = true;
3775  int nitems;
3776  TypeCacheEntry *typentry;
3777  int typlen;
3778  bool typbyval;
3779  char typalign;
3780  array_iter it1;
3781  array_iter it2;
3782  int i;
3783 
3784  if (element_type != AARR_ELEMTYPE(array2))
3785  ereport(ERROR,
3786  (errcode(ERRCODE_DATATYPE_MISMATCH),
3787  errmsg("cannot compare arrays of different element types")));
3788 
3789  /* fast path if the arrays do not have the same dimensionality */
3790  if (ndims1 != ndims2 ||
3791  memcmp(dims1, dims2, ndims1 * sizeof(int)) != 0 ||
3792  memcmp(lbs1, lbs2, ndims1 * sizeof(int)) != 0)
3793  result = false;
3794  else
3795  {
3796  /*
3797  * We arrange to look up the equality function only once per series of
3798  * calls, assuming the element type doesn't change underneath us. The
3799  * typcache is used so that we have no memory leakage when being used
3800  * as an index support function.
3801  */
3802  typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
3803  if (typentry == NULL ||
3804  typentry->type_id != element_type)
3805  {
3806  typentry = lookup_type_cache(element_type,
3808  if (!OidIsValid(typentry->eq_opr_finfo.fn_oid))
3809  ereport(ERROR,
3810  (errcode(ERRCODE_UNDEFINED_FUNCTION),
3811  errmsg("could not identify an equality operator for type %s",
3812  format_type_be(element_type))));
3813  fcinfo->flinfo->fn_extra = (void *) typentry;
3814  }
3815  typlen = typentry->typlen;
3816  typbyval = typentry->typbyval;
3817  typalign = typentry->typalign;
3818 
3819  /*
3820  * apply the operator to each pair of array elements.
3821  */
3822  InitFunctionCallInfoData(*locfcinfo, &typentry->eq_opr_finfo, 2,
3823  collation, NULL, NULL);
3824 
3825  /* Loop over source data */
3826  nitems = ArrayGetNItems(ndims1, dims1);
3827  array_iter_setup(&it1, array1);
3828  array_iter_setup(&it2, array2);
3829 
3830  for (i = 0; i < nitems; i++)
3831  {
3832  Datum elt1;
3833  Datum elt2;
3834  bool isnull1;
3835  bool isnull2;
3836  bool oprresult;
3837 
3838  /* Get elements, checking for NULL */
3839  elt1 = array_iter_next(&it1, &isnull1, i,
3840  typlen, typbyval, typalign);
3841  elt2 = array_iter_next(&it2, &isnull2, i,
3842  typlen, typbyval, typalign);
3843 
3844  /*
3845  * We consider two NULLs equal; NULL and not-NULL are unequal.
3846  */
3847  if (isnull1 && isnull2)
3848  continue;
3849  if (isnull1 || isnull2)
3850  {
3851  result = false;
3852  break;
3853  }
3854 
3855  /*
3856  * Apply the operator to the element pair; treat NULL as false
3857  */
3858  locfcinfo->args[0].value = elt1;
3859  locfcinfo->args[0].isnull = false;
3860  locfcinfo->args[1].value = elt2;
3861  locfcinfo->args[1].isnull = false;
3862  locfcinfo->isnull = false;
3863  oprresult = DatumGetBool(FunctionCallInvoke(locfcinfo));
3864  if (locfcinfo->isnull || !oprresult)
3865  {
3866  result = false;
3867  break;
3868  }
3869  }
3870  }
3871 
3872  /* Avoid leaking memory when handed toasted input. */
3873  AARR_FREE_IF_COPY(array1, 0);
3874  AARR_FREE_IF_COPY(array2, 1);
3875 
3876  PG_RETURN_BOOL(result);
3877 }
#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 5044 of file arrayfuncs.c.

5055 {
5056  char *destdataptr = ARR_DATA_PTR(newarray);
5057  bits8 *destnullsptr = ARR_NULLBITMAP(newarray);
5058  char *srcdataptr;
5059  int src_offset,
5060  dest_offset,
5061  prod[MAXDIM],
5062  span[MAXDIM],
5063  dist[MAXDIM],
5064  indx[MAXDIM];
5065  int i,
5066  j,
5067  inc;
5068 
5069  src_offset = ArrayGetOffset(ndim, dim, lb, st);
5070  srcdataptr = array_seek(arraydataptr, 0, arraynullsptr, src_offset,
5071  typlen, typbyval, typalign);
5072  mda_get_prod(ndim, dim, prod);
5073  mda_get_range(ndim, span, st, endp);
5074  mda_get_offset_values(ndim, dist, prod, span);
5075  for (i = 0; i < ndim; i++)
5076  indx[i] = 0;
5077  dest_offset = 0;
5078  j = ndim - 1;
5079  do
5080  {
5081  if (dist[j])
5082  {
5083  /* skip unwanted elements */
5084  srcdataptr = array_seek(srcdataptr, src_offset, arraynullsptr,
5085  dist[j],
5086  typlen, typbyval, typalign);
5087  src_offset += dist[j];
5088  }
5089  inc = array_copy(destdataptr, 1,
5090  srcdataptr, src_offset, arraynullsptr,
5091  typlen, typbyval, typalign);
5092  if (destnullsptr)
5093  array_bitmap_copy(destnullsptr, dest_offset,
5094  arraynullsptr, src_offset,
5095  1);
5096  destdataptr += inc;
5097  srcdataptr += inc;
5098  src_offset++;
5099  dest_offset++;
5100  } while ((j = mda_next_tuple(ndim, indx, span)) != -1);
5101 }
static int array_copy(char *destptr, int nitems, char *srcptr, int offset, bits8 *nullbitmap, int typlen, bool typbyval, char typalign)
Definition: arrayfuncs.c:4883
static char * array_seek(char *ptr, int offset, bits8 *nullbitmap, int nitems, int typlen, bool typbyval, char typalign)
Definition: arrayfuncs.c:4813
void mda_get_offset_values(int n, int *dist, const int *prod, const int *span)
Definition: arrayutils.c:204
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:174
void mda_get_prod(int n, const int *range, int *prod)
Definition: arrayutils.c:188
int mda_next_tuple(int n, int *curr, const int *span)
Definition: arrayutils.c:229

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

5979 {
5980  ArrayType *dims;
5981  ArrayType *result;
5982  Oid elmtype;
5983  Datum value;
5984  bool isnull;
5985 
5986  if (PG_ARGISNULL(1))
5987  ereport(ERROR,
5988  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
5989  errmsg("dimension array or low bound array cannot be null")));
5990 
5991  dims = PG_GETARG_ARRAYTYPE_P(1);
5992 
5993  if (!PG_ARGISNULL(0))
5994  {
5995  value = PG_GETARG_DATUM(0);
5996  isnull = false;
5997  }
5998  else
5999  {
6000  value = 0;
6001  isnull = true;
6002  }
6003 
6004  elmtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
6005  if (!OidIsValid(elmtype))
6006  elog(ERROR, "could not determine data type of input");
6007 
6008  result = array_fill_internal(dims, NULL, value, isnull, elmtype, fcinfo);
6009  PG_RETURN_ARRAYTYPE_P(result);
6010 }
#define PG_GETARG_ARRAYTYPE_P(n)
Definition: array.h:256
#define PG_RETURN_ARRAYTYPE_P(x)
Definition: array.h:258
static ArrayType * array_fill_internal(ArrayType *dims, ArrayType *lbs, Datum value, bool isnull, Oid elmtype, FunctionCallInfo fcinfo)
Definition: arrayfuncs.c:6030
Oid get_fn_expr_argtype(FmgrInfo *flinfo, int argnum)
Definition: fmgr.c:1893
#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 6030 of file arrayfuncs.c.

6033 {
6034  ArrayType *result;
6035  int *dimv;
6036  int *lbsv;
6037  int ndims;
6038  int nitems;
6039  int deflbs[MAXDIM];
6040  int16 elmlen;
6041  bool elmbyval;
6042  char elmalign;
6043  ArrayMetaState *my_extra;
6044 
6045  /*
6046  * Params checks
6047  */
6048  if (ARR_NDIM(dims) > 1)
6049  ereport(ERROR,
6050  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
6051  errmsg("wrong number of array subscripts"),
6052  errdetail("Dimension array must be one dimensional.")));
6053 
6054  if (array_contains_nulls(dims))
6055  ereport(ERROR,
6056  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
6057  errmsg("dimension values cannot be null")));
6058 
6059  dimv = (int *) ARR_DATA_PTR(dims);
6060  ndims = (ARR_NDIM(dims) > 0) ? ARR_DIMS(dims)[0] : 0;
6061 
6062  if (ndims < 0) /* we do allow zero-dimension arrays */
6063  ereport(ERROR,
6064  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6065  errmsg("invalid number of dimensions: %d", ndims)));
6066  if (ndims > MAXDIM)
6067  ereport(ERROR,
6068  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
6069  errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
6070  ndims, MAXDIM)));
6071 
6072  if (lbs != NULL)
6073  {
6074  if (ARR_NDIM(lbs) > 1)
6075  ereport(ERROR,
6076  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
6077  errmsg("wrong number of array subscripts"),
6078  errdetail("Dimension array must be one dimensional.")));
6079 
6080  if (array_contains_nulls(lbs))
6081  ereport(ERROR,
6082  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
6083  errmsg("dimension values cannot be null")));
6084 
6085  if (ndims != ((ARR_NDIM(lbs) > 0) ? ARR_DIMS(lbs)[0] : 0))
6086  ereport(ERROR,
6087  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
6088  errmsg("wrong number of array subscripts"),
6089  errdetail("Low bound array has different size than dimensions array.")));
6090 
6091  lbsv = (int *) ARR_DATA_PTR(lbs);
6092  }
6093  else
6094  {
6095  int i;
6096 
6097  for (i = 0; i < MAXDIM; i++)
6098  deflbs[i] = 1;
6099 
6100  lbsv = deflbs;
6101  }
6102 
6103  /* This checks for overflow of the array dimensions */
6104  nitems = ArrayGetNItems(ndims, dimv);
6105  ArrayCheckBounds(ndims, dimv, lbsv);
6106 
6107  /* fast track for empty array */
6108  if (nitems <= 0)
6109  return construct_empty_array(elmtype);
6110 
6111  /*
6112  * We arrange to look up info about element type only once per series of
6113  * calls, assuming the element type doesn't change underneath us.
6114  */
6115  my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
6116  if (my_extra == NULL)
6117  {
6118  fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
6119  sizeof(ArrayMetaState));
6120  my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
6121  my_extra->element_type = InvalidOid;
6122  }
6123 
6124  if (my_extra->element_type != elmtype)
6125  {
6126  /* Get info about element type */
6127  get_typlenbyvalalign(elmtype,
6128  &my_extra->typlen,
6129  &my_extra->typbyval,
6130  &my_extra->typalign);
6131  my_extra->element_type = elmtype;
6132  }
6133 
6134  elmlen = my_extra->typlen;
6135  elmbyval = my_extra->typbyval;
6136  elmalign = my_extra->typalign;
6137 
6138  /* compute required space */
6139  if (!isnull)
6140  {
6141  int i;
6142  char *p;
6143  int nbytes;
6144  int totbytes;
6145 
6146  /* make sure data is not toasted */
6147  if (elmlen == -1)
6149 
6150  nbytes = att_addlength_datum(0, elmlen, value);
6151  nbytes = att_align_nominal(nbytes, elmalign);
6152  Assert(nbytes > 0);
6153 
6154  totbytes = nbytes * nitems;
6155 
6156  /* check for overflow of multiplication or total request */
6157  if (totbytes / nbytes != nitems ||
6158  !AllocSizeIsValid(totbytes))
6159  ereport(ERROR,
6160  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
6161  errmsg("array size exceeds the maximum allowed (%d)",
6162  (int) MaxAllocSize)));
6163 
6164  /*
6165  * This addition can't overflow, but it might cause us to go past
6166  * MaxAllocSize. We leave it to palloc to complain in that case.
6167  */
6168  totbytes += ARR_OVERHEAD_NONULLS(ndims);
6169 
6170  result = create_array_envelope(ndims, dimv, lbsv, totbytes,
6171  elmtype, 0);
6172 
6173  p = ARR_DATA_PTR(result);
6174  for (i = 0; i < nitems; i++)
6175  p += ArrayCastAndSet(value, elmlen, elmbyval, elmalign, p);
6176  }
6177  else
6178  {
6179  int nbytes;
6180  int dataoffset;
6181 
6182  dataoffset = ARR_OVERHEAD_WITHNULLS(ndims, nitems);
6183  nbytes = dataoffset;
6184 
6185  result = create_array_envelope(ndims, dimv, lbsv, nbytes,
6186  elmtype, dataoffset);
6187 
6188  /* create_array_envelope already zeroed the bitmap, so we're done */
6189  }
6190 
6191  return result;
6192 }
#define ARR_OVERHEAD_WITHNULLS(ndims, nitems)
Definition: array.h:305
#define ARR_OVERHEAD_NONULLS(ndims)
Definition: array.h:303
bool array_contains_nulls(ArrayType *array)
Definition: arrayfuncs.c:3714
ArrayType * construct_empty_array(Oid elmtype)
Definition: arrayfuncs.c:3527
static ArrayType * create_array_envelope(int ndims, int *dimv, int *lbsv, int nbytes, Oid elmtype, int dataoffset)
Definition: arrayfuncs.c:6013
static int ArrayCastAndSet(Datum src, int typlen, bool typbyval, char typalign, char *dest)
Definition: arrayfuncs.c:4774
void ArrayCheckBounds(int ndim, const int *dims, const int *lb)
Definition: arrayutils.c:138
signed short int16
Definition: c.h:482
int errdetail(const char *fmt,...)
Definition: elog.c:1202
#define PG_DETOAST_DATUM(datum)
Definition: fmgr.h:240
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1021
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 5937 of file arrayfuncs.c.

5938 {
5939  ArrayType *dims;
5940  ArrayType *lbs;
5941  ArrayType *result;
5942  Oid elmtype;
5943  Datum value;
5944  bool isnull;
5945 
5946  if (PG_ARGISNULL(1) || PG_ARGISNULL(2))
5947  ereport(ERROR,
5948  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
5949  errmsg("dimension array or low bound array cannot be null")));
5950 
5951  dims = PG_GETARG_ARRAYTYPE_P(1);
5952  lbs = PG_GETARG_ARRAYTYPE_P(2);
5953 
5954  if (!PG_ARGISNULL(0))
5955  {
5956  value = PG_GETARG_DATUM(0);
5957  isnull = false;
5958  }
5959  else
5960  {
5961  value = 0;
5962  isnull = true;
5963  }
5964 
5965  elmtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
5966  if (!OidIsValid(elmtype))
5967  elog(ERROR, "could not determine data type of input");
5968 
5969  result = array_fill_internal(dims, lbs, value, isnull, elmtype, fcinfo);
5970  PG_RETURN_ARRAYTYPE_P(result);
5971 }

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

4707 {
4708  if (iterator->slice_ndim > 0)
4709  {
4710  pfree(iterator->slice_values);
4711  pfree(iterator->slice_nulls);
4712  }
4713  pfree(iterator);
4714 }

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

3915 {
3916  PG_RETURN_BOOL(array_cmp(fcinfo) >= 0);
3917 }
static int array_cmp(FunctionCallInfo fcinfo)
Definition: arrayfuncs.c:3932

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

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

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

4729 {
4730  if (nullbitmap == NULL)
4731  return false; /* assume not null */
4732  if (nullbitmap[offset / 8] & (1 << (offset % 8)))
4733  return false; /* not null */
4734  return true;
4735 }

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

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

3903 {
3904  PG_RETURN_BOOL(array_cmp(fcinfo) > 0);
3905 }

References array_cmp(), and PG_RETURN_BOOL.

◆ array_in()

Datum array_in ( PG_FUNCTION_ARGS  )

Definition at line 175 of file arrayfuncs.c.

176 {
177  char *string = PG_GETARG_CSTRING(0); /* external form */
178  Oid element_type = PG_GETARG_OID(1); /* type of an array
179  * element */
180  int32 typmod = PG_GETARG_INT32(2); /* typmod for array elements */
181  Node *escontext = fcinfo->context;
182  int typlen;
183  bool typbyval;
184  char typalign;
185  char typdelim;
186  Oid typioparam;
187  char *string_save,
188  *p;
189  int i,
190  nitems;
191  Datum *dataPtr;
192  bool *nullsPtr;
193  bool hasnulls;
194  int32 nbytes;
195  int32 dataoffset;
196  ArrayType *retval;
197  int ndim,
198  dim[MAXDIM],
199  lBound[MAXDIM];
200  ArrayMetaState *my_extra;
201 
202  /*
203  * We arrange to look up info about element type, including its input
204  * conversion proc, only once per series of calls, assuming the element
205  * type doesn't change underneath us.
206  */
207  my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
208  if (my_extra == NULL)
209  {
210  fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
211  sizeof(ArrayMetaState));
212  my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
213  my_extra->element_type = ~element_type;
214  }
215 
216  if (my_extra->element_type != element_type)
217  {
218  /*
219  * Get info about element type, including its input conversion proc
220  */
221  get_type_io_data(element_type, IOFunc_input,
222  &my_extra->typlen, &my_extra->typbyval,
223  &my_extra->typalign, &my_extra->typdelim,
224  &my_extra->typioparam, &my_extra->typiofunc);
225  fmgr_info_cxt(my_extra->typiofunc, &my_extra->proc,
226  fcinfo->flinfo->fn_mcxt);
227  my_extra->element_type = element_type;
228  }
229  typlen = my_extra->typlen;
230  typbyval = my_extra->typbyval;
231  typalign = my_extra->typalign;
232  typdelim = my_extra->typdelim;
233  typioparam = my_extra->typioparam;
234 
235  /* Make a modifiable copy of the input */
236  string_save = pstrdup(string);
237 
238  /*
239  * If the input string starts with dimension info, read and use that.
240  * Otherwise, we require the input to be in curly-brace style, and we
241  * prescan the input to determine dimensions.
242  *
243  * Dimension info takes the form of one or more [n] or [m:n] items. The
244  * outer loop iterates once per dimension item.
245  */
246  p = string_save;
247  ndim = 0;
248  for (;;)
249  {
250  char *q;
251  int ub;
252 
253  /*
254  * Note: we currently allow whitespace between, but not within,
255  * dimension items.
256  */
257  while (scanner_isspace(*p))
258  p++;
259  if (*p != '[')
260  break; /* no more dimension items */
261  p++;
262  if (ndim >= MAXDIM)
263  ereturn(escontext, (Datum) 0,
264  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
265  errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
266  ndim + 1, MAXDIM)));
267 
268  for (q = p; isdigit((unsigned char) *q) || (*q == '-') || (*q == '+'); q++)
269  /* skip */ ;
270  if (q == p) /* no digits? */
271  ereturn(escontext, (Datum) 0,
272  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
273  errmsg("malformed array literal: \"%s\"", string),
274  errdetail("\"[\" must introduce explicitly-specified array dimensions.")));
275 
276  if (*q == ':')
277  {
278  /* [m:n] format */
279  *q = '\0';
280  lBound[ndim] = atoi(p);
281  p = q + 1;
282  for (q = p; isdigit((unsigned char) *q) || (*q == '-') || (*q == '+'); q++)
283  /* skip */ ;
284  if (q == p) /* no digits? */
285  ereturn(escontext, (Datum) 0,
286  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
287  errmsg("malformed array literal: \"%s\"", string),
288  errdetail("Missing array dimension value.")));
289  }
290  else
291  {
292  /* [n] format */
293  lBound[ndim] = 1;
294  }
295  if (*q != ']')
296  ereturn(escontext, (Datum) 0,
297  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
298  errmsg("malformed array literal: \"%s\"", string),
299  errdetail("Missing \"%s\" after array dimensions.",
300  "]")));
301 
302  *q = '\0';
303  ub = atoi(p);
304  p = q + 1;
305  if (ub < lBound[ndim])
306  ereturn(escontext, (Datum) 0,
307  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
308  errmsg("upper bound cannot be less than lower bound")));
309 
310  dim[ndim] = ub - lBound[ndim] + 1;
311  ndim++;
312  }
313 
314  if (ndim == 0)
315  {
316  /* No array dimensions, so intuit dimensions from brace structure */
317  if (*p != '{')
318  ereturn(escontext, (Datum) 0,
319  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
320  errmsg("malformed array literal: \"%s\"", string),
321  errdetail("Array value must start with \"{\" or dimension information.")));
322  ndim = ArrayCount(p, dim, typdelim, escontext);
323  if (ndim < 0)
324  PG_RETURN_NULL();
325  for (i = 0; i < ndim; i++)
326  lBound[i] = 1;
327  }
328  else
329  {
330  int ndim_braces,
331  dim_braces[MAXDIM];
332 
333  /* If array dimensions are given, expect '=' operator */
334  if (strncmp(p, ASSGN, strlen(ASSGN)) != 0)
335  ereturn(escontext, (Datum) 0,
336  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
337  errmsg("malformed array literal: \"%s\"", string),
338  errdetail("Missing \"%s\" after array dimensions.",
339  ASSGN)));
340  p += strlen(ASSGN);
341  while (scanner_isspace(*p))
342  p++;
343 
344  /*
345  * intuit dimensions from brace structure -- it better match what we
346  * were given
347  */
348  if (*p != '{')
349  ereturn(escontext, (Datum) 0,
350  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
351  errmsg("malformed array literal: \"%s\"", string),
352  errdetail("Array contents must start with \"{\".")));
353  ndim_braces = ArrayCount(p, dim_braces, typdelim, escontext);
354  if (ndim_braces < 0)
355  PG_RETURN_NULL();
356  if (ndim_braces != ndim)
357  ereturn(escontext, (Datum) 0,
358  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
359  errmsg("malformed array literal: \"%s\"", string),
360  errdetail("Specified array dimensions do not match array contents.")));
361  for (i = 0; i < ndim; ++i)
362  {
363  if (dim[i] != dim_braces[i])
364  ereturn(escontext, (Datum) 0,
365  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
366  errmsg("malformed array literal: \"%s\"", string),
367  errdetail("Specified array dimensions do not match array contents.")));
368  }
369  }
370 
371 #ifdef ARRAYDEBUG
372  printf("array_in- ndim %d (", ndim);
373  for (i = 0; i < ndim; i++)
374  {
375  printf(" %d", dim[i]);
376  };
377  printf(") for %s\n", string);
378 #endif
379 
380  /* This checks for overflow of the array dimensions */
381  nitems = ArrayGetNItemsSafe(ndim, dim, escontext);
382  if (nitems < 0)
383  PG_RETURN_NULL();
384  if (!ArrayCheckBoundsSafe(ndim, dim, lBound, escontext))
385  PG_RETURN_NULL();
386 
387  /* Empty array? */
388  if (nitems == 0)
390 
391  dataPtr = (Datum *) palloc(nitems * sizeof(Datum));
392  nullsPtr = (bool *) palloc(nitems * sizeof(bool));
393  if (!ReadArrayStr(p, string,
394  nitems, ndim, dim,
395  &my_extra->proc, typioparam, typmod,
396  typdelim,
397  typlen, typbyval, typalign,
398  dataPtr, nullsPtr,
399  &hasnulls, &nbytes, escontext))
400  PG_RETURN_NULL();
401  if (hasnulls)
402  {
403  dataoffset = ARR_OVERHEAD_WITHNULLS(ndim, nitems);
404  nbytes += dataoffset;
405  }
406  else
407  {
408  dataoffset = 0; /* marker for no null bitmap */
409  nbytes += ARR_OVERHEAD_NONULLS(ndim);
410  }
411  retval = (ArrayType *) palloc0(nbytes);
412  SET_VARSIZE(retval, nbytes);
413  retval->ndim = ndim;
414  retval->dataoffset = dataoffset;
415 
416  /*
417  * This comes from the array's pg_type.typelem (which points to the base
418  * data type's pg_type.oid) and stores system oids in user tables. This
419  * oid must be preserved by binary upgrades.
420  */
421  retval->elemtype = element_type;
422  memcpy(ARR_DIMS(retval), dim, ndim * sizeof(int));
423  memcpy(ARR_LBOUND(retval), lBound, ndim * sizeof(int));
424 
425  CopyArrayEls(retval,
426  dataPtr, nullsPtr, nitems,
427  typlen, typbyval, typalign,
428  true);
429 
430  pfree(dataPtr);
431  pfree(nullsPtr);
432  pfree(string_save);
433 
434  PG_RETURN_ARRAYTYPE_P(retval);
435 }
static bool ReadArrayStr(char *arrayStr, const char *origStr, int nitems, int ndim, int *dim, FmgrInfo *inputproc, Oid typioparam, int32 typmod, char typdelim, int typlen, bool typbyval, char typalign, Datum *values, bool *nulls, bool *hasnulls, int32 *nbytes, Node *escontext)
Definition: arrayfuncs.c:717
void CopyArrayEls(ArrayType *array, Datum *values, bool *nulls, int nitems, int typlen, bool typbyval, char typalign, bool freedata)
Definition: arrayfuncs.c:964
static int ArrayCount(const char *str, int *dim, char typdelim, Node *escontext)
Definition: arrayfuncs.c:448
#define ASSGN
Definition: arrayfuncs.c:48
int ArrayGetNItemsSafe(int ndim, const int *dims, struct Node *escontext)
Definition: arrayutils.c:86
bool ArrayCheckBoundsSafe(int ndim, const int *dims, const int *lb, struct Node *escontext)
Definition: arrayutils.c:148
#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:2307
@ IOFunc_input
Definition: lsyscache.h:35
char * pstrdup(const char *in)
Definition: mcxt.c:1644
#define printf(...)
Definition: port.h:244
bool scanner_isspace(char ch)
Definition: scansup.c:117
Oid typioparam
Definition: array.h:236
Oid typiofunc
Definition: array.h:237
FmgrInfo proc
Definition: array.h:238
char typdelim
Definition: array.h:235
Definition: nodes.h:129

References ARR_DIMS, ARR_LBOUND, ARR_OVERHEAD_NONULLS, ARR_OVERHEAD_WITHNULLS, ArrayCheckBoundsSafe(), ArrayCount(), ArrayGetNItemsSafe(), ASSGN, 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, MAXDIM, MemoryContextAlloc(), ArrayType::ndim, nitems, palloc(), palloc0(), pfree(), PG_GETARG_CSTRING, PG_GETARG_INT32, PG_GETARG_OID, PG_RETURN_ARRAYTYPE_P, PG_RETURN_NULL, printf, ArrayMetaState::proc, pstrdup(), ReadArrayStr(), scanner_isspace(), SET_VARSIZE, typalign, ArrayMetaState::typalign, ArrayMetaState::typbyval, ArrayMetaState::typdelim, ArrayMetaState::typiofunc, ArrayMetaState::typioparam, and ArrayMetaState::typlen.

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

5128 {
5129  char *destPtr = ARR_DATA_PTR(destArray);
5130  char *origPtr = ARR_DATA_PTR(origArray);
5131  char *srcPtr = ARR_DATA_PTR(srcArray);
5132  bits8 *destBitmap = ARR_NULLBITMAP(destArray);
5133  bits8 *origBitmap = ARR_NULLBITMAP(origArray);
5134  bits8 *srcBitmap = ARR_NULLBITMAP(srcArray);
5135  int orignitems = ArrayGetNItems(ARR_NDIM(origArray),
5136  ARR_DIMS(origArray));
5137  int dest_offset,
5138  orig_offset,
5139  src_offset,
5140  prod[MAXDIM],
5141  span[MAXDIM],
5142  dist[MAXDIM],
5143  indx[MAXDIM];
5144  int i,
5145  j,
5146  inc;
5147 
5148  dest_offset = ArrayGetOffset(ndim, dim, lb, st);
5149  /* copy items before the slice start */
5150  inc = array_copy(destPtr, dest_offset,
5151  origPtr, 0, origBitmap,
5152  typlen, typbyval, typalign);
5153  destPtr += inc;
5154  origPtr += inc;
5155  if (destBitmap)
5156  array_bitmap_copy(destBitmap, 0, origBitmap, 0, dest_offset);
5157  orig_offset = dest_offset;
5158  mda_get_prod(ndim, dim, prod);
5159  mda_get_range(ndim, span, st, endp);
5160  mda_get_offset_values(ndim, dist, prod, span);
5161  for (i = 0; i < ndim; i++)
5162  indx[i] = 0;
5163  src_offset = 0;
5164  j = ndim - 1;
5165  do
5166  {
5167  /* Copy/advance over elements between here and next part of slice */
5168  if (dist[j])
5169  {
5170  inc = array_copy(destPtr, dist[j],
5171  origPtr, orig_offset, origBitmap,
5172  typlen, typbyval, typalign);
5173  destPtr += inc;
5174  origPtr += inc;
5175  if (destBitmap)
5176  array_bitmap_copy(destBitmap, dest_offset,
5177  origBitmap, orig_offset,
5178  dist[j]);
5179  dest_offset += dist[j];
5180  orig_offset += dist[j];
5181  }
5182  /* Copy new element at this slice position */
5183  inc = array_copy(destPtr, 1,
5184  srcPtr, src_offset, srcBitmap,
5185  typlen, typbyval, typalign);
5186  if (destBitmap)
5187  array_bitmap_copy(destBitmap, dest_offset,
5188  srcBitmap, src_offset,
5189  1);
5190  destPtr += inc;
5191  srcPtr += inc;
5192  dest_offset++;
5193  src_offset++;
5194  /* Advance over old element at this slice position */
5195  origPtr = array_seek(origPtr, orig_offset, origBitmap, 1,
5196  typlen, typbyval, typalign);
5197  orig_offset++;
5198  } while ((j = mda_next_tuple(ndim, indx, span)) != -1);
5199 
5200  /* don't miss any data at the end */
5201  array_copy(destPtr, orignitems - orig_offset,
5202  origPtr, orig_offset, origBitmap,
5203  typlen, typbyval, typalign);
5204  if (destBitmap)
5205  array_bitmap_copy(destBitmap, dest_offset,
5206  origBitmap, orig_offset,
5207  orignitems - orig_offset);
5208 }

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

4624 {
4625  /* Done if we have reached the end of the array */
4626  if (iterator->current_item >= iterator->nitems)
4627  return false;
4628 
4629  if (iterator->slice_ndim == 0)
4630  {
4631  /*
4632  * Scalar case: return one element.
4633  */
4634  if (array_get_isnull(iterator->nullbitmap, iterator->current_item++))
4635  {
4636  *isnull = true;
4637  *value = (Datum) 0;
4638  }
4639  else
4640  {
4641  /* non-NULL, so fetch the individual Datum to return */
4642  char *p = iterator->data_ptr;
4643 
4644  *isnull = false;
4645  *value = fetch_att(p, iterator->typbyval, iterator->typlen);
4646 
4647  /* Move our data pointer forward to the next element */
4648  p = att_addlength_pointer(p, iterator->typlen, p);
4649  p = (char *) att_align_nominal(p, iterator->typalign);
4650  iterator->data_ptr = p;
4651  }
4652  }
4653  else
4654  {
4655  /*
4656  * Slice case: build and return an array of the requested size.
4657  */
4658  ArrayType *result;
4659  Datum *values = iterator->slice_values;
4660  bool *nulls = iterator->slice_nulls;
4661  char *p = iterator->data_ptr;
4662  int i;
4663 
4664  for (i = 0; i < iterator->slice_len; i++)
4665  {
4666  if (array_get_isnull(iterator->nullbitmap,
4667  iterator->current_item++))
4668  {
4669  nulls[i] = true;
4670  values[i] = (Datum) 0;
4671  }
4672  else
4673  {
4674  nulls[i] = false;
4675  values[i] = fetch_att(p, iterator->typbyval, iterator->typlen);
4676 
4677  /* Move our data pointer forward to the next element */
4678  p = att_addlength_pointer(p, iterator->typlen, p);
4679  p = (char *) att_align_nominal(p, iterator->typalign);
4680  }
4681  }
4682 
4683  iterator->data_ptr = p;
4684 
4685  result = construct_md_array(values,
4686  nulls,
4687  iterator->slice_ndim,
4688  iterator->slice_dims,
4689  iterator->slice_lbound,
4690  ARR_ELEMTYPE(iterator->arr),
4691  iterator->typlen,
4692  iterator->typbyval,
4693  iterator->typalign);
4694 
4695  *isnull = false;
4696  *value = PointerGetDatum(result);
4697  }
4698 
4699  return true;
4700 }
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:3441
static Datum values[MAXATTR]
Definition: bootstrap.c:156
#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 5832 of file arrayfuncs.c.

5833 {
5834  if (array_cmp(fcinfo) > 0)
5836  else
5838 }
#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 3908 of file arrayfuncs.c.

3909 {
3910  PG_RETURN_BOOL(array_cmp(fcinfo) <= 0);
3911 }

References array_cmp(), and PG_RETURN_BOOL.

◆ array_length()

Datum array_length ( PG_FUNCTION_ARGS  )

Definition at line 1777 of file arrayfuncs.c.

1778 {
1780  int reqdim = PG_GETARG_INT32(1);
1781  int *dimv;
1782  int result;
1783 
1784  /* Sanity check: does it look like an array at all? */
1785  if (AARR_NDIM(v) <= 0 || AARR_NDIM(v) > MAXDIM)
1786  PG_RETURN_NULL();
1787 
1788  /* Sanity check: was the requested dim valid */
1789  if (reqdim <= 0 || reqdim > AARR_NDIM(v))
1790  PG_RETURN_NULL();
1791 
1792  dimv = AARR_DIMS(v);
1793 
1794  result = dimv[reqdim - 1];
1795 
1796  PG_RETURN_INT32(result);
1797 }

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

1721 {
1723  int reqdim = PG_GETARG_INT32(1);
1724  int *lb;
1725  int result;
1726 
1727  /* Sanity check: does it look like an array at all? */
1728  if (AARR_NDIM(v) <= 0 || AARR_NDIM(v) > MAXDIM)
1729  PG_RETURN_NULL();
1730 
1731  /* Sanity check: was the requested dim valid */
1732  if (reqdim <= 0 || reqdim > AARR_NDIM(v))
1733  PG_RETURN_NULL();
1734 
1735  lb = AARR_LBOUND(v);
1736  result = lb[reqdim - 1];
1737 
1738  PG_RETURN_INT32(result);
1739 }

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

3897 {
3898  PG_RETURN_BOOL(array_cmp(fcinfo) < 0);
3899 }

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

3163 {
3164  AnyArrayType *v = DatumGetAnyArrayP(arrayd);
3165  ArrayType *result;
3166  Datum *values;
3167  bool *nulls;
3168  int *dim;
3169  int ndim;
3170  int nitems;
3171  int i;
3172  int32 nbytes = 0;
3173  int32 dataoffset;
3174  bool hasnulls;
3175  Oid inpType;
3176  int inp_typlen;
3177  bool inp_typbyval;
3178  char inp_typalign;
3179  int typlen;
3180  bool typbyval;
3181  char typalign;
3182  array_iter iter;
3183  ArrayMetaState *inp_extra;
3184  ArrayMetaState *ret_extra;
3185  Datum *transform_source = exprstate->innermost_caseval;
3186  bool *transform_source_isnull = exprstate->innermost_casenull;
3187 
3188  inpType = AARR_ELEMTYPE(v);
3189  ndim = AARR_NDIM(v);
3190  dim = AARR_DIMS(v);
3191  nitems = ArrayGetNItems(ndim, dim);
3192 
3193  /* Check for empty array */
3194  if (nitems <= 0)
3195  {
3196  /* Return empty array */
3197  return PointerGetDatum(construct_empty_array(retType));
3198  }
3199 
3200  /*
3201  * We arrange to look up info about input and return element types only
3202  * once per series of calls, assuming the element type doesn't change
3203  * underneath us.
3204  */
3205  inp_extra = &amstate->inp_extra;
3206  ret_extra = &amstate->ret_extra;
3207 
3208  if (inp_extra->element_type != inpType)
3209  {
3210  get_typlenbyvalalign(inpType,
3211  &inp_extra->typlen,
3212  &inp_extra->typbyval,
3213  &inp_extra->typalign);
3214  inp_extra->element_type = inpType;
3215  }
3216  inp_typlen = inp_extra->typlen;
3217  inp_typbyval = inp_extra->typbyval;
3218  inp_typalign = inp_extra->typalign;
3219 
3220  if (ret_extra->element_type != retType)
3221  {
3222  get_typlenbyvalalign(retType,
3223  &ret_extra->typlen,
3224  &ret_extra->typbyval,
3225  &ret_extra->typalign);
3226  ret_extra->element_type = retType;
3227  }
3228  typlen = ret_extra->typlen;
3229  typbyval = ret_extra->typbyval;
3230  typalign = ret_extra->typalign;
3231 
3232  /* Allocate temporary arrays for new values */
3233  values = (Datum *) palloc(nitems * sizeof(Datum));
3234  nulls = (bool *) palloc(nitems * sizeof(bool));
3235 
3236  /* Loop over source data */
3237  array_iter_setup(&iter, v);
3238  hasnulls = false;
3239 
3240  for (i = 0; i < nitems; i++)
3241  {
3242  /* Get source element, checking for NULL */
3243  *transform_source =
3244  array_iter_next(&iter, transform_source_isnull, i,
3245  inp_typlen, inp_typbyval, inp_typalign);
3246 
3247  /* Apply the given expression to source element */
3248  values[i] = ExecEvalExpr(exprstate, econtext, &nulls[i]);
3249 
3250  if (nulls[i])
3251  hasnulls = true;
3252  else
3253  {
3254  /* Ensure data is not toasted */
3255  if (typlen == -1)
3257  /* Update total result size */
3258  nbytes = att_addlength_datum(nbytes, typlen, values[i]);
3259  nbytes = att_align_nominal(nbytes, typalign);
3260  /* check for overflow of total request */
3261  if (!AllocSizeIsValid(nbytes))
3262  ereport(ERROR,
3263  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
3264  errmsg("array size exceeds the maximum allowed (%d)",
3265  (int) MaxAllocSize)));
3266  }
3267  }
3268 
3269  /* Allocate and fill the result array */
3270  if (hasnulls)
3271  {
3272  dataoffset = ARR_OVERHEAD_WITHNULLS(ndim, nitems);
3273  nbytes += dataoffset;
3274  }
3275  else
3276  {
3277  dataoffset = 0; /* marker for no null bitmap */
3278  nbytes += ARR_OVERHEAD_NONULLS(ndim);
3279  }
3280  result = (ArrayType *) palloc0(nbytes);
3281  SET_VARSIZE(result, nbytes);
3282  result->ndim = ndim;
3283  result->dataoffset = dataoffset;
3284  result->elemtype = retType;
3285  memcpy(ARR_DIMS(result), AARR_DIMS(v), ndim * sizeof(int));
3286  memcpy(ARR_LBOUND(result), AARR_LBOUND(v), ndim * sizeof(int));
3287 
3288  CopyArrayEls(result,
3289  values, nulls, nitems,
3290  typlen, typbyval, typalign,
3291  false);
3292 
3293  /*
3294  * Note: do not risk trying to pfree the results of the called expression
3295  */
3296  pfree(values);
3297  pfree(nulls);
3298 
3299  return PointerGetDatum(result);
3300 }
AnyArrayType * DatumGetAnyArrayP(Datum d)
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:332
ArrayMetaState inp_extra
Definition: array.h:246
ArrayMetaState ret_extra
Definition: array.h:247
bool * innermost_casenull
Definition: execnodes.h:128
Datum * innermost_caseval
Definition: execnodes.h:127

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

1667 {
1669 
1670  /* Sanity check: does it look like an array at all? */
1671  if (AARR_NDIM(v) <= 0 || AARR_NDIM(v) > MAXDIM)
1672  PG_RETURN_NULL();
1673 
1675 }

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

3891 {
3893 }
Datum array_eq(PG_FUNCTION_ARGS)
Definition: arrayfuncs.c:3761

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

4863 {
4864  return array_seek(ptr, offset, nullbitmap, nitems,
4865  typlen, typbyval, typalign) - ptr;
4866 }

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

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

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

3108 {
3109  return array_get_element(PointerGetDatum(array), nSubscripts, indx,
3110  arraytyplen, elmlen, elmbyval, elmalign,
3111  isNull);
3112 }
Datum array_get_element(Datum arraydatum, int nSubscripts, int *indx, int arraytyplen, int elmlen, bool elmbyval, char elmalign, bool *isNull)
Definition: arrayfuncs.c:1834

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

6582 {
6583  ArrayType *array;
6584  Datum search = PG_GETARG_DATUM(1);
6585  bool search_isnull = PG_ARGISNULL(1);
6586 
6587  if (PG_ARGISNULL(0))
6588  PG_RETURN_NULL();
6589  array = PG_GETARG_ARRAYTYPE_P(0);
6590 
6591  array = array_replace_internal(array,
6592  search, search_isnull,
6593  (Datum) 0, true,
6594  true, PG_GET_COLLATION(),
6595  fcinfo);
6596  PG_RETURN_ARRAYTYPE_P(array);
6597 }
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:6323

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

6604 {
6605  ArrayType *array;
6606  Datum search = PG_GETARG_DATUM(1);
6607  bool search_isnull = PG_ARGISNULL(1);
6608  Datum replace = PG_GETARG_DATUM(2);
6609  bool replace_isnull = PG_ARGISNULL(2);
6610 
6611  if (PG_ARGISNULL(0))
6612  PG_RETURN_NULL();
6613  array = PG_GETARG_ARRAYTYPE_P(0);
6614 
6615  array = array_replace_internal(array,
6616  search, search_isnull,
6617  replace, replace_isnull,
6618  false, PG_GET_COLLATION(),
6619  fcinfo);
6620  PG_RETURN_ARRAYTYPE_P(array);
6621 }

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

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

4815 {
4816  int bitmask;
4817  int i;
4818 
4819  /* easy if fixed-size elements and no NULLs */
4820  if (typlen > 0 && !nullbitmap)
4821  return ptr + nitems * ((Size) att_align_nominal(typlen, typalign));
4822 
4823  /* seems worth having separate loops for NULL and no-NULLs cases */
4824  if (nullbitmap)
4825  {
4826  nullbitmap += offset / 8;
4827  bitmask = 1 << (offset % 8);
4828 
4829  for (i = 0; i < nitems; i++)
4830  {
4831  if (*nullbitmap & bitmask)
4832  {
4833  ptr = att_addlength_pointer(ptr, typlen, ptr);
4834  ptr = (char *) att_align_nominal(ptr, typalign);
4835  }
4836  bitmask <<= 1;
4837  if (bitmask == 0x100)
4838  {
4839  nullbitmap++;
4840  bitmask = 1;
4841  }
4842  }
4843  }
4844  else
4845  {
4846  for (i = 0; i < nitems; i++)
4847  {
4848  ptr = att_addlength_pointer(ptr, typlen, ptr);
4849  ptr = (char *) att_align_nominal(ptr, typalign);
4850  }
4851  }
4852  return ptr;
4853 }
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 1562 of file arrayfuncs.c.

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

3125 {
3127  nSubscripts, indx,
3128  dataValue, isNull,
3129  arraytyplen,
3130  elmlen, elmbyval, elmalign));
3131 }
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:2215

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

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

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, MAXDIM, ArrayType::ndim, palloc(), palloc0(), PG_DETOAST_DATUM, 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 2499 of file arrayfuncs.c.

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

4746 {
4747  int bitmask;
4748 
4749  nullbitmap += offset / 8;
4750  bitmask = 1 << (offset % 8);
4751  if (isNull)
4752  *nullbitmap &= ~bitmask;
4753  else
4754  *nullbitmap |= bitmask;
4755 }

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

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

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, MAXDIM, mda_get_range(), Min, ArrayType::ndim, nitems, palloc0(), 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 4984 of file arrayfuncs.c.

4988 {
4989  int src_offset,
4990  span[MAXDIM],
4991  prod[MAXDIM],
4992  dist[MAXDIM],
4993  indx[MAXDIM];
4994  char *ptr;
4995  int i,
4996  j,
4997  inc;
4998  int count = 0;
4999 
5000  mda_get_range(ndim, span, st, endp);
5001 
5002  /* Pretty easy for fixed element length without nulls ... */
5003  if (typlen > 0 && !arraynullsptr)
5004  return ArrayGetNItems(ndim, span) * att_align_nominal(typlen, typalign);
5005 
5006  /* Else gotta do it the hard way */
5007  src_offset = ArrayGetOffset(ndim, dim, lb, st);
5008  ptr = array_seek(arraydataptr, 0, arraynullsptr, src_offset,
5009  typlen, typbyval, typalign);
5010  mda_get_prod(ndim, dim, prod);
5011  mda_get_offset_values(ndim, dist, prod, span);
5012  for (i = 0; i < ndim; i++)
5013  indx[i] = 0;
5014  j = ndim - 1;
5015  do
5016  {
5017  if (dist[j])
5018  {
5019  ptr = array_seek(ptr, src_offset, arraynullsptr, dist[j],
5020  typlen, typbyval, typalign);
5021  src_offset += dist[j];
5022  }
5023  if (!array_get_isnull(arraynullsptr, src_offset))
5024  {
5025  inc = att_addlength_pointer(0, typlen, ptr);
5026  inc = att_align_nominal(inc, typalign);
5027  ptr += inc;
5028  count += inc;
5029  }
5030  src_offset++;
5031  } while ((j = mda_next_tuple(ndim, indx, span)) != -1);
5032  return count;
5033 }

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

5842 {
5843  if (array_cmp(fcinfo) < 0)
5845  else
5847 }

References array_cmp(), PG_GETARG_DATUM, and PG_RETURN_DATUM.

◆ array_unnest()

Datum array_unnest ( PG_FUNCTION_ARGS  )

Definition at line 6199 of file arrayfuncs.c.

6200 {
6201  typedef struct
6202  {
6203  array_iter iter;
6204  int nextelem;
6205  int numelems;
6206  int16 elmlen;
6207  bool elmbyval;
6208  char elmalign;
6209  } array_unnest_fctx;
6210 
6211  FuncCallContext *funcctx;
6212  array_unnest_fctx *fctx;
6213  MemoryContext oldcontext;
6214 
6215  /* stuff done only on the first call of the function */
6216  if (SRF_IS_FIRSTCALL())
6217  {
6218  AnyArrayType *arr;
6219 
6220  /* create a function context for cross-call persistence */
6221  funcctx = SRF_FIRSTCALL_INIT();
6222 
6223  /*
6224  * switch to memory context appropriate for multiple function calls
6225  */
6226  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
6227 
6228  /*
6229  * Get the array value and detoast if needed. We can't do this
6230  * earlier because if we have to detoast, we want the detoasted copy
6231  * to be in multi_call_memory_ctx, so it will go away when we're done
6232  * and not before. (If no detoast happens, we assume the originally
6233  * passed array will stick around till then.)
6234  */
6235  arr = PG_GETARG_ANY_ARRAY_P(0);
6236 
6237  /* allocate memory for user context */
6238  fctx = (array_unnest_fctx *) palloc(sizeof(array_unnest_fctx));
6239 
6240  /* initialize state */
6241  array_iter_setup(&fctx->iter, arr);
6242  fctx->nextelem = 0;
6243  fctx->numelems = ArrayGetNItems(AARR_NDIM(arr), AARR_DIMS(arr));
6244 
6245  if (VARATT_IS_EXPANDED_HEADER(arr))
6246  {
6247  /* we can just grab the type data from expanded array */
6248  fctx->elmlen = arr->xpn.typlen;
6249  fctx->elmbyval = arr->xpn.typbyval;
6250  fctx->elmalign = arr->xpn.typalign;
6251  }
6252  else
6254  &fctx->elmlen,
6255  &fctx->elmbyval,
6256  &fctx->elmalign);
6257 
6258  funcctx->user_fctx = fctx;
6259  MemoryContextSwitchTo(oldcontext);
6260  }
6261 
6262  /* stuff done on every call of the function */
6263  funcctx = SRF_PERCALL_SETUP();
6264  fctx = funcctx->user_fctx;
6265 
6266  if (fctx->nextelem < fctx->numelems)
6267  {
6268  int offset = fctx->nextelem++;
6269  Datum elem;
6270 
6271  elem = array_iter_next(&fctx->iter, &fcinfo->isnull, offset,
6272  fctx->elmlen, fctx->elmbyval, fctx->elmalign);
6273 
6274  SRF_RETURN_NEXT(funcctx, elem);
6275  }
6276  else
6277  {
6278  /* do when there is no more left */
6279  SRF_RETURN_DONE(funcctx);
6280  }
6281 }
#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 6287 of file arrayfuncs.c.

6288 {
6289  Node *rawreq = (Node *) PG_GETARG_POINTER(0);
6290  Node *ret = NULL;
6291 
6292  if (IsA(rawreq, SupportRequestRows))
6293  {
6294  /* Try to estimate the number of rows returned */
6295  SupportRequestRows *req = (SupportRequestRows *) rawreq;
6296 
6297  if (is_funcclause(req->node)) /* be paranoid */
6298  {
6299  List *args = ((FuncExpr *) req->node)->args;
6300  Node *arg1;
6301 
6302  /* We can use estimated argument values here */
6304 
6305  req->rows = estimate_array_length(arg1);
6306  ret = (Node *) req;
6307  }
6308  }
6309 
6310  PG_RETURN_POINTER(ret);
6311 }
Node * estimate_expression_value(PlannerInfo *root, Node *node)
Definition: clauses.c:2312
#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:179
#define linitial(l)
Definition: pg_list.h:178
int estimate_array_length(Node *arrayexpr)
Definition: selfuncs.c:2134
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 1747 of file arrayfuncs.c.

1748 {
1750  int reqdim = PG_GETARG_INT32(1);
1751  int *dimv,
1752  *lb;
1753  int result;
1754 
1755  /* Sanity check: does it look like an array at all? */
1756  if (AARR_NDIM(v) <= 0 || AARR_NDIM(v) > MAXDIM)
1757  PG_RETURN_NULL();
1758 
1759  /* Sanity check: was the requested dim valid */
1760  if (reqdim <= 0 || reqdim > AARR_NDIM(v))
1761  PG_RETURN_NULL();
1762 
1763  lb = AARR_LBOUND(v);
1764  dimv = AARR_DIMS(v);
1765 
1766  result = dimv[reqdim - 1] + lb[reqdim - 1] - 1;
1767 
1768  PG_RETURN_INT32(result);
1769 }

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

4764 {
4765  return fetch_att(value, byval, len);
4766 }
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 4774 of file arrayfuncs.c.

4779 {
4780  int inc;
4781 
4782  if (typlen > 0)
4783  {
4784  if (typbyval)
4785  store_att_byval(dest, src, typlen);
4786  else
4787  memmove(dest, DatumGetPointer(src), typlen);
4788  inc = att_align_nominal(typlen, typalign);
4789  }
4790  else
4791  {
4792  Assert(!typbyval);
4793  inc = att_addlength_datum(0, typlen, src);
4794  memmove(dest, DatumGetPointer(src), inc);
4795  inc = att_align_nominal(inc, typalign);
4796  }
4797 
4798  return inc;
4799 }
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 4507 of file arrayfuncs.c.

4508 {
4509  AnyArrayType *array1 = PG_GETARG_ANY_ARRAY_P(0);
4510  AnyArrayType *array2 = PG_GETARG_ANY_ARRAY_P(1);
4511  Oid collation = PG_GET_COLLATION();
4512  bool result;
4513 
4514  result = array_contain_compare(array1, array2, collation,