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 "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 bool array_isspace (char ch)
 
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 49 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 47 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 55 of file arrayfuncs.c.

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

Function Documentation

◆ accumArrayResult()

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

Definition at line 5319 of file arrayfuncs.c.

5323 {
5324  MemoryContext oldcontext;
5325 
5326  if (astate == NULL)
5327  {
5328  /* First time through --- initialize */
5329  astate = initArrayResult(element_type, rcontext, true);
5330  }
5331  else
5332  {
5333  Assert(astate->element_type == element_type);
5334  }
5335 
5336  oldcontext = MemoryContextSwitchTo(astate->mcontext);
5337 
5338  /* enlarge dvalues[]/dnulls[] if needed */
5339  if (astate->nelems >= astate->alen)
5340  {
5341  astate->alen *= 2;
5342  astate->dvalues = (Datum *)
5343  repalloc(astate->dvalues, astate->alen * sizeof(Datum));
5344  astate->dnulls = (bool *)
5345  repalloc(astate->dnulls, astate->alen * sizeof(bool));
5346  }
5347 
5348  /*
5349  * Ensure pass-by-ref stuff is copied into mcontext; and detoast it too if
5350  * it's varlena. (You might think that detoasting is not needed here
5351  * because construct_md_array can detoast the array elements later.
5352  * However, we must not let construct_md_array modify the ArrayBuildState
5353  * because that would mean array_agg_finalfn damages its input, which is
5354  * verboten. Also, this way frequently saves one copying step.)
5355  */
5356  if (!disnull && !astate->typbyval)
5357  {
5358  if (astate->typlen == -1)
5359  dvalue = PointerGetDatum(PG_DETOAST_DATUM_COPY(dvalue));
5360  else
5361  dvalue = datumCopy(dvalue, astate->typbyval, astate->typlen);
5362  }
5363 
5364  astate->dvalues[astate->nelems] = dvalue;
5365  astate->dnulls[astate->nelems] = disnull;
5366  astate->nelems++;
5367 
5368  MemoryContextSwitchTo(oldcontext);
5369 
5370  return astate;
5371 }
ArrayBuildState * initArrayResult(Oid element_type, MemoryContext rcontext, bool subcontext)
Definition: arrayfuncs.c:5262
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:132
#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:1456
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, Assert(), datumCopy(), ArrayBuildState::dnulls, ArrayBuildState::dvalues, ArrayBuildState::element_type, initArrayResult(), 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(), dblink_get_connections(), multirange_agg_transfn(), optionListToArray(), parse_ident(), pg_get_statisticsobjdef_expressions(), pg_stats_ext_mcvlist_items(), 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 5790 of file arrayfuncs.c.

5794 {
5795  if (astate == NULL)
5796  astate = initArrayResultAny(input_type, rcontext, true);
5797 
5798  if (astate->scalarstate)
5799  (void) accumArrayResult(astate->scalarstate,
5800  dvalue, disnull,
5801  input_type, rcontext);
5802  else
5803  (void) accumArrayResultArr(astate->arraystate,
5804  dvalue, disnull,
5805  input_type, rcontext);
5806 
5807  return astate;
5808 }
ArrayBuildState * accumArrayResult(ArrayBuildState *astate, Datum dvalue, bool disnull, Oid element_type, MemoryContext rcontext)
Definition: arrayfuncs.c:5319
ArrayBuildStateAny * initArrayResultAny(Oid input_type, MemoryContext rcontext, bool subcontext)
Definition: arrayfuncs.c:5745
ArrayBuildStateArr * accumArrayResultArr(ArrayBuildStateArr *astate, Datum dvalue, bool disnull, Oid array_type, MemoryContext rcontext)
Definition: arrayfuncs.c:5513
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 5513 of file arrayfuncs.c.

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

