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)
 
static void 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)
 
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)
 
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 5277 of file arrayfuncs.c.

5281 {
5282  MemoryContext oldcontext;
5283 
5284  if (astate == NULL)
5285  {
5286  /* First time through --- initialize */
5287  astate = initArrayResult(element_type, rcontext, true);
5288  }
5289  else
5290  {
5291  Assert(astate->element_type == element_type);
5292  }
5293 
5294  oldcontext = MemoryContextSwitchTo(astate->mcontext);
5295 
5296  /* enlarge dvalues[]/dnulls[] if needed */
5297  if (astate->nelems >= astate->alen)
5298  {
5299  astate->alen *= 2;
5300  astate->dvalues = (Datum *)
5301  repalloc(astate->dvalues, astate->alen * sizeof(Datum));
5302  astate->dnulls = (bool *)
5303  repalloc(astate->dnulls, astate->alen * sizeof(bool));
5304  }
5305 
5306  /*
5307  * Ensure pass-by-ref stuff is copied into mcontext; and detoast it too if
5308  * it's varlena. (You might think that detoasting is not needed here
5309  * because construct_md_array can detoast the array elements later.
5310  * However, we must not let construct_md_array modify the ArrayBuildState
5311  * because that would mean array_agg_finalfn damages its input, which is
5312  * verboten. Also, this way frequently saves one copying step.)
5313  */
5314  if (!disnull && !astate->typbyval)
5315  {
5316  if (astate->typlen == -1)
5317  dvalue = PointerGetDatum(PG_DETOAST_DATUM_COPY(dvalue));
5318  else
5319  dvalue = datumCopy(dvalue, astate->typbyval, astate->typlen);
5320  }
5321 
5322  astate->dvalues[astate->nelems] = dvalue;
5323  astate->dnulls[astate->nelems] = disnull;
5324  astate->nelems++;
5325 
5326  MemoryContextSwitchTo(oldcontext);
5327 
5328  return astate;
5329 }
ArrayBuildState * initArrayResult(Oid element_type, MemoryContext rcontext, bool subcontext)
Definition: arrayfuncs.c:5238
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:1321
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:135
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:670
uintptr_t Datum
Definition: postgres.h:412
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 5748 of file arrayfuncs.c.

5752 {
5753  if (astate == NULL)
5754  astate = initArrayResultAny(input_type, rcontext, true);
5755 
5756  if (astate->scalarstate)
5757  (void) accumArrayResult(astate->scalarstate,
5758  dvalue, disnull,
5759  input_type, rcontext);
5760  else
5761  (void) accumArrayResultArr(astate->arraystate,
5762  dvalue, disnull,
5763  input_type, rcontext);
5764 
5765  return astate;
5766 }
ArrayBuildState * accumArrayResult(ArrayBuildState *astate, Datum dvalue, bool disnull, Oid element_type, MemoryContext rcontext)
Definition: arrayfuncs.c:5277
ArrayBuildStateAny * initArrayResultAny(Oid input_type, MemoryContext rcontext, bool subcontext)
Definition: arrayfuncs.c:5703
ArrayBuildStateArr * accumArrayResultArr(ArrayBuildStateArr *astate, Datum dvalue, bool disnull, Oid array_type, MemoryContext rcontext)
Definition: arrayfuncs.c:5471
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 5471 of file arrayfuncs.c.

