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_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)
 
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 5123 of file arrayfuncs.c.

5127 {
5128  MemoryContext oldcontext;
5129 
5130  if (astate == NULL)
5131  {
5132  /* First time through --- initialize */
5133  astate = initArrayResult(element_type, rcontext, true);
5134  }
5135  else
5136  {
5137  Assert(astate->element_type == element_type);
5138  }
5139 
5140  oldcontext = MemoryContextSwitchTo(astate->mcontext);
5141 
5142  /* enlarge dvalues[]/dnulls[] if needed */
5143  if (astate->nelems >= astate->alen)
5144  {
5145  astate->alen *= 2;
5146  astate->dvalues = (Datum *)
5147  repalloc(astate->dvalues, astate->alen * sizeof(Datum));
5148  astate->dnulls = (bool *)
5149  repalloc(astate->dnulls, astate->alen * sizeof(bool));
5150  }
5151 
5152  /*
5153  * Ensure pass-by-ref stuff is copied into mcontext; and detoast it too if
5154  * it's varlena. (You might think that detoasting is not needed here
5155  * because construct_md_array can detoast the array elements later.
5156  * However, we must not let construct_md_array modify the ArrayBuildState
5157  * because that would mean array_agg_finalfn damages its input, which is
5158  * verboten. Also, this way frequently saves one copying step.)
5159  */
5160  if (!disnull && !astate->typbyval)
5161  {
5162  if (astate->typlen == -1)
5163  dvalue = PointerGetDatum(PG_DETOAST_DATUM_COPY(dvalue));
5164  else
5165  dvalue = datumCopy(dvalue, astate->typbyval, astate->typlen);
5166  }
5167 
5168  astate->dvalues[astate->nelems] = dvalue;
5169  astate->dnulls[astate->nelems] = disnull;
5170  astate->nelems++;
5171 
5172  MemoryContextSwitchTo(oldcontext);
5173 
5174  return astate;
5175 }
ArrayBuildState * initArrayResult(Oid element_type, MemoryContext rcontext, bool subcontext)
Definition: arrayfuncs.c:5084
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:1188
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
uintptr_t Datum
Definition: postgres.h:411
#define PointerGetDatum(X)
Definition: postgres.h:600
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(), get_altertable_subcmdtypes(), 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 5594 of file arrayfuncs.c.

5598 {
5599  if (astate == NULL)
5600  astate = initArrayResultAny(input_type, rcontext, true);
5601 
5602  if (astate->scalarstate)
5603  (void) accumArrayResult(astate->scalarstate,
5604  dvalue, disnull,
5605  input_type, rcontext);
5606  else
5607  (void) accumArrayResultArr(astate->arraystate,
5608  dvalue, disnull,
5609  input_type, rcontext);
5610 
5611  return astate;
5612 }
ArrayBuildState * accumArrayResult(ArrayBuildState *astate, Datum dvalue, bool disnull, Oid element_type, MemoryContext rcontext)
Definition: arrayfuncs.c:5123
ArrayBuildStateAny * initArrayResultAny(Oid input_type, MemoryContext rcontext, bool subcontext)
Definition: arrayfuncs.c:5549
ArrayBuildStateArr * accumArrayResultArr(ArrayBuildStateArr *astate, Datum dvalue, bool disnull, Oid array_type, MemoryContext rcontext)
Definition: arrayfuncs.c:5317
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 5317 of file arrayfuncs.c.

5321 {
5322  ArrayType *arg;
5323  MemoryContext oldcontext;
5324  int *dims,
5325  *lbs,
5326  ndims,
5327  nitems,
5328  ndatabytes;
5329  char *data;
5330  int i;
5331 
5332  /*
5333  * We disallow accumulating null subarrays. Another plausible definition
5334  * is to ignore them, but callers that want that can just skip calling
5335  * this function.
5336  */
5337  if (disnull)
5338  ereport(ERROR,
5339  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
5340  errmsg("cannot accumulate null arrays")));
5341 
5342  /* Detoast input array in caller's context */
5343  arg = DatumGetArrayTypeP(dvalue);
5344 
5345  if (astate == NULL)
5346  astate = initArrayResultArr(array_type, InvalidOid, rcontext, true);
5347  else
5348  Assert(astate->array_type == array_type);
5349 
5350  oldcontext = MemoryContextSwitchTo(astate->mcontext);
5351 
5352  /* Collect this input's dimensions */
5353  ndims = ARR_NDIM(arg);
5354  dims = ARR_DIMS(arg);
5355  lbs = ARR_LBOUND(arg);
5356  data = ARR_DATA_PTR(arg);
5357  nitems = ArrayGetNItems(ndims, dims);
5358  ndatabytes = ARR_SIZE(arg) - ARR_DATA_OFFSET(arg);
5359 
5360  if (astate->ndims == 0)
5361  {
5362  /* First input; check/save the dimensionality info */
5363 
5364  /* Should we allow empty inputs and just produce an empty output? */
5365  if (ndims == 0)
5366  ereport(ERROR,
5367  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
5368  errmsg("cannot accumulate empty arrays")));
5369  if (ndims + 1 > MAXDIM)
5370  ereport(ERROR,
5371  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
5372  errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
5373  ndims + 1, MAXDIM)));
5374 
5375  /*
5376  * The output array will have n+1 dimensions, with the ones after the
5377  * first matching the input's dimensions.
5378  */
5379  astate->ndims = ndims + 1;
5380  astate->dims[0] = 0;
5381  memcpy(&astate->dims[1], dims, ndims * sizeof(int));
5382  astate->lbs[0] = 1;
5383  memcpy(&astate->lbs[1], lbs, ndims * sizeof(int));
5384 
5385  /* Allocate at least enough data space for this item */
5386  astate->abytes = pg_nextpower2_32(Max(1024, ndatabytes + 1));
5387  astate->data = (char *) palloc(astate->abytes);
5388  }
5389  else
5390  {
5391  /* Second or later input: must match first input's dimensionality */
5392  if (astate->ndims != ndims + 1)
5393  ereport(ERROR,
5394  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
5395  errmsg("cannot accumulate arrays of different dimensionality")));
5396  for (i = 0; i < ndims; i++)
5397  {
5398  if (astate->dims[i + 1] != dims[i] || astate->lbs[i + 1] != lbs[i])
5399  ereport(ERROR,
5400  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
5401  errmsg("cannot accumulate arrays of different dimensionality")));
5402  }
5403 
5404  /* Enlarge data space if needed */
5405  if (astate->nbytes + ndatabytes > astate->abytes)
5406  {
5407  astate->abytes = Max(astate->abytes * 2,
5408  astate->nbytes + ndatabytes);
5409  astate->data = (char *) repalloc(astate->data, astate->abytes);
5410  }
5411  }
5412 
5413  /*
5414  * Copy the data portion of the sub-array. Note we assume that the
5415  * advertised data length of the sub-array is properly aligned. We do not
5416  * have to worry about detoasting elements since whatever's in the
5417  * sub-array should be OK already.
5418  */
5419  memcpy(astate->data + astate->nbytes, data, ndatabytes);
5420  astate->nbytes += ndatabytes;
5421 
5422  /* Deal with null bitmap if needed */
5423  if (astate->nullbitmap || ARR_HASNULL(arg))
5424  {
5425  int newnitems = astate->nitems + nitems;
5426 
5427  if (astate->nullbitmap == NULL)
5428  {
5429  /*
5430  * First input with nulls; we must retrospectively handle any
5431  * previous inputs by marking all their items non-null.
5432  */
5433  astate->aitems = pg_nextpower2_32(Max(256, newnitems + 1));
5434  astate->nullbitmap = (bits8 *) palloc((astate->aitems + 7) / 8);
5435  array_bitmap_copy(astate->nullbitmap, 0,
5436  NULL, 0,
5437  astate->nitems);
5438  }
5439  else if (newnitems > astate->aitems)
5440  {
5441  astate->aitems = Max(astate->aitems * 2, newnitems);
5442  astate->nullbitmap = (bits8 *)
5443  repalloc(astate->nullbitmap, (astate->aitems + 7) / 8);
5444  }
5445  array_bitmap_copy(astate->nullbitmap, astate->nitems,
5446  ARR_NULLBITMAP(arg), 0,
5447  nitems);
5448  }
5449 
5450  astate->nitems += nitems;
5451  astate->dims[0] += 1;
5452 
5453  MemoryContextSwitchTo(oldcontext);
5454 
5455  /* Release detoasted copy if any */
5456  if ((Pointer) arg != DatumGetPointer(dvalue))
5457  pfree(arg);
5458 
5459  return astate;
5460 }
#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:5271
void array_bitmap_copy(bits8 *destbitmap, int destoffset, const bits8 *srcbitmap, int srcoffset, int nitems)
Definition: arrayfuncs.c:4757
int ArrayGetNItems(int ndim, const int *dims)
Definition: arrayutils.c:76
#define Max(x, y)
Definition: c.h:980
char * Pointer
Definition: c.h:418
uint8 bits8
Definition: c.h:448
int errcode(int sqlerrcode)
Definition: elog.c:693
int errmsg(const char *fmt,...)
Definition: elog.c:904
#define ERROR
Definition: elog.h:33
#define ereport(elevel,...)
Definition: elog.h:143
int i
Definition: isn.c:73
void pfree(void *pointer)
Definition: mcxt.c:1175
void * palloc(Size size)
Definition: mcxt.c:1068
void * arg
static uint32 pg_nextpower2_32(uint32 num)
Definition: pg_bitutils.h:140
const void * data
#define DatumGetPointer(X)
Definition: postgres.h:593
#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 4757 of file arrayfuncs.c.