4938 {
4939  int destbitmask,
4940  destbitval,
4941  srcbitmask,
4942  srcbitval;
4943 
4944  Assert(destbitmap);
4945  if (nitems <= 0)
4946  return; /* don't risk fetch off end of memory */
4947  destbitmap += destoffset / 8;
4948  destbitmask = 1 << (destoffset % 8);
4949  destbitval = *destbitmap;
4950  if (srcbitmap)
4951  {
4952  srcbitmap += srcoffset / 8;
4953  srcbitmask = 1 << (srcoffset % 8);
4954  srcbitval = *srcbitmap;
4955  while (nitems-- > 0)
4956  {
4957  if (srcbitval & srcbitmask)
4958  destbitval |= destbitmask;
4959  else
4960  destbitval &= ~destbitmask;
4961  destbitmask <<= 1;
4962  if (destbitmask == 0x100)
4963  {
4964  *destbitmap++ = destbitval;
4965  destbitmask = 1;
4966  if (nitems > 0)
4967  destbitval = *destbitmap;
4968  }
4969  srcbitmask <<= 1;
4970  if (srcbitmask == 0x100)
4971  {
4972  srcbitmap++;
4973  srcbitmask = 1;
4974  if (nitems > 0)
4975  srcbitval = *srcbitmap;
4976  }
4977  }
4978  if (destbitmask != 1)
4979  *destbitmap = destbitval;
4980  }
4981  else
4982  {
4983  while (nitems-- > 0)
4984  {
4985  destbitval |= destbitmask;
4986  destbitmask <<= 1;
4987  if (destbitmask == 0x100)
4988  {
4989  *destbitmap++ = destbitval;
4990  destbitmask = 1;
4991  if (nitems > 0)
4992  destbitval = *destbitmap;
4993  }
4994  }
4995  if (destbitmask != 1)
4996  *destbitmap = destbitval;
4997  }
4998 }

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

1826 {
1828 
1830 }
#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 3954 of file arrayfuncs.c.

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

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

3737 {
3738  int nelems;
3739  bits8 *bitmap;
3740  int bitmask;
3741 
3742  /* Easy answer if there's no null bitmap */
3743  if (!ARR_HASNULL(array))
3744  return false;
3745 
3746  nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
3747 
3748  bitmap = ARR_NULLBITMAP(array);
3749 
3750  /* check whole bytes of the bitmap byte-at-a-time */
3751  while (nelems >= 8)
3752  {
3753  if (*bitmap != 0xFF)
3754  return true;
3755  bitmap++;
3756  nelems -= 8;
3757  }
3758 
3759  /* check last partial byte */
3760  bitmask = 1;
3761  while (nelems > 0)
3762  {
3763  if ((*bitmap & bitmask) == 0)
3764  return true;
3765  bitmask <<= 1;
3766  nelems--;
3767  }
3768 
3769  return false;
3770 }

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

4908 {
4909  int numbytes;
4910 
4911  numbytes = array_nelems_size(srcptr, offset, nullbitmap, nitems,
4912  typlen, typbyval, typalign);
4913  memcpy(destptr, srcptr, numbytes);
4914  return numbytes;
4915 }
static int array_nelems_size(char *ptr, int offset, bits8 *nullbitmap, int nitems, int typlen, bool typbyval, char typalign)
Definition: arrayfuncs.c:4883

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

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

1704 {
1706  char *p;
1707  int i;
1708  int *dimv,
1709  *lb;
1710 
1711  /*
1712  * 33 since we assume 15 digits per number + ':' +'[]'
1713  *
1714  * +1 for trailing null
1715  */
1716  char buf[MAXDIM * 33 + 1];
1717 
1718  /* Sanity check: does it look like an array at all? */
1719  if (AARR_NDIM(v) <= 0 || AARR_NDIM(v) > MAXDIM)
1720  PG_RETURN_NULL();
1721 
1722  dimv = AARR_DIMS(v);
1723  lb = AARR_LBOUND(v);
1724 
1725  p = buf;
1726  for (i = 0; i < AARR_NDIM(v); i++)
1727  {
1728  sprintf(p, "[%d:%d]", lb[i], dimv[i] + lb[i] - 1);
1729  p += strlen(p);
1730  }
1731 
1733 }
#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 3783 of file arrayfuncs.c.

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