5475 {
5476  ArrayType *arg;
5477  MemoryContext oldcontext;
5478  int *dims,
5479  *lbs,
5480  ndims,
5481  nitems,
5482  ndatabytes;
5483  char *data;
5484  int i;
5485 
5486  /*
5487  * We disallow accumulating null subarrays. Another plausible definition
5488  * is to ignore them, but callers that want that can just skip calling
5489  * this function.
5490  */
5491  if (disnull)
5492  ereport(ERROR,
5493  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
5494  errmsg("cannot accumulate null arrays")));
5495 
5496  /* Detoast input array in caller's context */
5497  arg = DatumGetArrayTypeP(dvalue);
5498 
5499  if (astate == NULL)
5500  astate = initArrayResultArr(array_type, InvalidOid, rcontext, true);
5501  else
5502  Assert(astate->array_type == array_type);
5503 
5504  oldcontext = MemoryContextSwitchTo(astate->mcontext);
5505 
5506  /* Collect this input's dimensions */
5507  ndims = ARR_NDIM(arg);
5508  dims = ARR_DIMS(arg);
5509  lbs = ARR_LBOUND(arg);
5510  data = ARR_DATA_PTR(arg);
5511  nitems = ArrayGetNItems(ndims, dims);
5512  ndatabytes = ARR_SIZE(arg) - ARR_DATA_OFFSET(arg);
5513 
5514  if (astate->ndims == 0)
5515  {
5516  /* First input; check/save the dimensionality info */
5517 
5518  /* Should we allow empty inputs and just produce an empty output? */
5519  if (ndims == 0)
5520  ereport(ERROR,
5521  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
5522  errmsg("cannot accumulate empty arrays")));
5523  if (ndims + 1 > MAXDIM)
5524  ereport(ERROR,
5525  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
5526  errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
5527  ndims + 1, MAXDIM)));
5528 
5529  /*
5530  * The output array will have n+1 dimensions, with the ones after the
5531  * first matching the input's dimensions.
5532  */
5533  astate->ndims = ndims + 1;
5534  astate->dims[0] = 0;
5535  memcpy(&astate->dims[1], dims, ndims * sizeof(int));
5536  astate->lbs[0] = 1;
5537  memcpy(&astate->lbs[1], lbs, ndims * sizeof(int));
5538 
5539  /* Allocate at least enough data space for this item */
5540  astate->abytes = pg_nextpower2_32(Max(1024, ndatabytes + 1));
5541  astate->data = (char *) palloc(astate->abytes);
5542  }
5543  else
5544  {
5545  /* Second or later input: must match first input's dimensionality */
5546  if (astate->ndims != ndims + 1)
5547  ereport(ERROR,
5548  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
5549  errmsg("cannot accumulate arrays of different dimensionality")));
5550  for (i = 0; i < ndims; i++)
5551  {
5552  if (astate->dims[i + 1] != dims[i] || astate->lbs[i + 1] != lbs[i])
5553  ereport(ERROR,
5554  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
5555  errmsg("cannot accumulate arrays of different dimensionality")));
5556  }
5557 
5558  /* Enlarge data space if needed */
5559  if (astate->nbytes + ndatabytes > astate->abytes)
5560  {
5561  astate->abytes = Max(astate->abytes * 2,
5562  astate->nbytes + ndatabytes);
5563  astate->data = (char *) repalloc(astate->data, astate->abytes);
5564  }
5565  }
5566 
5567  /*
5568  * Copy the data portion of the sub-array. Note we assume that the
5569  * advertised data length of the sub-array is properly aligned. We do not
5570  * have to worry about detoasting elements since whatever's in the
5571  * sub-array should be OK already.
5572  */
5573  memcpy(astate->data + astate->nbytes, data, ndatabytes);
5574  astate->nbytes += ndatabytes;
5575 
5576  /* Deal with null bitmap if needed */
5577  if (astate->nullbitmap || ARR_HASNULL(arg))
5578  {
5579  int newnitems = astate->nitems + nitems;
5580 
5581  if (astate->nullbitmap == NULL)
5582  {
5583  /*
5584  * First input with nulls; we must retrospectively handle any
5585  * previous inputs by marking all their items non-null.
5586  */
5587  astate->aitems = pg_nextpower2_32(Max(256, newnitems + 1));
5588  astate->nullbitmap = (bits8 *) palloc((astate->aitems + 7) / 8);
5589  array_bitmap_copy(astate->nullbitmap, 0,
5590  NULL, 0,
5591  astate->nitems);
5592  }
5593  else if (newnitems > astate->aitems)
5594  {
5595  astate->aitems = Max(astate->aitems * 2, newnitems);
5596  astate->nullbitmap = (bits8 *)
5597  repalloc(astate->nullbitmap, (astate->aitems + 7) / 8);
5598  }
5599  array_bitmap_copy(astate->nullbitmap, astate->nitems,
5600  ARR_NULLBITMAP(arg), 0,
5601  nitems);
5602  }
5603 
5604  astate->nitems += nitems;
5605  astate->dims[0] += 1;
5606 
5607  MemoryContextSwitchTo(oldcontext);
5608 
5609  /* Release detoasted copy if any */
5610  if ((Pointer) arg != DatumGetPointer(dvalue))
5611  pfree(arg);
5612 
5613  return astate;
5614 }
#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:5425
void array_bitmap_copy(bits8 *destbitmap, int destoffset, const bits8 *srcbitmap, int srcoffset, int nitems)
Definition: arrayfuncs.c:4911
int ArrayGetNItems(int ndim, const int *dims)
Definition: arrayutils.c:76
#define Max(x, y)
Definition: c.h:931
char * Pointer
Definition: c.h:419
uint8 bits8
Definition: c.h:449
int errcode(int sqlerrcode)
Definition: elog.c:695
int errmsg(const char *fmt,...)
Definition: elog.c:906
#define ERROR
Definition: elog.h:35
#define ereport(elevel,...)
Definition: elog.h:145
int i
Definition: isn.c:73
void pfree(void *pointer)
Definition: mcxt.c:1306
void * palloc(Size size)
Definition: mcxt.c:1199
void * arg
static uint32 pg_nextpower2_32(uint32 num)
Definition: pg_bitutils.h:140
const void * data
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:660
#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, 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 4911 of file arrayfuncs.c.

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