4760 {
4761  int destbitmask,
4762  destbitval,
4763  srcbitmask,
4764  srcbitval;
4765 
4766  Assert(destbitmap);
4767  if (nitems <= 0)
4768  return; /* don't risk fetch off end of memory */
4769  destbitmap += destoffset / 8;
4770  destbitmask = 1 << (destoffset % 8);
4771  destbitval = *destbitmap;
4772  if (srcbitmap)
4773  {
4774  srcbitmap += srcoffset / 8;
4775  srcbitmask = 1 << (srcoffset % 8);
4776  srcbitval = *srcbitmap;
4777  while (nitems-- > 0)
4778  {
4779  if (srcbitval & srcbitmask)
4780  destbitval |= destbitmask;
4781  else
4782  destbitval &= ~destbitmask;
4783  destbitmask <<= 1;
4784  if (destbitmask == 0x100)
4785  {
4786  *destbitmap++ = destbitval;
4787  destbitmask = 1;
4788  if (nitems > 0)
4789  destbitval = *destbitmap;
4790  }
4791  srcbitmask <<= 1;
4792  if (srcbitmask == 0x100)
4793  {
4794  srcbitmap++;
4795  srcbitmask = 1;
4796  if (nitems > 0)
4797  srcbitval = *srcbitmap;
4798  }
4799  }
4800  if (destbitmask != 1)
4801  *destbitmap = destbitval;
4802  }
4803  else
4804  {
4805  while (nitems-- > 0)
4806  {
4807  destbitval |= destbitmask;
4808  destbitmask <<= 1;
4809  if (destbitmask == 0x100)
4810  {
4811  *destbitmap++ = destbitval;
4812  destbitmask = 1;
4813  if (nitems > 0)
4814  destbitval = *destbitmap;
4815  }
4816  }
4817  if (destbitmask != 1)
4818  *destbitmap = destbitval;
4819  }
4820 }

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

1802 {
1804 
1806 }
#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 3776 of file arrayfuncs.c.