5077 {
5078  char *destdataptr = ARR_DATA_PTR(newarray);
5079  bits8 *destnullsptr = ARR_NULLBITMAP(newarray);
5080  char *srcdataptr;
5081  int src_offset,
5082  dest_offset,
5083  prod[MAXDIM],
5084  span[MAXDIM],
5085  dist[MAXDIM],
5086  indx[MAXDIM];
5087  int i,
5088  j,
5089  inc;
5090 
5091  src_offset = ArrayGetOffset(ndim, dim, lb, st);
5092  srcdataptr = array_seek(arraydataptr, 0, arraynullsptr, src_offset,
5093  typlen, typbyval, typalign);
5094  mda_get_prod(ndim, dim, prod);
5095  mda_get_range(ndim, span, st, endp);
5096  mda_get_offset_values(ndim, dist, prod, span);
5097  for (i = 0; i < ndim; i++)
5098  indx[i] = 0;
5099  dest_offset = 0;
5100  j = ndim - 1;
5101  do
5102  {
5103  if (dist[j])
5104  {
5105  /* skip unwanted elements */
5106  srcdataptr = array_seek(srcdataptr, src_offset, arraynullsptr,
5107  dist[j],
5108  typlen, typbyval, typalign);
5109  src_offset += dist[j];
5110  }
5111  inc = array_copy(destdataptr, 1,
5112  srcdataptr, src_offset, arraynullsptr,
5113  typlen, typbyval, typalign);
5114  if (destnullsptr)
5115  array_bitmap_copy(destnullsptr, dest_offset,
5116  arraynullsptr, src_offset,
5117  1);
5118  destdataptr += inc;
5119  srcdataptr += inc;
5120  src_offset++;
5121  dest_offset++;
5122  } while ((j = mda_next_tuple(ndim, indx, span)) != -1);
5123 }
static int array_copy(char *destptr, int nitems, char *srcptr, int offset, bits8 *nullbitmap, int typlen, bool typbyval, char typalign)
Definition: arrayfuncs.c:4905
static char * array_seek(char *ptr, int offset, bits8 *nullbitmap, int nitems, int typlen, bool typbyval, char typalign)
Definition: arrayfuncs.c:4835
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 5994 of file arrayfuncs.c.

5995 {
5996  ArrayType *dims;
5997  ArrayType *result;
5998  Oid elmtype;
5999  Datum value;
6000  bool isnull;
6001 
6002  if (PG_ARGISNULL(1))
6003  ereport(ERROR,
6004  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
6005  errmsg("dimension array or low bound array cannot be null")));
6006 
6007  dims = PG_GETARG_ARRAYTYPE_P(1);
6008 
6009  if (!PG_ARGISNULL(0))
6010  {
6011  value = PG_GETARG_DATUM(0);
6012  isnull = false;
6013  }
6014  else
6015  {
6016  value = 0;
6017  isnull = true;
6018  }
6019 
6020  elmtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
6021  if (!OidIsValid(elmtype))
6022  elog(ERROR, "could not determine data type of input");
6023 
6024  result = array_fill_internal(dims, NULL, value, isnull, elmtype, fcinfo);
6025  PG_RETURN_ARRAYTYPE_P(result);
6026 }
#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:6046
Oid get_fn_expr_argtype(FmgrInfo *flinfo, int argnum)
Definition: fmgr.c:1882
#define PG_ARGISNULL(n)
Definition: fmgr.h:209
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:268
static struct @145 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 6046 of file arrayfuncs.c.

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

5954 {
5955  ArrayType *dims;
5956  ArrayType *lbs;
5957  ArrayType *result;
5958  Oid elmtype;
5959  Datum value;
5960  bool isnull;
5961 
5962  if (PG_ARGISNULL(1) || PG_ARGISNULL(2))
5963  ereport(ERROR,
5964  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
5965  errmsg("dimension array or low bound array cannot be null")));
5966 
5967  dims = PG_GETARG_ARRAYTYPE_P(1);
5968  lbs = PG_GETARG_ARRAYTYPE_P(2);
5969 
5970  if (!PG_ARGISNULL(0))
5971  {
5972  value = PG_GETARG_DATUM(0);
5973  isnull = false;
5974  }
5975  else
5976  {
5977  value = 0;
5978  isnull = true;
5979  }
5980 
5981  elmtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
5982  if (!OidIsValid(elmtype))
5983  elog(ERROR, "could not determine data type of input");
5984 
5985  result = array_fill_internal(dims, lbs, value, isnull, elmtype, fcinfo);
5986  PG_RETURN_ARRAYTYPE_P(result);
5987 }

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