References Assert().

Referenced by accumArrayResultArr(), 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 1800 of file arrayfuncs.c.

1801 {
1803 
1805 }
#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 3930 of file arrayfuncs.c.

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

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

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

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

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

References array_nelems_size(), 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 4542 of file arrayfuncs.c.

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

1679 {
1681  char *p;
1682  int i;
1683  int *dimv,
1684  *lb;
1685 
1686  /*
1687  * 33 since we assume 15 digits per number + ':' +'[]'
1688  *
1689  * +1 for trailing null
1690  */
1691  char buf[MAXDIM * 33 + 1];
1692 
1693  /* Sanity check: does it look like an array at all? */
1694  if (AARR_NDIM(v) <= 0 || AARR_NDIM(v) > MAXDIM)
1695  PG_RETURN_NULL();
1696 
1697  dimv = AARR_DIMS(v);
1698  lb = AARR_LBOUND(v);
1699 
1700  p = buf;
1701  for (i = 0; i < AARR_NDIM(v); i++)
1702  {
1703  sprintf(p, "[%d:%d]", lb[i], dimv[i] + lb[i] - 1);
1704  p += strlen(p);
1705  }
1706 
1708 }
#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:189

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

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

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

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

5953 {
5954  ArrayType *dims;
5955  ArrayType *result;
5956  Oid elmtype;
5957  Datum value;
5958  bool isnull;
5959 
5960  if (PG_ARGISNULL(1))
5961  ereport(ERROR,
5962  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
5963  errmsg("dimension array or low bound array cannot be null")));
5964 
5965  dims = PG_GETARG_ARRAYTYPE_P(1);
5966 
5967  if (!PG_ARGISNULL(0))
5968  {
5969  value = PG_GETARG_DATUM(0);
5970  isnull = false;
5971  }
5972  else
5973  {
5974  value = 0;
5975  isnull = true;
5976  }
5977 
5978  elmtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
5979  if (!OidIsValid(elmtype))
5980  elog(ERROR, "could not determine data type of input");
5981 
5982  result = array_fill_internal(dims, NULL, value, isnull, elmtype, fcinfo);
5983  PG_RETURN_ARRAYTYPE_P(result);
5984 }
#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:6004
Oid get_fn_expr_argtype(FmgrInfo *flinfo, int argnum)
Definition: fmgr.c:1786
#define PG_ARGISNULL(n)
Definition: fmgr.h:209
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:268
static struct @143 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 6004 of file arrayfuncs.c.

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