3777 {
3778  LOCAL_FCINFO(locfcinfo, 2);
3779  AnyArrayType *array1 = PG_GETARG_ANY_ARRAY_P(0);
3780  AnyArrayType *array2 = PG_GETARG_ANY_ARRAY_P(1);
3781  Oid collation = PG_GET_COLLATION();
3782  int ndims1 = AARR_NDIM(array1);
3783  int ndims2 = AARR_NDIM(array2);
3784  int *dims1 = AARR_DIMS(array1);
3785  int *dims2 = AARR_DIMS(array2);
3786  int nitems1 = ArrayGetNItems(ndims1, dims1);
3787  int nitems2 = ArrayGetNItems(ndims2, dims2);
3788  Oid element_type = AARR_ELEMTYPE(array1);
3789  int result = 0;
3790  TypeCacheEntry *typentry;
3791  int typlen;
3792  bool typbyval;
3793  char typalign;
3794  int min_nitems;
3795  array_iter it1;
3796  array_iter it2;
3797  int i;
3798 
3799  if (element_type != AARR_ELEMTYPE(array2))
3800  ereport(ERROR,
3801  (errcode(ERRCODE_DATATYPE_MISMATCH),
3802  errmsg("cannot compare arrays of different element types")));
3803 
3804  /*
3805  * We arrange to look up the comparison function only once per series of
3806  * calls, assuming the element type doesn't change underneath us. The
3807  * typcache is used so that we have no memory leakage when being used as
3808  * an index support function.
3809  */
3810  typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
3811  if (typentry == NULL ||
3812  typentry->type_id != element_type)
3813  {
3814  typentry = lookup_type_cache(element_type,
3816  if (!OidIsValid(typentry->cmp_proc_finfo.fn_oid))
3817  ereport(ERROR,
3818  (errcode(ERRCODE_UNDEFINED_FUNCTION),
3819  errmsg("could not identify a comparison function for type %s",
3820  format_type_be(element_type))));
3821  fcinfo->flinfo->fn_extra = (void *) typentry;
3822  }
3823  typlen = typentry->typlen;
3824  typbyval = typentry->typbyval;
3825  typalign = typentry->typalign;
3826 
3827  /*
3828  * apply the operator to each pair of array elements.
3829  */
3830  InitFunctionCallInfoData(*locfcinfo, &typentry->cmp_proc_finfo, 2,
3831  collation, NULL, NULL);
3832 
3833  /* Loop over source data */
3834  min_nitems = Min(nitems1, nitems2);
3835  array_iter_setup(&it1, array1);
3836  array_iter_setup(&it2, array2);
3837 
3838  for (i = 0; i < min_nitems; i++)
3839  {
3840  Datum elt1;
3841  Datum elt2;
3842  bool isnull1;
3843  bool isnull2;
3844  int32 cmpresult;
3845 
3846  /* Get elements, checking for NULL */
3847  elt1 = array_iter_next(&it1, &isnull1, i, typlen, typbyval, typalign);
3848  elt2 = array_iter_next(&it2, &isnull2, i, typlen, typbyval, typalign);
3849 
3850  /*
3851  * We consider two NULLs equal; NULL > not-NULL.
3852  */
3853  if (isnull1 && isnull2)
3854  continue;
3855  if (isnull1)
3856  {
3857  /* arg1 is greater than arg2 */
3858  result = 1;
3859  break;
3860  }
3861  if (isnull2)
3862  {
3863  /* arg1 is less than arg2 */
3864  result = -1;
3865  break;
3866  }
3867 
3868  /* Compare the pair of elements */
3869  locfcinfo->args[0].value = elt1;
3870  locfcinfo->args[0].isnull = false;
3871  locfcinfo->args[1].value = elt2;
3872  locfcinfo->args[1].isnull = false;
3873  cmpresult = DatumGetInt32(FunctionCallInvoke(locfcinfo));
3874 
3875  /* We don't expect comparison support functions to return null */
3876  Assert(!locfcinfo->isnull);
3877 
3878  if (cmpresult == 0)
3879  continue; /* equal */
3880 
3881  if (cmpresult < 0)
3882  {
3883  /* arg1 is less than arg2 */
3884  result = -1;
3885  break;
3886  }
3887  else
3888  {
3889  /* arg1 is greater than arg2 */
3890  result = 1;
3891  break;
3892  }
3893  }
3894 
3895  /*
3896  * If arrays contain same data (up to end of shorter one), apply
3897  * additional rules to sort by dimensionality. The relative significance
3898  * of the different bits of information is historical; mainly we just care
3899  * that we don't say "equal" for arrays of different dimensionality.
3900  */
3901  if (result == 0)
3902  {
3903  if (nitems1 != nitems2)
3904  result = (nitems1 < nitems2) ? -1 : 1;
3905  else if (ndims1 != ndims2)
3906  result = (ndims1 < ndims2) ? -1 : 1;
3907  else
3908  {
3909  for (i = 0; i < ndims1; i++)
3910  {
3911  if (dims1[i] != dims2[i])
3912  {
3913  result = (dims1[i] < dims2[i]) ? -1 : 1;
3914  break;
3915  }
3916  }
3917  if (result == 0)
3918  {
3919  int *lbound1 = AARR_LBOUND(array1);
3920  int *lbound2 = AARR_LBOUND(array2);
3921 
3922  for (i = 0; i < ndims1; i++)
3923  {
3924  if (lbound1[i] != lbound2[i])
3925  {
3926  result = (lbound1[i] < lbound2[i]) ? -1 : 1;
3927  break;
3928  }
3929  }
3930  }
3931  }
3932  }
3933 
3934  /* Avoid leaking memory when handed toasted input. */
3935  AARR_FREE_IF_COPY(array1, 0);
3936  AARR_FREE_IF_COPY(array2, 1);
3937 
3938  return result;
3939 }
#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:986
signed int int32
Definition: c.h:429
#define OidIsValid(objectId)
Definition: c.h:710
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition: fmgr.h:150
#define LOCAL_FCINFO(name, nargs)
Definition: fmgr.h:110
#define FunctionCallInvoke(fcinfo)
Definition: fmgr.h:172
#define PG_GET_COLLATION()
Definition: fmgr.h:198
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
char typalign
Definition: pg_type.h:176
#define DatumGetInt32(X)
Definition: postgres.h:516
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 4172 of file arrayfuncs.c.

4174 {
4175  LOCAL_FCINFO(locfcinfo, 2);
4176  bool result = matchall;
4177  Oid element_type = AARR_ELEMTYPE(array1);
4178  TypeCacheEntry *typentry;
4179  int nelems1;
4180  Datum *values2;
4181  bool *nulls2;
4182  int nelems2;
4183  int typlen;
4184  bool typbyval;
4185  char typalign;
4186  int i;
4187  int j;
4188  array_iter it1;
4189 
4190  if (element_type != AARR_ELEMTYPE(array2))
4191  ereport(ERROR,
4192  (errcode(ERRCODE_DATATYPE_MISMATCH),
4193  errmsg("cannot compare arrays of different element types")));
4194 
4195  /*
4196  * We arrange to look up the equality function only once per series of
4197  * calls, assuming the element type doesn't change underneath us. The
4198  * typcache is used so that we have no memory leakage when being used as
4199  * an index support function.
4200  */
4201  typentry = (TypeCacheEntry *) *fn_extra;
4202  if (typentry == NULL ||
4203  typentry->type_id != element_type)
4204  {
4205  typentry = lookup_type_cache(element_type,
4207  if (!OidIsValid(typentry->eq_opr_finfo.fn_oid))
4208  ereport(ERROR,
4209  (errcode(ERRCODE_UNDEFINED_FUNCTION),
4210  errmsg("could not identify an equality operator for type %s",
4211  format_type_be(element_type))));
4212  *fn_extra = (void *) typentry;
4213  }
4214  typlen = typentry->typlen;
4215  typbyval = typentry->typbyval;
4216  typalign = typentry->typalign;
4217 
4218  /*
4219  * Since we probably will need to scan array2 multiple times, it's
4220  * worthwhile to use deconstruct_array on it. We scan array1 the hard way
4221  * however, since we very likely won't need to look at all of it.
4222  */
4223  if (VARATT_IS_EXPANDED_HEADER(array2))
4224  {
4225  /* This should be safe even if input is read-only */
4226  deconstruct_expanded_array(&(array2->xpn));
4227  values2 = array2->xpn.dvalues;
4228  nulls2 = array2->xpn.dnulls;
4229  nelems2 = array2->xpn.nelems;
4230  }
4231  else
4232  deconstruct_array((ArrayType *) array2,
4233  element_type, typlen, typbyval, typalign,
4234  &values2, &nulls2, &nelems2);
4235 
4236  /*
4237  * Apply the comparison operator to each pair of array elements.
4238  */
4239  InitFunctionCallInfoData(*locfcinfo, &typentry->eq_opr_finfo, 2,
4240  collation, NULL, NULL);
4241 
4242  /* Loop over source data */
4243  nelems1 = ArrayGetNItems(AARR_NDIM(array1), AARR_DIMS(array1));
4244  array_iter_setup(&it1, array1);
4245 
4246  for (i = 0; i < nelems1; i++)
4247  {
4248  Datum elt1;
4249  bool isnull1;
4250 
4251  /* Get element, checking for NULL */
4252  elt1 = array_iter_next(&it1, &isnull1, i, typlen, typbyval, typalign);
4253 
4254  /*
4255  * We assume that the comparison operator is strict, so a NULL can't
4256  * match anything. XXX this diverges from the "NULL=NULL" behavior of
4257  * array_eq, should we act like that?
4258  */
4259  if (isnull1)
4260  {
4261  if (matchall)
4262  {
4263  result = false;
4264  break;
4265  }
4266  continue;
4267  }
4268 
4269  for (j = 0; j < nelems2; j++)
4270  {
4271  Datum elt2 = values2[j];
4272  bool isnull2 = nulls2 ? nulls2[j] : false;
4273  bool oprresult;
4274 
4275  if (isnull2)
4276  continue; /* can't match */
4277 
4278  /*
4279  * Apply the operator to the element pair; treat NULL as false
4280  */
4281  locfcinfo->args[0].value = elt1;
4282  locfcinfo->args[0].isnull = false;
4283  locfcinfo->args[1].value = elt2;
4284  locfcinfo->args[1].isnull = false;
4285  locfcinfo->isnull = false;
4286  oprresult = DatumGetBool(FunctionCallInvoke(locfcinfo));
4287  if (!locfcinfo->isnull && oprresult)
4288  break;
4289  }
4290 
4291  if (j < nelems2)
4292  {
4293  /* found a match for elt1 */
4294  if (!matchall)
4295  {
4296  result = true;
4297  break;
4298  }
4299  }
4300  else
4301  {
4302  /* no match for elt1 */
4303  if (matchall)
4304  {
4305  result = false;
4306  break;
4307  }
4308  }
4309  }
4310 
4311  return result;
4312 }
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:3491
int j
Definition: isn.c:74
#define DatumGetBool(X)
Definition: postgres.h:437
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 3558 of file arrayfuncs.c.

3559 {
3560  int nelems;
3561  bits8 *bitmap;
3562  int bitmask;
3563 
3564  /* Easy answer if there's no null bitmap */
3565  if (!ARR_HASNULL(array))
3566  return false;
3567 
3568  nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
3569 
3570  bitmap = ARR_NULLBITMAP(array);
3571 
3572  /* check whole bytes of the bitmap byte-at-a-time */
3573  while (nelems >= 8)
3574  {
3575  if (*bitmap != 0xFF)
3576  return true;
3577  bitmap++;
3578  nelems -= 8;
3579  }
3580 
3581  /* check last partial byte */
3582  bitmask = 1;
3583  while (nelems > 0)
3584  {
3585  if ((*bitmap & bitmask) == 0)
3586  return true;
3587  bitmask <<= 1;
3588  nelems--;
3589  }
3590 
3591  return false;
3592 }

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

4730 {
4731  int numbytes;
4732 
4733  numbytes = array_nelems_size(srcptr, offset, nullbitmap, nitems,
4734  typlen, typbyval, typalign);
4735  memcpy(destptr, srcptr, numbytes);
4736  return numbytes;
4737 }
static int array_nelems_size(char *ptr, int offset, bits8 *nullbitmap, int nitems, int typlen, bool typbyval, char typalign)
Definition: arrayfuncs.c:4705

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

4389 {
4390  ArrayIterator iterator = palloc0(sizeof(ArrayIteratorData));
4391 
4392  /*
4393  * Sanity-check inputs --- caller should have got this right already
4394  */
4395  Assert(PointerIsValid(arr));
4396  if (slice_ndim < 0 || slice_ndim > ARR_NDIM(arr))
4397  elog(ERROR, "invalid arguments to array_create_iterator");
4398 
4399  /*
4400  * Remember basic info about the array and its element type
4401  */
4402  iterator->arr = arr;
4403  iterator->nullbitmap = ARR_NULLBITMAP(arr);
4404  iterator->nitems = ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr));
4405 
4406  if (mstate != NULL)
4407  {
4408  Assert(mstate->element_type == ARR_ELEMTYPE(arr));
4409 
4410  iterator->typlen = mstate->typlen;
4411  iterator->typbyval = mstate->typbyval;
4412  iterator->typalign = mstate->typalign;
4413  }
4414  else
4416  &iterator->typlen,
4417  &iterator->typbyval,
4418  &iterator->typalign);
4419 
4420  /*
4421  * Remember the slicing parameters.
4422  */
4423  iterator->slice_ndim = slice_ndim;
4424 
4425  if (slice_ndim > 0)
4426  {
4427  /*
4428  * Get pointers into the array's dims and lbound arrays to represent
4429  * the dims/lbound arrays of a slice. These are the same as the
4430  * rightmost N dimensions of the array.
4431  */
4432  iterator->slice_dims = ARR_DIMS(arr) + ARR_NDIM(arr) - slice_ndim;
4433  iterator->slice_lbound = ARR_LBOUND(arr) + ARR_NDIM(arr) - slice_ndim;
4434 
4435  /*
4436  * Compute number of elements in a slice.
4437  */
4438  iterator->slice_len = ArrayGetNItems(slice_ndim,
4439  iterator->slice_dims);
4440 
4441  /*
4442  * Create workspace for building sub-arrays.
4443  */
4444  iterator->slice_values = (Datum *)
4445  palloc(iterator->slice_len * sizeof(Datum));
4446  iterator->slice_nulls = (bool *)
4447  palloc(iterator->slice_len * sizeof(bool));
4448  }
4449 
4450  /*
4451  * Initialize our data pointer and linear element number. These will
4452  * advance through the array during array_iterate().
4453  */
4454  iterator->data_ptr = ARR_DATA_PTR(arr);
4455  iterator->current_item = 0;
4456 
4457  return iterator;
4458 }
#define ARR_ELEMTYPE(a)
Definition: array.h:285
#define PointerIsValid(pointer)
Definition: c.h:698
#define elog(elevel,...)
Definition: elog.h:218
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2228
void * palloc0(Size size)
Definition: mcxt.c:1099
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 1679 of file arrayfuncs.c.

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

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