4729 {
4730  if (iterator->slice_ndim > 0)
4731  {
4732  pfree(iterator->slice_values);
4733  pfree(iterator->slice_nulls);
4734  }
4735  pfree(iterator);
4736 }

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

3937 {
3938  PG_RETURN_BOOL(array_cmp(fcinfo) >= 0);
3939 }
static int array_cmp(FunctionCallInfo fcinfo)
Definition: arrayfuncs.c:3954

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

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

1961 {
1962  ExpandedArrayHeader *eah;
1963  int i,
1964  ndim,
1965  *dim,
1966  *lb,
1967  offset;
1968  Datum *dvalues;
1969  bool *dnulls;
1970 
1971  eah = (ExpandedArrayHeader *) DatumGetEOHP(arraydatum);
1972  Assert(eah->ea_magic == EA_MAGIC);
1973 
1974  /* sanity-check caller's info against object */
1975  Assert(arraytyplen == -1);
1976  Assert(elmlen == eah->typlen);
1977  Assert(elmbyval == eah->typbyval);
1978  Assert(elmalign == eah->typalign);
1979 
1980  ndim = eah->ndims;
1981  dim = eah->dims;
1982  lb = eah->lbound;
1983 
1984  /*
1985  * Return NULL for invalid subscript
1986  */
1987  if (ndim != nSubscripts || ndim <= 0 || ndim > MAXDIM)
1988  {
1989  *isNull = true;
1990  return (Datum) 0;
1991  }
1992  for (i = 0; i < ndim; i++)
1993  {
1994  if (indx[i] < lb[i] || indx[i] >= (dim[i] + lb[i]))
1995  {
1996  *isNull = true;
1997  return (Datum) 0;
1998  }
1999  }
2000 
2001  /*
2002  * Calculate the element number
2003  */
2004  offset = ArrayGetOffset(nSubscripts, dim, lb, indx);
2005 
2006  /*
2007  * Deconstruct array if we didn't already. Note that we apply this even
2008  * if the input is nominally read-only: it should be safe enough.
2009  */
2011 
2012  dvalues = eah->dvalues;
2013  dnulls = eah->dnulls;
2014 
2015  /*
2016  * Check for NULL array element
2017  */
2018  if (dnulls && dnulls[offset])
2019  {
2020  *isNull = true;
2021  return (Datum) 0;
2022  }
2023 
2024  /*
2025  * OK, get the element. It's OK to return a pass-by-ref value as a
2026  * pointer into the expanded array, for the same reason that regular
2027  * array_get_element can return a pointer into flat arrays: the value is
2028  * assumed not to change for as long as the Datum reference can exist.
2029  */
2030  *isNull = false;
2031  return dvalues[offset];
2032 }
#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 4750 of file arrayfuncs.c.

4751 {
4752  if (nullbitmap == NULL)
4753  return false; /* assume not null */
4754  if (nullbitmap[offset / 8] & (1 << (offset % 8)))
4755  return false; /* not null */
4756  return true;
4757 }

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

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