5912 {
5913  ArrayType *dims;
5914  ArrayType *lbs;
5915  ArrayType *result;
5916  Oid elmtype;
5917  Datum value;
5918  bool isnull;
5919 
5920  if (PG_ARGISNULL(1) || PG_ARGISNULL(2))
5921  ereport(ERROR,
5922  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
5923  errmsg("dimension array or low bound array cannot be null")));
5924 
5925  dims = PG_GETARG_ARRAYTYPE_P(1);
5926  lbs = PG_GETARG_ARRAYTYPE_P(2);
5927 
5928  if (!PG_ARGISNULL(0))
5929  {
5930  value = PG_GETARG_DATUM(0);
5931  isnull = false;
5932  }
5933  else
5934  {
5935  value = 0;
5936  isnull = true;
5937  }
5938 
5939  elmtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
5940  if (!OidIsValid(elmtype))
5941  elog(ERROR, "could not determine data type of input");
5942 
5943  result = array_fill_internal(dims, lbs, value, isnull, elmtype, fcinfo);
5944  PG_RETURN_ARRAYTYPE_P(result);
5945 }

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

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

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

3913 {
3914  PG_RETURN_BOOL(array_cmp(fcinfo) >= 0);
3915 }
static int array_cmp(FunctionCallInfo fcinfo)
Definition: arrayfuncs.c:3930

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

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

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

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

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

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

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

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

3901 {
3902  PG_RETURN_BOOL(array_cmp(fcinfo) > 0);
3903 }

References array_cmp(), and PG_RETURN_BOOL.

◆ array_in()

Datum array_in ( PG_FUNCTION_ARGS  )

Definition at line 174 of file arrayfuncs.c.

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

References ARR_DIMS, ARR_LBOUND, ARR_OVERHEAD_NONULLS, ARR_OVERHEAD_WITHNULLS, array_isspace(), ArrayCheckBounds(), ArrayCount(), ArrayGetNItems(), ASSGN, construct_empty_array(), CopyArrayEls(), ArrayType::dataoffset, ArrayMetaState::element_type, ArrayType::elemtype, ereport, errcode(), errdetail(), errmsg(), ERROR, fmgr_info_cxt(), FmgrInfo::fn_mcxt, get_type_io_data(), i, if(), IOFunc_input, MAXDIM, MemoryContextAlloc(), ArrayType::ndim, palloc(), palloc0(), pfree(), PG_GETARG_CSTRING, PG_GETARG_INT32, PG_GETARG_OID, PG_RETURN_ARRAYTYPE_P, 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 5115 of file arrayfuncs.c.

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

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

437 {
438  if (ch == ' ' ||
439  ch == '\t' ||
440  ch == '\n' ||
441  ch == '\r' ||
442  ch == '\v' ||
443  ch == '\f')
444  return true;
445  return false;
446 }

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

◆ array_iterate()

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

Definition at line 4621 of file arrayfuncs.c.

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

5807 {
5808  if (array_cmp(fcinfo) > 0)
5810  else
5812 }
#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 3906 of file arrayfuncs.c.

3907 {
3908  PG_RETURN_BOOL(array_cmp(fcinfo) <= 0);
3909 }

References array_cmp(), and PG_RETURN_BOOL.

◆ array_length()

Datum array_length ( PG_FUNCTION_ARGS  )

Definition at line 1773 of file arrayfuncs.c.

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

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

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

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

3895 {
3896  PG_RETURN_BOOL(array_cmp(fcinfo) < 0);
3897 }

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

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

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

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

3889 {
3891 }
Datum array_eq(PG_FUNCTION_ARGS)
Definition: arrayfuncs.c:3759

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

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

References array_seek(), and typalign.

Referenced by array_copy(), and array_set_slice().

◆ array_out()

Datum array_out ( PG_FUNCTION_ARGS  )

Definition at line 1015 of file arrayfuncs.c.

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

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

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

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