3606 {
3607  LOCAL_FCINFO(locfcinfo, 2);
3608  AnyArrayType *array1 = PG_GETARG_ANY_ARRAY_P(0);
3609  AnyArrayType *array2 = PG_GETARG_ANY_ARRAY_P(1);
3610  Oid collation = PG_GET_COLLATION();
3611  int ndims1 = AARR_NDIM(array1);
3612  int ndims2 = AARR_NDIM(array2);
3613  int *dims1 = AARR_DIMS(array1);
3614  int *dims2 = AARR_DIMS(array2);
3615  int *lbs1 = AARR_LBOUND(array1);
3616  int *lbs2 = AARR_LBOUND(array2);
3617  Oid element_type = AARR_ELEMTYPE(array1);
3618  bool result = true;
3619  int nitems;
3620  TypeCacheEntry *typentry;
3621  int typlen;
3622  bool typbyval;
3623  char typalign;
3624  array_iter it1;
3625  array_iter it2;
3626  int i;
3627 
3628  if (element_type != AARR_ELEMTYPE(array2))
3629  ereport(ERROR,
3630  (errcode(ERRCODE_DATATYPE_MISMATCH),
3631  errmsg("cannot compare arrays of different element types")));
3632 
3633  /* fast path if the arrays do not have the same dimensionality */
3634  if (ndims1 != ndims2 ||
3635  memcmp(dims1, dims2, ndims1 * sizeof(int)) != 0 ||
3636  memcmp(lbs1, lbs2, ndims1 * sizeof(int)) != 0)
3637  result = false;
3638  else
3639  {
3640  /*
3641  * We arrange to look up the equality function only once per series of
3642  * calls, assuming the element type doesn't change underneath us. The
3643  * typcache is used so that we have no memory leakage when being used
3644  * as an index support function.
3645  */
3646  typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
3647  if (typentry == NULL ||
3648  typentry->type_id != element_type)
3649  {
3650  typentry = lookup_type_cache(element_type,
3652  if (!OidIsValid(typentry->eq_opr_finfo.fn_oid))
3653  ereport(ERROR,
3654  (errcode(ERRCODE_UNDEFINED_FUNCTION),
3655  errmsg("could not identify an equality operator for type %s",
3656  format_type_be(element_type))));
3657  fcinfo->flinfo->fn_extra = (void *) typentry;
3658  }
3659  typlen = typentry->typlen;
3660  typbyval = typentry->typbyval;
3661  typalign = typentry->typalign;
3662 
3663  /*
3664  * apply the operator to each pair of array elements.
3665  */
3666  InitFunctionCallInfoData(*locfcinfo, &typentry->eq_opr_finfo, 2,
3667  collation, NULL, NULL);
3668 
3669  /* Loop over source data */
3670  nitems = ArrayGetNItems(ndims1, dims1);
3671  array_iter_setup(&it1, array1);
3672  array_iter_setup(&it2, array2);
3673 
3674  for (i = 0; i < nitems; i++)
3675  {
3676  Datum elt1;
3677  Datum elt2;
3678  bool isnull1;
3679  bool isnull2;
3680  bool oprresult;
3681 
3682  /* Get elements, checking for NULL */
3683  elt1 = array_iter_next(&it1, &isnull1, i,
3684  typlen, typbyval, typalign);
3685  elt2 = array_iter_next(&it2, &isnull2, i,
3686  typlen, typbyval, typalign);
3687 
3688  /*
3689  * We consider two NULLs equal; NULL and not-NULL are unequal.
3690  */
3691  if (isnull1 && isnull2)
3692  continue;
3693  if (isnull1 || isnull2)
3694  {
3695  result = false;
3696  break;
3697  }
3698 
3699  /*
3700  * Apply the operator to the element pair; treat NULL as false
3701  */
3702  locfcinfo->args[0].value = elt1;
3703  locfcinfo->args[0].isnull = false;
3704  locfcinfo->args[1].value = elt2;
3705  locfcinfo->args[1].isnull = false;
3706  locfcinfo->isnull = false;
3707  oprresult = DatumGetBool(FunctionCallInvoke(locfcinfo));
3708  if (locfcinfo->isnull || !oprresult)
3709  {
3710  result = false;
3711  break;
3712  }
3713  }
3714  }
3715 
3716  /* Avoid leaking memory when handed toasted input. */
3717  AARR_FREE_IF_COPY(array1, 0);
3718  AARR_FREE_IF_COPY(array2, 1);
3719 
3720  PG_RETURN_BOOL(result);
3721 }
#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 4888 of file arrayfuncs.c.

4899 {
4900  char *destdataptr = ARR_DATA_PTR(newarray);
4901  bits8 *destnullsptr = ARR_NULLBITMAP(newarray);
4902  char *srcdataptr;
4903  int src_offset,
4904  dest_offset,
4905  prod[MAXDIM],
4906  span[MAXDIM],
4907  dist[MAXDIM],
4908  indx[MAXDIM];
4909  int i,
4910  j,
4911  inc;
4912 
4913  src_offset = ArrayGetOffset(ndim, dim, lb, st);
4914  srcdataptr = array_seek(arraydataptr, 0, arraynullsptr, src_offset,
4915  typlen, typbyval, typalign);
4916  mda_get_prod(ndim, dim, prod);
4917  mda_get_range(ndim, span, st, endp);
4918  mda_get_offset_values(ndim, dist, prod, span);
4919  for (i = 0; i < ndim; i++)
4920  indx[i] = 0;
4921  dest_offset = 0;
4922  j = ndim - 1;
4923  do
4924  {
4925  if (dist[j])
4926  {
4927  /* skip unwanted elements */
4928  srcdataptr = array_seek(srcdataptr, src_offset, arraynullsptr,
4929  dist[j],
4930  typlen, typbyval, typalign);
4931  src_offset += dist[j];
4932  }
4933  inc = array_copy(destdataptr, 1,
4934  srcdataptr, src_offset, arraynullsptr,
4935  typlen, typbyval, typalign);
4936  if (destnullsptr)
4937  array_bitmap_copy(destnullsptr, dest_offset,
4938  arraynullsptr, src_offset,
4939  1);
4940  destdataptr += inc;
4941  srcdataptr += inc;
4942  src_offset++;
4943  dest_offset++;
4944  } while ((j = mda_next_tuple(ndim, indx, span)) != -1);
4945 }
static int array_copy(char *destptr, int nitems, char *srcptr, int offset, bits8 *nullbitmap, int typlen, bool typbyval, char typalign)
Definition: arrayfuncs.c:4727
static char * array_seek(char *ptr, int offset, bits8 *nullbitmap, int nitems, int typlen, bool typbyval, char typalign)
Definition: arrayfuncs.c:4657
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 5798 of file arrayfuncs.c.

5799 {
5800  ArrayType *dims;
5801  ArrayType *result;
5802  Oid elmtype;
5803  Datum value;
5804  bool isnull;
5805 
5806  if (PG_ARGISNULL(1))
5807  ereport(ERROR,
5808  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
5809  errmsg("dimension array or low bound array cannot be null")));
5810 
5811  dims = PG_GETARG_ARRAYTYPE_P(1);
5812 
5813  if (!PG_ARGISNULL(0))
5814  {
5815  value = PG_GETARG_DATUM(0);
5816  isnull = false;
5817  }
5818  else
5819  {
5820  value = 0;
5821  isnull = true;
5822  }
5823 
5824  elmtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
5825  if (!OidIsValid(elmtype))
5826  elog(ERROR, "could not determine data type of input");
5827 
5828  result = array_fill_internal(dims, NULL, value, isnull, elmtype, fcinfo);
5829  PG_RETURN_ARRAYTYPE_P(result);
5830 }
#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:5850
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 @151 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 5850 of file arrayfuncs.c.