3925 {
3926  PG_RETURN_BOOL(array_cmp(fcinfo) > 0);
3927 }

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 (array_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 (array_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 array_isspace(char ch)
Definition: arrayfuncs.c:446
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:738
void CopyArrayEls(ArrayType *array, Datum *values, bool *nulls, int nitems, int typlen, bool typbyval, char typalign, bool freedata)
Definition: arrayfuncs.c:985
static int ArrayCount(const char *str, int *dim, char typdelim, Node *escontext)
Definition: arrayfuncs.c:469
#define ASSGN
Definition: arrayfuncs.c:47
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:2283
@ IOFunc_input
Definition: lsyscache.h:35
char * pstrdup(const char *in)
Definition: mcxt.c:1624
#define printf(...)
Definition: port.h:244
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, array_isspace(), 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(), 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 5139 of file arrayfuncs.c.

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

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

static bool array_isspace ( char  ch)
static

Definition at line 446 of file arrayfuncs.c.

447 {
448  if (ch == ' ' ||
449  ch == '\t' ||
450  ch == '\n' ||
451  ch == '\r' ||
452  ch == '\v' ||
453  ch == '\f')
454  return true;
455  return false;
456 }

Referenced by array_in(), array_out(), ArrayCount(), and ReadArrayStr().

◆ array_iterate()

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

Definition at line 4645 of file arrayfuncs.c.

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

5849 {
5850  if (array_cmp(fcinfo) > 0)
5852  else
5854 }
#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 3930 of file arrayfuncs.c.

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

References array_cmp(), and PG_RETURN_BOOL.

◆ array_length()

Datum array_length ( PG_FUNCTION_ARGS  )

Definition at line 1798 of file arrayfuncs.c.

1799 {
1801  int reqdim = PG_GETARG_INT32(1);
1802  int *dimv;
1803  int result;
1804 
1805  /* Sanity check: does it look like an array at all? */
1806  if (AARR_NDIM(v) <= 0 || AARR_NDIM(v) > MAXDIM)
1807  PG_RETURN_NULL();
1808 
1809  /* Sanity check: was the requested dim valid */
1810  if (reqdim <= 0 || reqdim > AARR_NDIM(v))
1811  PG_RETURN_NULL();
1812 
1813  dimv = AARR_DIMS(v);
1814 
1815  result = dimv[reqdim - 1];
1816 
1817  PG_RETURN_INT32(result);
1818 }

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

1742 {
1744  int reqdim = PG_GETARG_INT32(1);
1745  int *lb;
1746  int result;
1747 
1748  /* Sanity check: does it look like an array at all? */
1749  if (AARR_NDIM(v) <= 0 || AARR_NDIM(v) > MAXDIM)
1750  PG_RETURN_NULL();
1751 
1752  /* Sanity check: was the requested dim valid */
1753  if (reqdim <= 0 || reqdim > AARR_NDIM(v))
1754  PG_RETURN_NULL();
1755 
1756  lb = AARR_LBOUND(v);
1757  result = lb[reqdim - 1];
1758 
1759  PG_RETURN_INT32(result);
1760 }

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

3919 {
3920  PG_RETURN_BOOL(array_cmp(fcinfo) < 0);
3921 }

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

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

1688 {
1690 
1691  /* Sanity check: does it look like an array at all? */
1692  if (AARR_NDIM(v) <= 0 || AARR_NDIM(v) > MAXDIM)
1693  PG_RETURN_NULL();
1694 
1696 }

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

3913 {
3915 }
Datum array_eq(PG_FUNCTION_ARGS)
Definition: arrayfuncs.c:3783

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

4885 {
4886  return array_seek(ptr, offset, nullbitmap, nitems,
4887  typlen, typbyval, typalign) - ptr;
4888 }

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

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

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

3129 {
3130  return array_get_element(PointerGetDatum(array), nSubscripts, indx,
3131  arraytyplen, elmlen, elmbyval, elmalign,
3132  isNull);
3133 }
Datum array_get_element(Datum arraydatum, int nSubscripts, int *indx, int arraytyplen, int elmlen, bool elmbyval, char elmalign, bool *isNull)
Definition: arrayfuncs.c:1855

References array_get_element(), and PointerGetDatum().

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

◆ array_remove()

Datum array_remove ( PG_FUNCTION_ARGS  )

Definition at line 6597 of file arrayfuncs.c.

6598 {
6599  ArrayType *array;
6600  Datum search = PG_GETARG_DATUM(1);
6601  bool search_isnull = PG_ARGISNULL(1);
6602 
6603  if (PG_ARGISNULL(0))
6604  PG_RETURN_NULL();
6605  array = PG_GETARG_ARRAYTYPE_P(0);
6606 
6607  array = array_replace_internal(array,
6608  search, search_isnull,
6609  (Datum) 0, true,
6610  true, PG_GET_COLLATION(),
6611  fcinfo);
6612  PG_RETURN_ARRAYTYPE_P(array);
6613 }
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:6339

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

6620 {
6621  ArrayType *array;
6622  Datum search = PG_GETARG_DATUM(1);
6623  bool search_isnull = PG_ARGISNULL(1);
6624  Datum replace = PG_GETARG_DATUM(2);
6625  bool replace_isnull = PG_ARGISNULL(2);
6626 
6627  if (PG_ARGISNULL(0))
6628  PG_RETURN_NULL();
6629  array = PG_GETARG_ARRAYTYPE_P(0);
6630 
6631  array = array_replace_internal(array,
6632  search, search_isnull,
6633  replace, replace_isnull,
6634  false, PG_GET_COLLATION(),
6635  fcinfo);
6636  PG_RETURN_ARRAYTYPE_P(array);
6637 }

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

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

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

4837 {
4838  int bitmask;
4839  int i;
4840 
4841  /* easy if fixed-size elements and no NULLs */
4842  if (typlen > 0 && !nullbitmap)
4843  return ptr + nitems * ((Size) att_align_nominal(typlen, typalign));
4844 
4845  /* seems worth having separate loops for NULL and no-NULLs cases */
4846  if (nullbitmap)
4847  {
4848  nullbitmap += offset / 8;
4849  bitmask = 1 << (offset % 8);
4850 
4851  for (i = 0; i < nitems; i++)
4852  {
4853  if (*nullbitmap & bitmask)
4854  {
4855  ptr = att_addlength_pointer(ptr, typlen, ptr);
4856  ptr = (char *) att_align_nominal(ptr, typalign);
4857  }
4858  bitmask <<= 1;
4859  if (bitmask == 0x100)
4860  {
4861  nullbitmap++;
4862  bitmask = 1;
4863  }
4864  }
4865  }
4866  else
4867  {
4868  for (i = 0; i < nitems; i++)
4869  {
4870  ptr = att_addlength_pointer(ptr, typlen, ptr);
4871  ptr = (char *) att_align_nominal(ptr, typalign);
4872  }
4873  }
4874  return ptr;
4875 }
size_t Size
Definition: c.h:589

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

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

3146 {
3148  nSubscripts, indx,
3149  dataValue, isNull,
3150  arraytyplen,
3151  elmlen, elmbyval, elmalign));
3152 }
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:2236

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

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

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

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