6556 {
6557  ArrayType *array;
6558  Datum search = PG_GETARG_DATUM(1);
6559  bool search_isnull = PG_ARGISNULL(1);
6560 
6561  if (PG_ARGISNULL(0))
6562  PG_RETURN_NULL();
6563  array = PG_GETARG_ARRAYTYPE_P(0);
6564 
6565  array = array_replace_internal(array,
6566  search, search_isnull,
6567  (Datum) 0, true,
6568  true, PG_GET_COLLATION(),
6569  fcinfo);
6570  PG_RETURN_ARRAYTYPE_P(array);
6571 }
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:6297

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

6578 {
6579  ArrayType *array;
6580  Datum search = PG_GETARG_DATUM(1);
6581  bool search_isnull = PG_ARGISNULL(1);
6582  Datum replace = PG_GETARG_DATUM(2);
6583  bool replace_isnull = PG_ARGISNULL(2);
6584 
6585  if (PG_ARGISNULL(0))
6586  PG_RETURN_NULL();
6587  array = PG_GETARG_ARRAYTYPE_P(0);
6588 
6589  array = array_replace_internal(array,
6590  search, search_isnull,
6591  replace, replace_isnull,
6592  false, PG_GET_COLLATION(),
6593  fcinfo);
6594  PG_RETURN_ARRAYTYPE_P(array);
6595 }

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

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

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

References att_addlength_pointer, att_align_nominal, i, 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 1558 of file arrayfuncs.c.

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

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

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

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

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

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, MemSet, 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 2496 of file arrayfuncs.c.

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

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

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

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

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(), MemSet, Min, ArrayType::ndim, 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 4982 of file arrayfuncs.c.

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

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

5816 {
5817  if (array_cmp(fcinfo) < 0)
5819  else
5821 }

References array_cmp(), PG_GETARG_DATUM, and PG_RETURN_DATUM.

◆ array_unnest()

Datum array_unnest ( PG_FUNCTION_ARGS  )

Definition at line 6173 of file arrayfuncs.c.

6174 {
6175  typedef struct
6176  {
6177  array_iter iter;
6178  int nextelem;
6179  int numelems;
6180  int16 elmlen;
6181  bool elmbyval;
6182  char elmalign;
6183  } array_unnest_fctx;
6184 
6185  FuncCallContext *funcctx;
6186  array_unnest_fctx *fctx;
6187  MemoryContext oldcontext;
6188 
6189  /* stuff done only on the first call of the function */
6190  if (SRF_IS_FIRSTCALL())
6191  {
6192  AnyArrayType *arr;
6193 
6194  /* create a function context for cross-call persistence */
6195  funcctx = SRF_FIRSTCALL_INIT();
6196 
6197  /*
6198  * switch to memory context appropriate for multiple function calls
6199  */
6200  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
6201 
6202  /*
6203  * Get the array value and detoast if needed. We can't do this
6204  * earlier because if we have to detoast, we want the detoasted copy
6205  * to be in multi_call_memory_ctx, so it will go away when we're done
6206  * and not before. (If no detoast happens, we assume the originally
6207  * passed array will stick around till then.)
6208  */
6209  arr = PG_GETARG_ANY_ARRAY_P(0);
6210 
6211  /* allocate memory for user context */
6212  fctx = (array_unnest_fctx *) palloc(sizeof(array_unnest_fctx));
6213 
6214  /* initialize state */
6215  array_iter_setup(&fctx->iter, arr);
6216  fctx->nextelem = 0;
6217  fctx->numelems = ArrayGetNItems(AARR_NDIM(arr), AARR_DIMS(arr));
6218 
6219  if (VARATT_IS_EXPANDED_HEADER(arr))
6220  {
6221  /* we can just grab the type data from expanded array */
6222  fctx->elmlen = arr->xpn.typlen;
6223  fctx->elmbyval = arr->xpn.typbyval;
6224  fctx->elmalign = arr->xpn.typalign;
6225  }
6226  else
6228  &fctx->elmlen,
6229  &fctx->elmbyval,
6230  &fctx->elmalign);
6231 
6232  funcctx->user_fctx = fctx;
6233  MemoryContextSwitchTo(oldcontext);
6234  }
6235 
6236  /* stuff done on every call of the function */
6237  funcctx = SRF_PERCALL_SETUP();
6238  fctx = funcctx->user_fctx;
6239 
6240  if (fctx->nextelem < fctx->numelems)
6241  {
6242  int offset = fctx->nextelem++;
6243  Datum elem;
6244 
6245  elem = array_iter_next(&fctx->iter, &fcinfo->isnull, offset,
6246  fctx->elmlen, fctx->elmbyval, fctx->elmalign);
6247 
6248  SRF_RETURN_NEXT(funcctx, elem);
6249  }
6250  else
6251  {
6252  /* do when there is no more left */
6253  SRF_RETURN_DONE(funcctx);
6254  }
6255 }
#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 6261 of file arrayfuncs.c.