5853 {
5854  ArrayType *result;
5855  int *dimv;
5856  int *lbsv;
5857  int ndims;
5858  int nitems;
5859  int deflbs[MAXDIM];
5860  int16 elmlen;
5861  bool elmbyval;
5862  char elmalign;
5863  ArrayMetaState *my_extra;
5864 
5865  /*
5866  * Params checks
5867  */
5868  if (ARR_NDIM(dims) > 1)
5869  ereport(ERROR,
5870  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
5871  errmsg("wrong number of array subscripts"),
5872  errdetail("Dimension array must be one dimensional.")));
5873 
5874  if (array_contains_nulls(dims))
5875  ereport(ERROR,
5876  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
5877  errmsg("dimension values cannot be null")));
5878 
5879  dimv = (int *) ARR_DATA_PTR(dims);
5880  ndims = (ARR_NDIM(dims) > 0) ? ARR_DIMS(dims)[0] : 0;
5881 
5882  if (ndims < 0) /* we do allow zero-dimension arrays */
5883  ereport(ERROR,
5884  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5885  errmsg("invalid number of dimensions: %d", ndims)));
5886  if (ndims > MAXDIM)
5887  ereport(ERROR,
5888  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
5889  errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
5890  ndims, MAXDIM)));
5891 
5892  if (lbs != NULL)
5893  {
5894  if (ARR_NDIM(lbs) > 1)
5895  ereport(ERROR,
5896  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
5897  errmsg("wrong number of array subscripts"),
5898  errdetail("Dimension array must be one dimensional.")));
5899 
5900  if (array_contains_nulls(lbs))
5901  ereport(ERROR,
5902  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
5903  errmsg("dimension values cannot be null")));
5904 
5905  if (ndims != ((ARR_NDIM(lbs) > 0) ? ARR_DIMS(lbs)[0] : 0))
5906  ereport(ERROR,
5907  (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
5908  errmsg("wrong number of array subscripts"),
5909  errdetail("Low bound array has different size than dimensions array.")));
5910 
5911  lbsv = (int *) ARR_DATA_PTR(lbs);
5912  }
5913  else
5914  {
5915  int i;
5916 
5917  for (i = 0; i < MAXDIM; i++)
5918  deflbs[i] = 1;
5919 
5920  lbsv = deflbs;
5921  }
5922 
5923  /* This checks for overflow of the array dimensions */
5924  nitems = ArrayGetNItems(ndims, dimv);
5925  ArrayCheckBounds(ndims, dimv, lbsv);
5926 
5927  /* fast track for empty array */
5928  if (nitems <= 0)
5929  return construct_empty_array(elmtype);
5930 
5931  /*
5932  * We arrange to look up info about element type only once per series of
5933  * calls, assuming the element type doesn't change underneath us.
5934  */
5935  my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
5936  if (my_extra == NULL)
5937  {
5938  fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
5939  sizeof(ArrayMetaState));
5940  my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
5941  my_extra->element_type = InvalidOid;
5942  }
5943 
5944  if (my_extra->element_type != elmtype)
5945  {
5946  /* Get info about element type */
5947  get_typlenbyvalalign(elmtype,
5948  &my_extra->typlen,
5949  &my_extra->typbyval,
5950  &my_extra->typalign);
5951  my_extra->element_type = elmtype;
5952  }
5953 
5954  elmlen = my_extra->typlen;
5955  elmbyval = my_extra->typbyval;
5956  elmalign = my_extra->typalign;
5957 
5958  /* compute required space */
5959  if (!isnull)
5960  {
5961  int i;
5962  char *p;
5963  int nbytes;
5964  int totbytes;
5965 
5966  /* make sure data is not toasted */
5967  if (elmlen == -1)
5969 
5970  nbytes = att_addlength_datum(0, elmlen, value);
5971  nbytes = att_align_nominal(nbytes, elmalign);
5972  Assert(nbytes > 0);
5973 
5974  totbytes = nbytes * nitems;
5975 
5976  /* check for overflow of multiplication or total request */
5977  if (totbytes / nbytes != nitems ||
5978  !AllocSizeIsValid(totbytes))
5979  ereport(ERROR,
5980  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
5981  errmsg("array size exceeds the maximum allowed (%d)",
5982  (int) MaxAllocSize)));
5983 
5984  /*
5985  * This addition can't overflow, but it might cause us to go past
5986  * MaxAllocSize. We leave it to palloc to complain in that case.
5987  */
5988  totbytes += ARR_OVERHEAD_NONULLS(ndims);
5989 
5990  result = create_array_envelope(ndims, dimv, lbsv, totbytes,
5991  elmtype, 0);
5992 
5993  p = ARR_DATA_PTR(result);
5994  for (i = 0; i < nitems; i++)
5995  p += ArrayCastAndSet(value, elmlen, elmbyval, elmalign, p);
5996  }
5997  else
5998  {
5999  int nbytes;
6000  int dataoffset;
6001 
6002  dataoffset = ARR_OVERHEAD_WITHNULLS(ndims, nitems);
6003  nbytes = dataoffset;
6004 
6005  result = create_array_envelope(ndims, dimv, lbsv, nbytes,
6006  elmtype, dataoffset);
6007 
6008  /* create_array_envelope already zeroed the bitmap, so we're done */
6009  }
6010 
6011  return result;
6012 }
#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:3558
ArrayType * construct_empty_array(Oid elmtype)
Definition: arrayfuncs.c:3440
static ArrayType * create_array_envelope(int ndims, int *dimv, int *lbsv, int nbytes, Oid elmtype, int dataoffset)
Definition: arrayfuncs.c:5833
static int ArrayCastAndSet(Datum src, int typlen, bool typbyval, char typalign, char *dest)
Definition: arrayfuncs.c:4618
void ArrayCheckBounds(int ndim, const int *dims, const int *lb)
Definition: arrayutils.c:128
signed short int16
Definition: c.h:428
int errdetail(const char *fmt,...)
Definition: elog.c:1037
#define PG_DETOAST_DATUM(datum)
Definition: fmgr.h:240
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:863
#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:148
#define att_addlength_datum(cur_offset, attlen, attdatum)
Definition: tupmacs.h:164

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

5758 {
5759  ArrayType *dims;
5760  ArrayType *lbs;
5761  ArrayType *result;
5762  Oid elmtype;
5763  Datum value;
5764  bool isnull;
5765 
5766  if (PG_ARGISNULL(1) || PG_ARGISNULL(2))
5767  ereport(ERROR,
5768  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
5769  errmsg("dimension array or low bound array cannot be null")));
5770 
5771  dims = PG_GETARG_ARRAYTYPE_P(1);
5772  lbs = PG_GETARG_ARRAYTYPE_P(2);
5773 
5774  if (!PG_ARGISNULL(0))
5775  {
5776  value = PG_GETARG_DATUM(0);
5777  isnull = false;
5778  }
5779  else
5780  {
5781  value = 0;
5782  isnull = true;
5783  }
5784 
5785  elmtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
5786  if (!OidIsValid(elmtype))
5787  elog(ERROR, "could not determine data type of input");
5788 
5789  result = array_fill_internal(dims, lbs, value, isnull, elmtype, fcinfo);
5790  PG_RETURN_ARRAYTYPE_P(result);
5791 }

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

4551 {
4552  if (iterator->slice_ndim > 0)
4553  {
4554  pfree(iterator->slice_values);
4555  pfree(iterator->slice_nulls);
4556  }
4557  pfree(iterator);
4558 }

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

3759 {
3760  PG_RETURN_BOOL(array_cmp(fcinfo) >= 0);
3761 }
static int array_cmp(FunctionCallInfo fcinfo)
Definition: arrayfuncs.c:3776

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

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

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

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

4573 {
4574  if (nullbitmap == NULL)
4575  return false; /* assume not null */
4576  if (nullbitmap[offset / 8] & (1 << (offset % 8)))
4577  return false; /* not null */
4578  return true;
4579 }

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

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

3747 {
3748  PG_RETURN_BOOL(array_cmp(fcinfo) > 0);
3749 }

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:961
#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:2282
@ IOFunc_input
Definition: lsyscache.h:35
char * pstrdup(const char *in)
Definition: mcxt.c:1305
#define printf(...)
Definition: port.h:231
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 4961 of file arrayfuncs.c.