4768 {
4769  int bitmask;
4770 
4771  nullbitmap += offset / 8;
4772  bitmask = 1 << (offset % 8);
4773  if (isNull)
4774  *nullbitmap &= ~bitmask;
4775  else
4776  *nullbitmap |= bitmask;
4777 }

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

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

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

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

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

5858 {
5859  if (array_cmp(fcinfo) < 0)
5861  else
5863 }

References array_cmp(), PG_GETARG_DATUM, and PG_RETURN_DATUM.

◆ array_unnest()

Datum array_unnest ( PG_FUNCTION_ARGS  )

Definition at line 6215 of file arrayfuncs.c.

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

6304 {
6305  Node *rawreq = (Node *) PG_GETARG_POINTER(0);
6306  Node *ret = NULL;
6307 
6308  if (IsA(rawreq, SupportRequestRows))
6309  {
6310  /* Try to estimate the number of rows returned */
6311  SupportRequestRows *req = (SupportRequestRows *) rawreq;
6312 
6313  if (is_funcclause(req->node)) /* be paranoid */
6314  {
6315  List *args = ((FuncExpr *) req->node)->args;
6316  Node *arg1;
6317 
6318  /* We can use estimated argument values here */
6320 
6321  req->rows = estimate_array_length(arg1);
6322  ret = (Node *) req;
6323  }
6324  }
6325 
6326  PG_RETURN_POINTER(ret);
6327 }
Node * estimate_expression_value(PlannerInfo *root, Node *node)
Definition: clauses.c:2304
#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 1768 of file arrayfuncs.c.

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

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

4786 {
4787  return fetch_att(value, byval, len);
4788 }
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 4796 of file arrayfuncs.c.

4801 {
4802  int inc;
4803 
4804  if (typlen > 0)
4805  {
4806  if (typbyval)
4807  store_att_byval(dest, src, typlen);
4808  else
4809  memmove(dest, DatumGetPointer(src), typlen);
4810  inc = att_align_nominal(typlen, typalign);
4811  }
4812  else
4813  {
4814  Assert(!typbyval);
4815  inc = att_addlength_datum(0, typlen, src);
4816  memmove(dest, DatumGetPointer(src), inc);
4817  inc = att_align_nominal(inc, typalign);
4818  }
4819 
4820  return inc;
4821 }
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 4529 of file arrayfuncs.c.

4530 {
4531  AnyArrayType *array1 = PG_GETARG_ANY_ARRAY_P(0);
4532  AnyArrayType *array2 = PG_GETARG_ANY_ARRAY_P(1)