6262 {
6263  Node *rawreq = (Node *) PG_GETARG_POINTER(0);
6264  Node *ret = NULL;
6265 
6266  if (IsA(rawreq, SupportRequestRows))
6267  {
6268  /* Try to estimate the number of rows returned */
6269  SupportRequestRows *req = (SupportRequestRows *) rawreq;
6270 
6271  if (is_funcclause(req->node)) /* be paranoid */
6272  {
6273  List *args = ((FuncExpr *) req->node)->args;
6274  Node *arg1;
6275 
6276  /* We can use estimated argument values here */
6278 
6279  req->rows = estimate_array_length(arg1);
6280  ret = (Node *) req;
6281  }
6282  }
6283 
6284  PG_RETURN_POINTER(ret);
6285 }
Node * estimate_expression_value(PlannerInfo *root, Node *node)
Definition: clauses.c:2273
#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:168
#define linitial(l)
Definition: pg_list.h:176
int estimate_array_length(Node *arrayexpr)
Definition: selfuncs.c:2133
Definition: pg_list.h:52
Definition: nodes.h:118
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 1743 of file arrayfuncs.c.

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

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

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

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

4506 {
4507  AnyArrayType *array1 = PG_GETARG_ANY_ARRAY_P(0);
4508  AnyArrayType *array2 = PG_GETARG_ANY_ARRAY_P(1);
4509  Oid collation = PG_GET_COLLATION();
4510  bool result;
4511 
4512  result = array_contain_compare(array1, array2, collation, true,
4513  &fcinfo->flinfo->fn_extra);
4514 
4515  /* Avoid leaking memory when handed toasted input. */
4516  AARR_FREE_IF_COPY(array1, 0);
4517  AARR_FREE_IF_COPY(array2, 1);
4518 
4519  PG_RETURN_BOOL(result);
4520 }
static bool array_contain_compare(AnyArrayType *array1, AnyArrayType *array2, Oid collation, bool matchall, void **fn_extra)
Definition: arrayfuncs.c:4326

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

◆ arraycontains()

Datum arraycontains ( PG_FUNCTION_ARGS  )

Definition at line 4487 of file arrayfuncs.c.

4488 {
4489  AnyArrayType *array1 = PG_GETARG_ANY_ARRAY_P(0);
4490  AnyArrayType *array2 = PG_GETARG_ANY_ARRAY_P(1);
4491  Oid collation = PG_GET_COLLATION();
4492  bool result;
4493 
4494  result = array_contain_compare(array2, array1, collation, true,
4495  &fcinfo->flinfo->fn_extra);
4496 
4497  /* Avoid leaking memory when handed toasted input. */
4498  AARR_FREE_IF_COPY(array1, 0);
4499  AARR_FREE_IF_COPY(array2, 1);
4500 
4501  PG_RETURN_BOOL(result);
4502 }

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

◆ ArrayCount()

static int ArrayCount ( const char *  str,
int *  dim,
char  typdelim 
)
static

Definition at line 456 of file arrayfuncs.c.

457 {
458  int nest_level = 0,
459  i;
460  int ndim = 1,
461  temp[MAXDIM],
462  nelems[MAXDIM],
463  nelems_last[MAXDIM];
464  bool in_quotes = false;
465  bool eoArray = false;
466  bool empty_array = true;
467  const char *ptr;
468  ArrayParseState parse_state =