4972 {
4973  char *destPtr = ARR_DATA_PTR(destArray);
4974  char *origPtr = ARR_DATA_PTR(origArray);
4975  char *srcPtr = ARR_DATA_PTR(srcArray);
4976  bits8 *destBitmap = ARR_NULLBITMAP(destArray);
4977  bits8 *origBitmap = ARR_NULLBITMAP(origArray);
4978  bits8 *srcBitmap = ARR_NULLBITMAP(srcArray);
4979  int orignitems = ArrayGetNItems(ARR_NDIM(origArray),
4980  ARR_DIMS(origArray));
4981  int dest_offset,
4982  orig_offset,
4983  src_offset,
4984  prod[MAXDIM],
4985  span[MAXDIM],
4986  dist[MAXDIM],
4987  indx[MAXDIM];
4988  int i,
4989  j,
4990  inc;
4991 
4992  dest_offset = ArrayGetOffset(ndim, dim, lb, st);
4993  /* copy items before the slice start */
4994  inc = array_copy(destPtr, dest_offset,
4995  origPtr, 0, origBitmap,
4996  typlen, typbyval, typalign);
4997  destPtr += inc;
4998  origPtr += inc;
4999  if (destBitmap)
5000  array_bitmap_copy(destBitmap, 0, origBitmap, 0, dest_offset);
5001  orig_offset = dest_offset;
5002  mda_get_prod(ndim, dim, prod);
5003  mda_get_range(ndim, span, st, endp);
5004  mda_get_offset_values(ndim, dist, prod, span);
5005  for (i = 0; i < ndim; i++)
5006  indx[i] = 0;
5007  src_offset = 0;
5008  j = ndim - 1;
5009  do
5010  {
5011  /* Copy/advance over elements between here and next part of slice */
5012  if (dist[j])
5013  {
5014  inc = array_copy(destPtr, dist[j],
5015  origPtr, orig_offset, origBitmap,
5016  typlen, typbyval, typalign);
5017  destPtr += inc;
5018  origPtr += inc;
5019  if (destBitmap)
5020  array_bitmap_copy(destBitmap, dest_offset,
5021  origBitmap, orig_offset,
5022  dist[j]);
5023  dest_offset += dist[j];
5024  orig_offset += dist[j];
5025  }
5026  /* Copy new element at this slice position */
5027  inc = array_copy(destPtr, 1,
5028  srcPtr, src_offset, srcBitmap,
5029  typlen, typbyval, typalign);
5030  if (destBitmap)
5031  array_bitmap_copy(destBitmap, dest_offset,
5032  srcBitmap, src_offset,
5033  1);
5034  destPtr += inc;
5035  srcPtr += inc;
5036  dest_offset++;
5037  src_offset++;
5038  /* Advance over old element at this slice position */
5039  origPtr = array_seek(origPtr, orig_offset, origBitmap, 1,
5040  typlen, typbyval, typalign);
5041  orig_offset++;
5042  } while ((j = mda_next_tuple(ndim, indx, span)) != -1);
5043 
5044  /* don't miss any data at the end */
5045  array_copy(destPtr, orignitems - orig_offset,
5046  origPtr, orig_offset, origBitmap,
5047  typlen, typbyval, typalign);
5048  if (destBitmap)
5049  array_bitmap_copy(destBitmap, dest_offset,
5050  origBitmap, orig_offset,
5051  orignitems - orig_offset);
5052 }

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

4468 {
4469  /* Done if we have reached the end of the array */
4470  if (iterator->current_item >= iterator->nitems)
4471  return false;
4472 
4473  if (iterator->slice_ndim == 0)
4474  {
4475  /*
4476  * Scalar case: return one element.
4477  */
4478  if (array_get_isnull(iterator->nullbitmap, iterator->current_item++))
4479  {
4480  *isnull = true;
4481  *value = (Datum) 0;
4482  }
4483  else
4484  {
4485  /* non-NULL, so fetch the individual Datum to return */
4486  char *p = iterator->data_ptr;
4487 
4488  *isnull = false;
4489  *value = fetch_att(p, iterator->typbyval, iterator->typlen);
4490 
4491  /* Move our data pointer forward to the next element */
4492  p = att_addlength_pointer(p, iterator->typlen, p);
4493  p = (char *) att_align_nominal(p, iterator->typalign);
4494  iterator->data_ptr = p;
4495  }
4496  }
4497  else
4498  {
4499  /*
4500  * Slice case: build and return an array of the requested size.
4501  */
4502  ArrayType *result;
4503  Datum *values = iterator->slice_values;
4504  bool *nulls = iterator->slice_nulls;
4505  char *p = iterator->data_ptr;
4506  int i;
4507 
4508  for (i = 0; i < iterator->slice_len; i++)
4509  {
4510  if (array_get_isnull(iterator->nullbitmap,
4511  iterator->current_item++))
4512  {
4513  nulls[i] = true;
4514  values[i] = (Datum) 0;
4515  }
4516  else
4517  {
4518  nulls[i] = false;
4519  values[i] = fetch_att(p, iterator->typbyval, iterator->typlen);
4520 
4521  /* Move our data pointer forward to the next element */
4522  p = att_addlength_pointer(p, iterator->typlen, p);
4523  p = (char *) att_align_nominal(p, iterator->typalign);
4524  }
4525  }
4526 
4527  iterator->data_ptr = p;
4528 
4529  result = construct_md_array(values,
4530  nulls,
4531  iterator->slice_ndim,
4532  iterator->slice_dims,
4533  iterator->slice_lbound,
4534  ARR_ELEMTYPE(iterator->arr),
4535  iterator->typlen,
4536  iterator->typbyval,
4537  iterator->typalign);
4538 
4539  *isnull = false;
4540  *value = PointerGetDatum(result);
4541  }
4542 
4543  return true;
4544 }
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:3354
static Datum values[MAXATTR]
Definition: bootstrap.c:156
#define att_addlength_pointer(cur_offset, attlen, attptr)
Definition: tupmacs.h:176
#define fetch_att(T, attbyval, attlen)
Definition: tupmacs.h:75

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

5653 {
5654  if (array_cmp(fcinfo) > 0)
5656  else
5658 }
#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 3752 of file arrayfuncs.c.

3753 {
3754  PG_RETURN_BOOL(array_cmp(fcinfo) <= 0);
3755 }

References array_cmp(), and PG_RETURN_BOOL.

◆ array_length()

Datum array_length ( PG_FUNCTION_ARGS  )

Definition at line 1774 of file arrayfuncs.c.

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

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

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

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

3741 {
3742  PG_RETURN_BOOL(array_cmp(fcinfo) < 0);
3743 }

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

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

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

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

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

3735 {
3737 }
Datum array_eq(PG_FUNCTION_ARGS)
Definition: arrayfuncs.c:3605

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

4707 {
4708  return array_seek(ptr, offset, nullbitmap, nitems,
4709  typlen, typbyval, typalign) - ptr;
4710 }

References array_seek(), and typalign.

Referenced by array_copy(), and array_set_slice().

◆ array_out()

Datum array_out ( PG_FUNCTION_ARGS  )

Definition at line 1016 of file arrayfuncs.c.

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

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

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

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

6402 {
6403  ArrayType *array;
6404  Datum search = PG_GETARG_DATUM(1);
6405  bool search_isnull = PG_ARGISNULL(1);
6406 
6407  if (PG_ARGISNULL(0))
6408  PG_RETURN_NULL();
6409  array = PG_GETARG_ARRAYTYPE_P(0);
6410 
6411  array = array_replace_internal(array,
6412  search, search_isnull,
6413  (Datum) 0, true,
6414  true, PG_GET_COLLATION(),
6415  fcinfo);
6416  PG_RETURN_ARRAYTYPE_P(array);
6417 }
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:6143

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

6424 {
6425  ArrayType *array;
6426  Datum search = PG_GETARG_DATUM(1);
6427  bool search_isnull = PG_ARGISNULL(1);
6428  Datum replace = PG_GETARG_DATUM(2);
6429  bool replace_isnull = PG_ARGISNULL(2);
6430 
6431  if (PG_ARGISNULL(0))
6432  PG_RETURN_NULL();
6433  array = PG_GETARG_ARRAYTYPE_P(0);
6434 
6435  array = array_replace_internal(array,
6436  search, search_isnull,
6437  replace, replace_isnull,
6438  false, PG_GET_COLLATION(),
6439  fcinfo);
6440  PG_RETURN_ARRAYTYPE_P(array);
6441 }

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

6148 {
6149  LOCAL_FCINFO(locfcinfo, 2);
6150  ArrayType *result;
6151  Oid element_type;
6152  Datum *values;
6153  bool *nulls;
6154  int *dim;
6155  int ndim;
6156  int nitems,
6157  nresult;
6158  int i;
6159  int32 nbytes = 0;
6160  int32 dataoffset;
6161  bool hasnulls;
6162  int typlen;
6163  bool typbyval;
6164  char typalign;
6165  char *arraydataptr;
6166  bits8 *bitmap;
6167  int bitmask;
6168  bool changed = false;
6169  TypeCacheEntry *typentry;
6170 
6171  element_type = ARR_ELEMTYPE(array);
6172  ndim = ARR_NDIM(array);
6173  dim = ARR_DIMS(array);
6174  nitems = ArrayGetNItems(ndim, dim);
6175 
6176  /* Return input array unmodified if it is empty */
6177  if (nitems <= 0)
6178  return array;
6179 
6180  /*
6181  * We can't remove elements from multi-dimensional arrays, since the
6182  * result might not be rectangular.
6183  */
6184  if (remove && ndim > 1)
6185  ereport(ERROR,
6186  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6187  errmsg("removing elements from multidimensional arrays is not supported")));
6188 
6189  /*
6190  * We arrange to look up the equality function only once per series of
6191  * calls, assuming the element type doesn't change underneath us.
6192  */
6193  typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
6194  if (typentry == NULL ||
6195  typentry->type_id != element_type)
6196  {
6197  typentry = lookup_type_cache(element_type,
6199  if (!OidIsValid(typentry->eq_opr_finfo.fn_oid))
6200  ereport(ERROR,
6201  (errcode(ERRCODE_UNDEFINED_FUNCTION),
6202  errmsg("could not identify an equality operator for type %s",
6203  format_type_be(element_type))));
6204  fcinfo->flinfo->fn_extra = (void *) typentry;
6205  }
6206  typlen = typentry->typlen;
6207  typbyval = typentry->typbyval;
6208  typalign = typentry->typalign;
6209 
6210  /*
6211  * Detoast values if they are toasted. The replacement value must be
6212  * detoasted for insertion into the result array, while detoasting the
6213  * search value only once saves cycles.
6214  */
6215  if (typlen == -1)
6216  {
6217  if (!search_isnull)
6218  search = PointerGetDatum(PG_DETOAST_DATUM(search));
6219  if (!replace_isnull)
6220  replace = PointerGetDatum(PG_DETOAST_DATUM(replace));
6221  }
6222 
6223  /* Prepare to apply the comparison operator */
6224  InitFunctionCallInfoData(*locfcinfo, &typentry->eq_opr_finfo, 2,
6225  collation, NULL, NULL);
6226 
6227  /* Allocate temporary arrays for new values */
6228  values = (Datum *) palloc(nitems * sizeof(Datum));
6229  nulls = (bool *) palloc(nitems * sizeof(bool));
6230 
6231  /* Loop over source data */
6232  arraydataptr = ARR_DATA_PTR(array);
6233  bitmap = ARR_NULLBITMAP(array);
6234  bitmask = 1;
6235  hasnulls = false;
6236  nresult = 0;
6237 
6238  for (i = 0; i < nitems; i++)
6239  {
6240  Datum elt;
6241  bool isNull;
6242  bool oprresult;
6243  bool skip = false;
6244 
6245  /* Get source element, checking for NULL */
6246  if (bitmap && (*bitmap & bitmask) == 0)
6247  {
6248  isNull = true;
6249  /* If searching for NULL, we have a match */
6250  if (search_isnull)
6251  {
6252  if (remove)
6253  {
6254  skip = true;
6255  changed = true;
6256  }
6257  else if (!replace_isnull)
6258  {
6259  values[nresult] = replace;
6260  isNull = false;
6261  changed = true;
6262  }
6263  }
6264  }
6265  else
6266  {
6267  isNull = false;
6268  elt = fetch_att(arraydataptr, typbyval, typlen);
6269  arraydataptr = att_addlength_datum(arraydataptr, typlen, elt);
6270  arraydataptr = (char *) att_align_nominal(arraydataptr, typalign);
6271 
6272  if (search_isnull)
6273  {
6274  /* no match possible, keep element */
6275  values[nresult] = elt;
6276  }
6277  else
6278  {
6279  /*
6280  * Apply the operator to the element pair; treat NULL as false
6281  */
6282  locfcinfo->args[0].value = elt;
6283  locfcinfo->args[0].isnull = false;
6284  locfcinfo->args[1].value = search;
6285  locfcinfo->args[1].isnull = false;
6286  locfcinfo->isnull = false;
6287  oprresult = DatumGetBool(FunctionCallInvoke(locfcinfo));
6288  if (locfcinfo->isnull || !oprresult)
6289  {
6290  /* no match, keep element */
6291  values[nresult] = elt;
6292  }
6293  else
6294  {
6295  /* match, so replace or delete */
6296  changed = true;
6297  if (remove)
6298  skip = true;
6299  else
6300  {
6301  values[nresult] = replace;
6302  isNull = replace_isnull;
6303  }
6304  }
6305  }
6306  }
6307 
6308  if (!skip)
6309  {
6310  nulls[nresult] = isNull;
6311  if (isNull)
6312  hasnulls = true;
6313  else
6314  {
6315  /* Update total result size */
6316  nbytes = att_addlength_datum(nbytes, typlen, values[nresult]);
6317  nbytes = att_align_nominal(nbytes, typalign);
6318  /* check for overflow of total request */
6319  if (!AllocSizeIsValid(nbytes))
6320  ereport(ERROR,
6321  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
6322  errmsg("array size exceeds the maximum allowed (%d)",
6323  (int) MaxAllocSize)));
6324  }
6325  nresult++;
6326  }
6327 
6328  /* advance bitmap pointer if any */
6329  if (bitmap)
6330  {
6331  bitmask <<= 1;
6332  if (bitmask == 0x100)
6333  {
6334  bitmap++;
6335  bitmask = 1;
6336  }
6337  }
6338  }
6339 
6340  /*
6341  * If not changed just return the original array
6342  */
6343  if (!changed)
6344  {
6345  pfree(values);
6346  pfree(nulls);
6347  return array;
6348  }
6349 
6350  /* If all elements were removed return an empty array */
6351  if (nresult == 0)
6352  {
6353  pfree(values);
6354  pfree(nulls);
6355  return construct_empty_array(element_type);
6356  }
6357 
6358  /* Allocate and initialize the result array */
6359  if (hasnulls)
6360  {
6361  dataoffset = ARR_OVERHEAD_WITHNULLS(ndim, nresult);
6362  nbytes += dataoffset;
6363  }
6364  else
6365  {
6366  dataoffset = 0; /* marker for no null bitmap */
6367  nbytes += ARR_OVERHEAD_NONULLS(ndim);
6368  }
6369  result = (ArrayType *) palloc0(nbytes);
6370  SET_VARSIZE(result, nbytes);
6371  result->ndim = ndim;
6372  result->dataoffset = dataoffset;
6373  result->elemtype = element_type;
6374  memcpy(ARR_DIMS(result), ARR_DIMS(array), ndim * sizeof(int));
6375  memcpy(ARR_LBOUND(result), ARR_LBOUND(array), ndim * sizeof(int));
6376 
6377  if (remove)
6378  {
6379  /* Adjust the result length */
6380  ARR_DIMS(result)[0] = nresult;
6381  }
6382 
6383  /* Insert data into result array */
6384  CopyArrayEls(result,
6385  values, nulls, nresult,
6386  typlen, typbyval, typalign,
6387  false);
6388 
6389  pfree(values);
6390  pfree(nulls);
6391 
6392  return result;
6393 }
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 4657 of file arrayfuncs.c.

4659 {
4660  int bitmask;
4661  int i;
4662 
4663  /* easy if fixed-size elements and no NULLs */
4664  if (typlen > 0 && !nullbitmap)
4665  return ptr + nitems * ((Size) att_align_nominal(typlen, typalign));
4666 
4667  /* seems worth having separate loops for NULL and no-NULLs cases */
4668  if (nullbitmap)
4669  {
4670  nullbitmap += offset / 8;
4671  bitmask = 1 << (offset % 8);
4672 
4673  for (i = 0; i < nitems; i++)
4674  {
4675  if (*nullbitmap & bitmask)
4676  {
4677  ptr = att_addlength_pointer(ptr, typlen, ptr);
4678  ptr = (char *) att_align_nominal(ptr, typalign);
4679  }
4680  bitmask <<= 1;
4681  if (bitmask == 0x100)
4682  {
4683  nullbitmap++;
4684  bitmask = 1;
4685  }
4686  }
4687  }
4688  else
4689  {
4690  for (i = 0; i < nitems; i++)
4691  {
4692  ptr = att_addlength_pointer(ptr, typlen, ptr);
4693  ptr = (char *) att_align_nominal(ptr, typalign);
4694  }
4695  }
4696  return ptr;
4697 }
size_t Size
Definition: c.h:540

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

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

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

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

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

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

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

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

4590 {
4591  int bitmask;
4592 
4593  nullbitmap += offset / 8;
4594  bitmask = 1 << (offset % 8);
4595  if (isNull)
4596  *nullbitmap &= ~bitmask;
4597  else
4598  *nullbitmap |= bitmask;
4599 }

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

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

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

4832 {
4833  int src_offset,
4834  span[MAXDIM],
4835  prod[MAXDIM],
4836  dist[MAXDIM],
4837  indx[MAXDIM];
4838  char *ptr;
4839  int i,
4840  j,
4841  inc;
4842  int count = 0;
4843 
4844  mda_get_range(ndim, span, st, endp);
4845 
4846  /* Pretty easy for fixed element length without nulls ... */
4847  if (typlen > 0 && !arraynullsptr)
4848  return ArrayGetNItems(ndim, span) * att_align_nominal(typlen, typalign);
4849 
4850  /* Else gotta do it the hard way */
4851  src_offset = ArrayGetOffset(ndim, dim, lb, st);
4852  ptr = array_seek(arraydataptr, 0, arraynullsptr, src_offset,
4853  typlen, typbyval, typalign);
4854  mda_get_prod(ndim, dim, prod);
4855  mda_get_offset_values(ndim, dist, prod, span);
4856  for (i = 0; i < ndim; i++)
4857  indx[i] = 0;
4858  j = ndim - 1;
4859  do
4860  {
4861  if (dist[j])
4862  {
4863  ptr = array_seek(ptr, src_offset, arraynullsptr, dist[j],
4864  typlen, typbyval, typalign);
4865  src_offset += dist[j];
4866  }
4867  if (!array_get_isnull(arraynullsptr, src_offset))
4868  {
4869  inc = att_addlength_pointer(0, typlen, ptr);
4870  inc = att_align_nominal(inc, typalign);
4871  ptr += inc;
4872  count += inc;
4873  }
4874  src_offset++;
4875  } while ((j = mda_next_tuple(ndim, indx, span)) != -1);
4876  return count;
4877 }

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

5662 {
5663  if (array_cmp(fcinfo) < 0)
5665  else
5667 }

References array_cmp(), PG_GETARG_DATUM, and PG_RETURN_DATUM.

◆ array_unnest()

Datum array_unnest ( PG_FUNCTION_ARGS  )

Definition at line 6019 of file arrayfuncs.c.

6020 {
6021  typedef struct
6022  {
6023  array_iter iter;
6024  int nextelem;
6025  int numelems;
6026  int16 elmlen;
6027  bool elmbyval;
6028  char elmalign;
6029  } array_unnest_fctx;
6030 
6031  FuncCallContext *funcctx;
6032  array_unnest_fctx *fctx;
6033  MemoryContext oldcontext;
6034 
6035  /* stuff done only on the first call of the function */
6036  if (SRF_IS_FIRSTCALL())
6037  {
6038  AnyArrayType *arr;
6039 
6040  /* create a function context for cross-call persistence */
6041  funcctx = SRF_FIRSTCALL_INIT();
6042 
6043  /*
6044  * switch to memory context appropriate for multiple function calls
6045  */
6046  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
6047 
6048  /*
6049  * Get the array value and detoast if needed. We can't do this
6050  * earlier because if we have to detoast, we want the detoasted copy
6051  * to be in multi_call_memory_ctx, so it will go away when we're done
6052  * and not before. (If no detoast happens, we assume the originally
6053  * passed array will stick around till then.)
6054  */
6055  arr = PG_GETARG_ANY_ARRAY_P(0);
6056 
6057  /* allocate memory for user context */
6058  fctx = (array_unnest_fctx *) palloc(sizeof(array_unnest_fctx));
6059 
6060  /* initialize state */
6061  array_iter_setup(&fctx->iter, arr);
6062  fctx->nextelem = 0;
6063  fctx->numelems = ArrayGetNItems(AARR_NDIM(arr), AARR_DIMS(arr));
6064 
6065  if (VARATT_IS_EXPANDED_HEADER(arr))
6066  {
6067  /* we can just grab the type data from expanded array */
6068  fctx->elmlen = arr->xpn.typlen;
6069  fctx->elmbyval = arr->xpn.typbyval;
6070  fctx->elmalign = arr->xpn.typalign;
6071  }
6072  else
6074  &fctx->elmlen,
6075  &fctx->elmbyval,
6076  &fctx->elmalign);
6077 
6078  funcctx->user_fctx = fctx;
6079  MemoryContextSwitchTo(oldcontext);
6080  }
6081 
6082  /* stuff done on every call of the function */
6083  funcctx = SRF_PERCALL_SETUP();
6084  fctx = funcctx->user_fctx;
6085 
6086  if (fctx->nextelem < fctx->numelems)
6087  {
6088  int offset = fctx->nextelem++;
6089  Datum elem;
6090 
6091  elem = array_iter_next(&fctx->iter, &fcinfo->isnull, offset,
6092  fctx->elmlen, fctx->elmbyval, fctx->elmalign);
6093 
6094  SRF_RETURN_NEXT(funcctx, elem);
6095  }
6096  else
6097  {
6098  /* do when there is no more left */
6099  SRF_RETURN_DONE(funcctx);
6100  }
6101 }
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:299
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:303
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:305
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:301
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:323
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 6107 of file arrayfuncs.c.

6108 {
6109  Node *rawreq = (Node *) PG_GETARG_POINTER(0);
6110  Node *ret = NULL;
6111 
6112  if (IsA(rawreq, SupportRequestRows))
6113  {
6114  /* Try to estimate the number of rows returned */
6115  SupportRequestRows *req = (SupportRequestRows *) rawreq;
6116 
6117  if (is_funcclause(req->node)) /* be paranoid */
6118  {
6119  List *args = ((FuncExpr *) req->node)->args;
6120  Node *arg1;
6121 
6122  /* We can use estimated argument values here */
6124 
6125  req->rows = estimate_array_length(arg1);
6126  ret = (Node *) req;
6127  }
6128  }
6129 
6130  PG_RETURN_POINTER(ret);
6131 }
Node * estimate_expression_value(PlannerInfo *root, Node *node)
Definition: clauses.c:2290
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
static bool is_funcclause(const void *clause)
Definition: nodeFuncs.h:57
#define IsA(nodeptr, _type_)
Definition: nodes.h:624
#define linitial(l)
Definition: pg_list.h:174
int estimate_array_length(Node *arrayexpr)
Definition: selfuncs.c:2132
Definition: pg_list.h:51
Definition: nodes.h:574
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 1744 of file arrayfuncs.c.

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

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

4608 {
4609  return fetch_att(value, byval, len);
4610 }
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 4618 of file arrayfuncs.c.

4623 {
4624  int inc;
4625 
4626  if (typlen > 0)
4627  {
4628  if (typbyval)
4629  store_att_byval(dest, src, typlen);
4630  else
4631  memmove(dest, DatumGetPointer(src), typlen);
4632  inc = att_align_nominal(typlen, typalign);
4633  }
4634  else
4635  {
4636  Assert(!typbyval);
4637  inc = att_addlength_datum(0, typlen, src);
4638  memmove(dest, DatumGetPointer(src), inc);
4639  inc = att_align_nominal(inc, typalign);
4640  }
4641 
4642  return inc;
4643 }
#define store_att_byval(T, newdatum, attlen)
Definition: tupmacs.h:226

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

4352 {
4353  AnyArrayType *array1 = PG_GETARG_ANY_ARRAY_P(0);
4354  AnyArrayType *array2 = PG_GETARG_ANY_ARRAY_P(1);
4355  Oid collation = PG_GET_COLLATION();
4356  bool result;
4357 
4358  result = array_contain_compare(array1, array2, collation, true,
4359  &fcinfo->flinfo->fn_extra);
4360 
4361  /* Avoid leaking memory when handed toasted input. */
4362  AARR_FREE_IF_COPY(array1, 0);
4363  AARR_FREE_IF_COPY(array2, 1);
4364 
4365  PG_RETURN_BOOL(result);
4366 }
static bool array_contain_compare(AnyArrayType *array1, AnyArrayType *array2, Oid collation, bool matchall, void **fn_extra)
Definition: arrayfuncs.c:4172

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

4334 {
4335  AnyArrayType *array1 = PG_GETARG_ANY_ARRAY_P(0);
4336  AnyArrayType *array2 = PG_GETARG_ANY_ARRAY_P(1);
4337  Oid collation = PG_GET_COLLATION();
4338  bool result;
4339 
4340  result = array_contain_compare(array2, array1, collation, true,
4341  &fcinfo->flinfo->fn_extra);
4342 
4343  /* Avoid leaking memory when handed toasted input. */
4344  AARR_FREE_IF_COPY(array1, 0);
4345  AARR_FREE_IF_COPY(array2, 1);
4346 
4347  PG_RETURN_BOOL(result);
4348 }

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 = ARRAY_NO_LEVEL;
469 
470  for (i = 0; i < MAXDIM; ++i)
471  {
472  temp[i] = dim[i] = nelems_last[i] = 0;
473  nelems[i] = 1;
474  }
475 
476  ptr =