PostgreSQL Source Code git master
arrayfuncs.c File Reference
#include "postgres.h"
#include <ctype.h>
#include <math.h>
#include "catalog/pg_type.h"
#include "common/int.h"
#include "funcapi.h"
#include "libpq/pqformat.h"
#include "nodes/nodeFuncs.h"
#include "nodes/supportnodes.h"
#include "optimizer/optimizer.h"
#include "parser/scansup.h"
#include "port/pg_bitutils.h"
#include "utils/array.h"
#include "utils/arrayaccess.h"
#include "utils/builtins.h"
#include "utils/datum.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/selfuncs.h"
#include "utils/typcache.h"
Include dependency graph for arrayfuncs.c:

Go to the source code of this file.

Data Structures

struct  ArrayIteratorData
 
struct  generate_subscripts_fctx
 

Macros

#define ASSGN   "="
 
#define AARR_FREE_IF_COPY(array, n)
 
#define APPENDSTR(str)   (strcpy(p, (str)), p += strlen(p))
 
#define APPENDCHAR(ch)   (*p++ = (ch), *p = '\0')
 

Typedefs

typedef struct ArrayIteratorData ArrayIteratorData
 
typedef struct generate_subscripts_fctx generate_subscripts_fctx
 

Enumerations

enum  ArrayToken {
  ATOK_LEVEL_START , ATOK_LEVEL_END , ATOK_DELIM , ATOK_ELEM ,
  ATOK_ELEM_NULL , ATOK_ERROR
}
 

Functions

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

Variables

bool Array_nulls = true
 

Macro Definition Documentation

◆ AARR_FREE_IF_COPY

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

Definition at line 50 of file arrayfuncs.c.

◆ APPENDCHAR

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

◆ APPENDSTR

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

◆ ASSGN

#define ASSGN   "="

Definition at line 48 of file arrayfuncs.c.

Typedef Documentation

◆ ArrayIteratorData

◆ generate_subscripts_fctx

Enumeration Type Documentation

◆ ArrayToken

enum ArrayToken
Enumerator
ATOK_LEVEL_START 
ATOK_LEVEL_END 
ATOK_DELIM 
ATOK_ELEM 
ATOK_ELEM_NULL 
ATOK_ERROR 

Definition at line 57 of file arrayfuncs.c.

58{
ArrayToken
Definition: arrayfuncs.c:58
@ ATOK_ELEM_NULL
Definition: arrayfuncs.c:63
@ ATOK_DELIM
Definition: arrayfuncs.c:61
@ ATOK_LEVEL_END
Definition: arrayfuncs.c:60
@ ATOK_ELEM
Definition: arrayfuncs.c:62
@ ATOK_LEVEL_START
Definition: arrayfuncs.c:59
@ ATOK_ERROR
Definition: arrayfuncs.c:64

Function Documentation

◆ accumArrayResult()

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

Definition at line 5350 of file arrayfuncs.c.

5354{
5355 MemoryContext oldcontext;
5356
5357 if (astate == NULL)
5358 {
5359 /* First time through --- initialize */
5360 astate = initArrayResult(element_type, rcontext, true);
5361 }
5362 else
5363 {
5364 Assert(astate->element_type == element_type);
5365 }
5366
5367 oldcontext = MemoryContextSwitchTo(astate->mcontext);
5368
5369 /* enlarge dvalues[]/dnulls[] if needed */
5370 if (astate->nelems >= astate->alen)
5371 {
5372 astate->alen *= 2;
5373 /* give an array-related error if we go past MaxAllocSize */
5374 if (!AllocSizeIsValid(astate->alen * sizeof(Datum)))
5375 ereport(ERROR,
5376 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
5377 errmsg("array size exceeds the maximum allowed (%d)",
5378 (int) MaxAllocSize)));
5379 astate->dvalues = (Datum *)
5380 repalloc(astate->dvalues, astate->alen * sizeof(Datum));
5381 astate->dnulls = (bool *)
5382 repalloc(astate->dnulls, astate->alen * sizeof(bool));
5383 }
5384
5385 /*
5386 * Ensure pass-by-ref stuff is copied into mcontext; and detoast it too if
5387 * it's varlena. (You might think that detoasting is not needed here
5388 * because construct_md_array can detoast the array elements later.
5389 * However, we must not let construct_md_array modify the ArrayBuildState
5390 * because that would mean array_agg_finalfn damages its input, which is
5391 * verboten. Also, this way frequently saves one copying step.)
5392 */
5393 if (!disnull && !astate->typbyval)
5394 {
5395 if (astate->typlen == -1)
5396 dvalue = PointerGetDatum(PG_DETOAST_DATUM_COPY(dvalue));
5397 else
5398 dvalue = datumCopy(dvalue, astate->typbyval, astate->typlen);
5399 }
5400
5401 astate->dvalues[astate->nelems] = dvalue;
5402 astate->dnulls[astate->nelems] = disnull;
5403 astate->nelems++;
5404
5405 MemoryContextSwitchTo(oldcontext);
5406
5407 return astate;
5408}
ArrayBuildState * initArrayResult(Oid element_type, MemoryContext rcontext, bool subcontext)
Definition: arrayfuncs.c:5293
#define Assert(condition)
Definition: c.h:815
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:132
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
#define MaxAllocSize
Definition: fe_memutils.h:22
#define PG_DETOAST_DATUM_COPY(datum)
Definition: fmgr.h:242
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1541
#define AllocSizeIsValid(size)
Definition: memutils.h:42
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:327
uintptr_t Datum
Definition: postgres.h:69
bool * dnulls
Definition: array.h:191
bool typbyval
Definition: array.h:196
MemoryContext mcontext
Definition: array.h:189
int16 typlen
Definition: array.h:195
Oid element_type
Definition: array.h:194
Datum * dvalues
Definition: array.h:190

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

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

◆ accumArrayResultAny()

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

Definition at line 5827 of file arrayfuncs.c.

5831{
5832 if (astate == NULL)
5833 astate = initArrayResultAny(input_type, rcontext, true);
5834
5835 if (astate->scalarstate)
5836 (void) accumArrayResult(astate->scalarstate,
5837 dvalue, disnull,
5838 input_type, rcontext);
5839 else
5840 (void) accumArrayResultArr(astate->arraystate,
5841 dvalue, disnull,
5842 input_type, rcontext);
5843
5844 return astate;
5845}
ArrayBuildState * accumArrayResult(ArrayBuildState *astate, Datum dvalue, bool disnull, Oid element_type, MemoryContext rcontext)
Definition: arrayfuncs.c:5350
ArrayBuildStateAny * initArrayResultAny(Oid input_type, MemoryContext rcontext, bool subcontext)
Definition: arrayfuncs.c:5782
ArrayBuildStateArr * accumArrayResultArr(ArrayBuildStateArr *astate, Datum dvalue, bool disnull, Oid array_type, MemoryContext rcontext)
Definition: arrayfuncs.c:5550
ArrayBuildStateArr * arraystate
Definition: array.h:230
ArrayBuildState * scalarstate
Definition: array.h:229

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

Referenced by ExecScanSubPlan(), and ExecSetParamPlan().

◆ accumArrayResultArr()

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

Definition at line 5550 of file arrayfuncs.c.

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

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

Referenced by accumArrayResultAny(), and array_agg_array_transfn().

◆ array_bitmap_copy()

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

Definition at line 4966 of file arrayfuncs.c.

4969{
4970 int destbitmask,
4971 destbitval,
4972 srcbitmask,
4973 srcbitval;
4974
4975 Assert(destbitmap);
4976 if (nitems <= 0)
4977 return; /* don't risk fetch off end of memory */
4978 destbitmap += destoffset / 8;
4979 destbitmask = 1 << (destoffset % 8);
4980 destbitval = *destbitmap;
4981 if (srcbitmap)
4982 {
4983 srcbitmap += srcoffset / 8;
4984 srcbitmask = 1 << (srcoffset % 8);
4985 srcbitval = *srcbitmap;
4986 while (nitems-- > 0)
4987 {
4988 if (srcbitval & srcbitmask)
4989 destbitval |= destbitmask;
4990 else
4991 destbitval &= ~destbitmask;
4992 destbitmask <<= 1;
4993 if (destbitmask == 0x100)
4994 {
4995 *destbitmap++ = destbitval;
4996 destbitmask = 1;
4997 if (nitems > 0)
4998 destbitval = *destbitmap;
4999 }
5000 srcbitmask <<= 1;
5001 if (srcbitmask == 0x100)
5002 {
5003 srcbitmap++;
5004 srcbitmask = 1;
5005 if (nitems > 0)
5006 srcbitval = *srcbitmap;
5007 }
5008 }
5009 if (destbitmask != 1)
5010 *destbitmap = destbitval;
5011 }
5012 else
5013 {
5014 while (nitems-- > 0)
5015 {
5016 destbitval |= destbitmask;
5017 destbitmask <<= 1;
5018 if (destbitmask == 0x100)
5019 {
5020 *destbitmap++ = destbitval;
5021 destbitmask = 1;
5022 if (nitems > 0)
5023 destbitval = *destbitmap;
5024 }
5025 }
5026 if (destbitmask != 1)
5027 *destbitmap = destbitval;
5028 }
5029}

References Assert, and nitems.

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

◆ array_cardinality()

Datum array_cardinality ( PG_FUNCTION_ARGS  )

Definition at line 1790 of file arrayfuncs.c.

1791{
1793
1795}
#define AARR_DIMS(a)
Definition: array.h:338
#define PG_GETARG_ANY_ARRAY_P(n)
Definition: array.h:274
#define AARR_NDIM(a)
Definition: array.h:328
#define PG_RETURN_INT32(x)
Definition: fmgr.h:354

References AARR_DIMS, AARR_NDIM, ArrayGetNItems(), PG_GETARG_ANY_ARRAY_P, and PG_RETURN_INT32.

◆ array_cmp()

static int array_cmp ( FunctionCallInfo  fcinfo)
static

Definition at line 3985 of file arrayfuncs.c.

3986{
3987 LOCAL_FCINFO(locfcinfo, 2);
3990 Oid collation = PG_GET_COLLATION();
3991 int ndims1 = AARR_NDIM(array1);
3992 int ndims2 = AARR_NDIM(array2);
3993 int *dims1 = AARR_DIMS(array1);
3994 int *dims2 = AARR_DIMS(array2);
3995 int nitems1 = ArrayGetNItems(ndims1, dims1);
3996 int nitems2 = ArrayGetNItems(ndims2, dims2);
3997 Oid element_type = AARR_ELEMTYPE(array1);
3998 int result = 0;
3999 TypeCacheEntry *typentry;
4000 int typlen;
4001 bool typbyval;
4002 char typalign;
4003 int min_nitems;
4004 array_iter it1;
4005 array_iter it2;
4006 int i;
4007
4008 if (element_type != AARR_ELEMTYPE(array2))
4009 ereport(ERROR,
4010 (errcode(ERRCODE_DATATYPE_MISMATCH),
4011 errmsg("cannot compare arrays of different element types")));
4012
4013 /*
4014 * We arrange to look up the comparison function only once per series of
4015 * calls, assuming the element type doesn't change underneath us. The
4016 * typcache is used so that we have no memory leakage when being used as
4017 * an index support function.
4018 */
4019 typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
4020 if (typentry == NULL ||
4021 typentry->type_id != element_type)
4022 {
4023 typentry = lookup_type_cache(element_type,
4025 if (!OidIsValid(typentry->cmp_proc_finfo.fn_oid))
4026 ereport(ERROR,
4027 (errcode(ERRCODE_UNDEFINED_FUNCTION),
4028 errmsg("could not identify a comparison function for type %s",
4029 format_type_be(element_type))));
4030 fcinfo->flinfo->fn_extra = typentry;
4031 }
4032 typlen = typentry->typlen;
4033 typbyval = typentry->typbyval;
4034 typalign = typentry->typalign;
4035
4036 /*
4037 * apply the operator to each pair of array elements.
4038 */
4039 InitFunctionCallInfoData(*locfcinfo, &typentry->cmp_proc_finfo, 2,
4040 collation, NULL, NULL);
4041
4042 /* Loop over source data */
4043 min_nitems = Min(nitems1, nitems2);
4044 array_iter_setup(&it1, array1);
4045 array_iter_setup(&it2, array2);
4046
4047 for (i = 0; i < min_nitems; i++)
4048 {
4049 Datum elt1;
4050 Datum elt2;
4051 bool isnull1;
4052 bool isnull2;
4053 int32 cmpresult;
4054
4055 /* Get elements, checking for NULL */
4056 elt1 = array_iter_next(&it1, &isnull1, i, typlen, typbyval, typalign);
4057 elt2 = array_iter_next(&it2, &isnull2, i, typlen, typbyval, typalign);
4058
4059 /*
4060 * We consider two NULLs equal; NULL > not-NULL.
4061 */
4062 if (isnull1 && isnull2)
4063 continue;
4064 if (isnull1)
4065 {
4066 /* arg1 is greater than arg2 */
4067 result = 1;
4068 break;
4069 }
4070 if (isnull2)
4071 {
4072 /* arg1 is less than arg2 */
4073 result = -1;
4074 break;
4075 }
4076
4077 /* Compare the pair of elements */
4078 locfcinfo->args[0].value = elt1;
4079 locfcinfo->args[0].isnull = false;
4080 locfcinfo->args[1].value = elt2;
4081 locfcinfo->args[1].isnull = false;
4082 cmpresult = DatumGetInt32(FunctionCallInvoke(locfcinfo));
4083
4084 /* We don't expect comparison support functions to return null */
4085 Assert(!locfcinfo->isnull);
4086
4087 if (cmpresult == 0)
4088 continue; /* equal */
4089
4090 if (cmpresult < 0)
4091 {
4092 /* arg1 is less than arg2 */
4093 result = -1;
4094 break;
4095 }
4096 else
4097 {
4098 /* arg1 is greater than arg2 */
4099 result = 1;
4100 break;
4101 }
4102 }
4103
4104 /*
4105 * If arrays contain same data (up to end of shorter one), apply
4106 * additional rules to sort by dimensionality. The relative significance
4107 * of the different bits of information is historical; mainly we just care
4108 * that we don't say "equal" for arrays of different dimensionality.
4109 */
4110 if (result == 0)
4111 {
4112 if (nitems1 != nitems2)
4113 result = (nitems1 < nitems2) ? -1 : 1;
4114 else if (ndims1 != ndims2)
4115 result = (ndims1 < ndims2) ? -1 : 1;
4116 else
4117 {
4118 for (i = 0; i < ndims1; i++)
4119 {
4120 if (dims1[i] != dims2[i])
4121 {
4122 result = (dims1[i] < dims2[i]) ? -1 : 1;
4123 break;
4124 }
4125 }
4126 if (result == 0)
4127 {
4128 int *lbound1 = AARR_LBOUND(array1);
4129 int *lbound2 = AARR_LBOUND(array2);
4130
4131 for (i = 0; i < ndims1; i++)
4132 {
4133 if (lbound1[i] != lbound2[i])
4134 {
4135 result = (lbound1[i] < lbound2[i]) ? -1 : 1;
4136 break;
4137 }
4138 }
4139 }
4140 }
4141 }
4142
4143 /* Avoid leaking memory when handed toasted input. */
4144 AARR_FREE_IF_COPY(array1, 0);
4145 AARR_FREE_IF_COPY(array2, 1);
4146
4147 return result;
4148}
#define AARR_ELEMTYPE(a)
Definition: array.h:335
#define AARR_LBOUND(a)
Definition: array.h:341
static Datum array_iter_next(array_iter *it, bool *isnull, int i, int elmlen, bool elmbyval, char elmalign)
Definition: arrayaccess.h:81
static void array_iter_setup(array_iter *it, AnyArrayType *a)
Definition: arrayaccess.h:49
#define AARR_FREE_IF_COPY(array, n)
Definition: arrayfuncs.c:50
#define Min(x, y)
Definition: c.h:961
int32_t int32
Definition: c.h:484
#define OidIsValid(objectId)
Definition: c.h:732
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition: fmgr.h:150
#define LOCAL_FCINFO(name, nargs)
Definition: fmgr.h:110
#define FunctionCallInvoke(fcinfo)
Definition: fmgr.h:172
#define PG_GET_COLLATION()
Definition: fmgr.h:198
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:76
char typalign
Definition: pg_type.h:176
static int32 DatumGetInt32(Datum X)
Definition: postgres.h:207
unsigned int Oid
Definition: postgres_ext.h:32
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:386
#define TYPECACHE_CMP_PROC_FINFO
Definition: typcache.h:143

References AARR_DIMS, AARR_ELEMTYPE, AARR_FREE_IF_COPY, AARR_LBOUND, AARR_NDIM, array_iter_next(), array_iter_setup(), ArrayGetNItems(), Assert, TypeCacheEntry::cmp_proc_finfo, DatumGetInt32(), ereport, errcode(), errmsg(), ERROR, FunctionCallInfoBaseData::flinfo, FmgrInfo::fn_extra, FmgrInfo::fn_oid, format_type_be(), FunctionCallInvoke, i, if(), InitFunctionCallInfoData, LOCAL_FCINFO, lookup_type_cache(), Min, OidIsValid, PG_GET_COLLATION, PG_GETARG_ANY_ARRAY_P, typalign, TypeCacheEntry::typalign, TypeCacheEntry::typbyval, TypeCacheEntry::type_id, TYPECACHE_CMP_PROC_FINFO, and TypeCacheEntry::typlen.

Referenced by array_ge(), array_gt(), array_larger(), array_le(), array_lt(), array_smaller(), and btarraycmp().

◆ array_contain_compare()

static bool array_contain_compare ( AnyArrayType array1,
AnyArrayType array2,
Oid  collation,
bool  matchall,
void **  fn_extra 
)
static

Definition at line 4381 of file arrayfuncs.c.

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

References AARR_DIMS, AARR_ELEMTYPE, AARR_NDIM, array_iter_next(), array_iter_setup(), ArrayGetNItems(), DatumGetBool(), deconstruct_array(), deconstruct_expanded_array(), ExpandedArrayHeader::dnulls, ExpandedArrayHeader::dvalues, TypeCacheEntry::eq_opr_finfo, ereport, errcode(), errmsg(), ERROR, FmgrInfo::fn_oid, format_type_be(), FunctionCallInvoke, i, InitFunctionCallInfoData, j, LOCAL_FCINFO, lookup_type_cache(), ExpandedArrayHeader::nelems, OidIsValid, typalign, TypeCacheEntry::typalign, TypeCacheEntry::typbyval, TypeCacheEntry::type_id, TYPECACHE_EQ_OPR_FINFO, TypeCacheEntry::typlen, VARATT_IS_EXPANDED_HEADER, and AnyArrayType::xpn.

Referenced by arraycontained(), arraycontains(), and arrayoverlap().

◆ array_contains_nulls()

bool array_contains_nulls ( ArrayType array)

Definition at line 3767 of file arrayfuncs.c.

3768{
3769 int nelems;
3770 bits8 *bitmap;
3771 int bitmask;
3772
3773 /* Easy answer if there's no null bitmap */
3774 if (!ARR_HASNULL(array))
3775 return false;
3776
3777 nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
3778
3779 bitmap = ARR_NULLBITMAP(array);
3780
3781 /* check whole bytes of the bitmap byte-at-a-time */
3782 while (nelems >= 8)
3783 {
3784 if (*bitmap != 0xFF)
3785 return true;
3786 bitmap++;
3787 nelems -= 8;
3788 }
3789
3790 /* check last partial byte */
3791 bitmask = 1;
3792 while (nelems > 0)
3793 {
3794 if ((*bitmap & bitmask) == 0)
3795 return true;
3796 bitmask <<= 1;
3797 nelems--;
3798 }
3799
3800 return false;
3801}

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_jsonb_path_all(), get_path_all(), getWeights(), lt_q_regex(), pg_isolation_test_session_is_blocked(), pg_logical_slot_get_changes_guts(), sanity_check_array(), sanity_check_tid_array(), stats_check_arg_array(), text_to_stavalues(), width_bucket_array(), and worker_spi_launch().

◆ array_copy()

static int array_copy ( char *  destptr,
int  nitems,
char *  srcptr,
int  offset,
bits8 nullbitmap,
int  typlen,
bool  typbyval,
char  typalign 
)
static

Definition at line 4936 of file arrayfuncs.c.

4939{
4940 int numbytes;
4941
4942 numbytes = array_nelems_size(srcptr, offset, nullbitmap, nitems,
4943 typlen, typbyval, typalign);
4944 memcpy(destptr, srcptr, numbytes);
4945 return numbytes;
4946}
static int array_nelems_size(char *ptr, int offset, bits8 *nullbitmap, int nitems, int typlen, bool typbyval, char typalign)
Definition: arrayfuncs.c:4914

References array_nelems_size(), nitems, and typalign.

Referenced by array_extract_slice(), and array_insert_slice().

◆ array_create_iterator()

ArrayIterator array_create_iterator ( ArrayType arr,
int  slice_ndim,
ArrayMetaState mstate 
)

Definition at line 4597 of file arrayfuncs.c.

4598{
4599 ArrayIterator iterator = palloc0(sizeof(ArrayIteratorData));
4600
4601 /*
4602 * Sanity-check inputs --- caller should have got this right already
4603 */
4604 Assert(PointerIsValid(arr));
4605 if (slice_ndim < 0 || slice_ndim > ARR_NDIM(arr))
4606 elog(ERROR, "invalid arguments to array_create_iterator");
4607
4608 /*
4609 * Remember basic info about the array and its element type
4610 */
4611 iterator->arr = arr;
4612 iterator->nullbitmap = ARR_NULLBITMAP(arr);
4613 iterator->nitems = ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr));
4614
4615 if (mstate != NULL)
4616 {
4617 Assert(mstate->element_type == ARR_ELEMTYPE(arr));
4618
4619 iterator->typlen = mstate->typlen;
4620 iterator->typbyval = mstate->typbyval;
4621 iterator->typalign = mstate->typalign;
4622 }
4623 else
4625 &iterator->typlen,
4626 &iterator->typbyval,
4627 &iterator->typalign);
4628
4629 /*
4630 * Remember the slicing parameters.
4631 */
4632 iterator->slice_ndim = slice_ndim;
4633
4634 if (slice_ndim > 0)
4635 {
4636 /*
4637 * Get pointers into the array's dims and lbound arrays to represent
4638 * the dims/lbound arrays of a slice. These are the same as the
4639 * rightmost N dimensions of the array.
4640 */
4641 iterator->slice_dims = ARR_DIMS(arr) + ARR_NDIM(arr) - slice_ndim;
4642 iterator->slice_lbound = ARR_LBOUND(arr) + ARR_NDIM(arr) - slice_ndim;
4643
4644 /*
4645 * Compute number of elements in a slice.
4646 */
4647 iterator->slice_len = ArrayGetNItems(slice_ndim,
4648 iterator->slice_dims);
4649
4650 /*
4651 * Create workspace for building sub-arrays.
4652 */
4653 iterator->slice_values = (Datum *)
4654 palloc(iterator->slice_len * sizeof(Datum));
4655 iterator->slice_nulls = (bool *)
4656 palloc(iterator->slice_len * sizeof(bool));
4657 }
4658
4659 /*
4660 * Initialize our data pointer and linear element number. These will
4661 * advance through the array during array_iterate().
4662 */
4663 iterator->data_ptr = ARR_DATA_PTR(arr);
4664 iterator->current_item = 0;
4665
4666 return iterator;
4667}
#define ARR_ELEMTYPE(a)
Definition: array.h:292
#define PointerIsValid(pointer)
Definition: c.h:720
#define elog(elevel,...)
Definition: elog.h:225
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2271
void * palloc0(Size size)
Definition: mcxt.c:1347
ArrayType * arr
Definition: arrayfuncs.c:71
bool * slice_nulls
Definition: arrayfuncs.c:84
Datum * slice_values
Definition: arrayfuncs.c:83
bits8 * nullbitmap
Definition: arrayfuncs.c:72
char typalign
Definition: array.h:241
int16 typlen
Definition: array.h:239
Oid element_type
Definition: array.h:238
bool typbyval
Definition: array.h:240

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

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

◆ array_dims()

Datum array_dims ( PG_FUNCTION_ARGS  )

Definition at line 1668 of file arrayfuncs.c.

1669{
1671 char *p;
1672 int i;
1673 int *dimv,
1674 *lb;
1675
1676 /*
1677 * 33 since we assume 15 digits per number + ':' +'[]'
1678 *
1679 * +1 for trailing null
1680 */
1681 char buf[MAXDIM * 33 + 1];
1682
1683 /* Sanity check: does it look like an array at all? */
1684 if (AARR_NDIM(v) <= 0 || AARR_NDIM(v) > MAXDIM)
1686
1687 dimv = AARR_DIMS(v);
1688 lb = AARR_LBOUND(v);
1689
1690 p = buf;
1691 for (i = 0; i < AARR_NDIM(v); i++)
1692 {
1693 sprintf(p, "[%d:%d]", lb[i], dimv[i] + lb[i] - 1);
1694 p += strlen(p);
1695 }
1696
1698}
#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:72
#define sprintf
Definition: port.h:240
text * cstring_to_text(const char *s)
Definition: varlena.c:184

References AARR_DIMS, AARR_LBOUND, AARR_NDIM, buf, cstring_to_text(), i, MAXDIM, PG_GETARG_ANY_ARRAY_P, PG_RETURN_NULL, PG_RETURN_TEXT_P, and sprintf.

◆ array_eq()

Datum array_eq ( PG_FUNCTION_ARGS  )

Definition at line 3814 of file arrayfuncs.c.

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

References AARR_DIMS, AARR_ELEMTYPE, AARR_FREE_IF_COPY, AARR_LBOUND, AARR_NDIM, array_iter_next(), array_iter_setup(), ArrayGetNItems(), DatumGetBool(), TypeCacheEntry::eq_opr_finfo, ereport, errcode(), errmsg(), ERROR, FmgrInfo::fn_oid, format_type_be(), FunctionCallInvoke, i, if(), InitFunctionCallInfoData, LOCAL_FCINFO, lookup_type_cache(), nitems, OidIsValid, PG_GET_COLLATION, PG_GETARG_ANY_ARRAY_P, PG_RETURN_BOOL, typalign, TypeCacheEntry::typalign, TypeCacheEntry::typbyval, TypeCacheEntry::type_id, TYPECACHE_EQ_OPR_FINFO, and TypeCacheEntry::typlen.

Referenced by array_ne().

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

5108{
5109 char *destdataptr = ARR_DATA_PTR(newarray);
5110 bits8 *destnullsptr = ARR_NULLBITMAP(newarray);
5111 char *srcdataptr;
5112 int src_offset,
5113 dest_offset,
5114 prod[MAXDIM],
5115 span[MAXDIM],
5116 dist[MAXDIM],
5117 indx[MAXDIM];
5118 int i,
5119 j,
5120 inc;
5121
5122 src_offset = ArrayGetOffset(ndim, dim, lb, st);
5123 srcdataptr = array_seek(arraydataptr, 0, arraynullsptr, src_offset,
5124 typlen, typbyval, typalign);
5125 mda_get_prod(ndim, dim, prod);
5126 mda_get_range(ndim, span, st, endp);
5127 mda_get_offset_values(ndim, dist, prod, span);
5128 for (i = 0; i < ndim; i++)
5129 indx[i] = 0;
5130 dest_offset = 0;
5131 j = ndim - 1;
5132 do
5133 {
5134 if (dist[j])
5135 {
5136 /* skip unwanted elements */
5137 srcdataptr = array_seek(srcdataptr, src_offset, arraynullsptr,
5138 dist[j],
5139 typlen, typbyval, typalign);
5140 src_offset += dist[j];
5141 }
5142 inc = array_copy(destdataptr, 1,
5143 srcdataptr, src_offset, arraynullsptr,
5144 typlen, typbyval, typalign);
5145 if (destnullsptr)
5146 array_bitmap_copy(destnullsptr, dest_offset,
5147 arraynullsptr, src_offset,
5148 1);
5149 destdataptr += inc;
5150 srcdataptr += inc;
5151 src_offset++;
5152 dest_offset++;
5153 } while ((j = mda_next_tuple(ndim, indx, span)) != -1);
5154}
static int array_copy(char *destptr, int nitems, char *srcptr, int offset, bits8 *nullbitmap, int typlen, bool typbyval, char typalign)
Definition: arrayfuncs.c:4936
static char * array_seek(char *ptr, int offset, bits8 *nullbitmap, int nitems, int typlen, bool typbyval, char typalign)
Definition: arrayfuncs.c:4866
void mda_get_offset_values(int n, int *dist, const int *prod, const int *span)
Definition: arrayutils.c:183
int ArrayGetOffset(int n, const int *dim, const int *lb, const int *indx)
Definition: arrayutils.c:32
void mda_get_range(int n, int *span, const int *st, const int *endp)
Definition: arrayutils.c:153
void mda_get_prod(int n, const int *range, int *prod)
Definition: arrayutils.c:167
int mda_next_tuple(int n, int *curr, const int *span)
Definition: arrayutils.c:208

References ARR_DATA_PTR, ARR_NULLBITMAP, array_bitmap_copy(), array_copy(), array_seek(), ArrayGetOffset(), i, j, MAXDIM, mda_get_offset_values(), mda_get_prod(), mda_get_range(), mda_next_tuple(), and typalign.

Referenced by array_get_slice().

◆ array_fill()

Datum array_fill ( PG_FUNCTION_ARGS  )

Definition at line 6031 of file arrayfuncs.c.

6032{
6033 ArrayType *dims;
6034 ArrayType *result;
6035 Oid elmtype;
6036 Datum value;
6037 bool isnull;
6038
6039 if (PG_ARGISNULL(1))
6040 ereport(ERROR,
6041 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
6042 errmsg("dimension array or low bound array cannot be null")));
6043
6044 dims = PG_GETARG_ARRAYTYPE_P(1);
6045
6046 if (!PG_ARGISNULL(0))
6047 {
6049 isnull = false;
6050 }
6051 else
6052 {
6053 value = 0;
6054 isnull = true;
6055 }
6056
6057 elmtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
6058 if (!OidIsValid(elmtype))
6059 elog(ERROR, "could not determine data type of input");
6060
6061 result = array_fill_internal(dims, NULL, value, isnull, elmtype, fcinfo);
6062 PG_RETURN_ARRAYTYPE_P(result);
6063}
#define PG_GETARG_ARRAYTYPE_P(n)
Definition: array.h:263
#define PG_RETURN_ARRAYTYPE_P(x)
Definition: array.h:265
static ArrayType * array_fill_internal(ArrayType *dims, ArrayType *lbs, Datum value, bool isnull, Oid elmtype, FunctionCallInfo fcinfo)
Definition: arrayfuncs.c:6083
Oid get_fn_expr_argtype(FmgrInfo *flinfo, int argnum)
Definition: fmgr.c:1910
#define PG_ARGISNULL(n)
Definition: fmgr.h:209
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:268
static struct @162 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 6083 of file arrayfuncs.c.

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

References AllocSizeIsValid, ARR_DATA_PTR, ARR_DIMS, ARR_NDIM, ARR_OVERHEAD_NONULLS, ARR_OVERHEAD_WITHNULLS, array_contains_nulls(), ArrayCastAndSet(), ArrayCheckBounds(), ArrayGetNItems(), Assert, att_addlength_datum, att_align_nominal, construct_empty_array(), create_array_envelope(), ArrayMetaState::element_type, ereport, errcode(), errdetail(), errmsg(), ERROR, FunctionCallInfoBaseData::flinfo, FmgrInfo::fn_extra, FmgrInfo::fn_mcxt, get_typlenbyvalalign(), i, if(), InvalidOid, MaxAllocSize, MAXDIM, MemoryContextAlloc(), nitems, PG_DETOAST_DATUM, PointerGetDatum(), ArrayMetaState::typalign, ArrayMetaState::typbyval, ArrayMetaState::typlen, and value.

Referenced by array_fill(), and array_fill_with_lower_bounds().

◆ array_fill_with_lower_bounds()

Datum array_fill_with_lower_bounds ( PG_FUNCTION_ARGS  )

Definition at line 5990 of file arrayfuncs.c.

5991{
5992 ArrayType *dims;
5993 ArrayType *lbs;
5994 ArrayType *result;
5995 Oid elmtype;
5996 Datum value;
5997 bool isnull;
5998
5999 if (PG_ARGISNULL(1) || PG_ARGISNULL(2))
6000 ereport(ERROR,
6001 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
6002 errmsg("dimension array or low bound array cannot be null")));
6003
6004 dims = PG_GETARG_ARRAYTYPE_P(1);
6005 lbs = PG_GETARG_ARRAYTYPE_P(2);
6006
6007 if (!PG_ARGISNULL(0))
6008 {
6010 isnull = false;
6011 }
6012 else
6013 {
6014 value = 0;
6015 isnull = true;
6016 }
6017
6018 elmtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
6019 if (!OidIsValid(elmtype))
6020 elog(ERROR, "could not determine data type of input");
6021
6022 result = array_fill_internal(dims, lbs, value, isnull, elmtype, fcinfo);
6023 PG_RETURN_ARRAYTYPE_P(result);
6024}

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

4760{
4761 if (iterator->slice_ndim > 0)
4762 {
4763 pfree(iterator->slice_values);
4764 pfree(iterator->slice_nulls);
4765 }
4766 pfree(iterator);
4767}

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

3968{
3969 PG_RETURN_BOOL(array_cmp(fcinfo) >= 0);
3970}
static int array_cmp(FunctionCallInfo fcinfo)
Definition: arrayfuncs.c:3985

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

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

References ARR_DATA_PTR, ARR_DIMS, ARR_LBOUND, ARR_NDIM, ARR_NULLBITMAP, array_get_element_expanded(), array_get_isnull(), array_seek(), ArrayCast(), ArrayGetOffset(), DatumGetArrayTypeP, DatumGetPointer(), i, MAXDIM, and VARATT_IS_EXTERNAL_EXPANDED.

Referenced by array_ref(), array_subscript_fetch(), array_subscript_fetch_old(), ATExecAlterColumnType(), and RelationBuildTupleDesc().

◆ array_get_element_expanded()

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

Definition at line 1921 of file arrayfuncs.c.

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

References ArrayGetOffset(), Assert, DatumGetEOHP(), deconstruct_expanded_array(), ExpandedArrayHeader::dims, ExpandedArrayHeader::dnulls, ExpandedArrayHeader::dvalues, EA_MAGIC, ExpandedArrayHeader::ea_magic, i, ExpandedArrayHeader::lbound, MAXDIM, ExpandedArrayHeader::ndims, ExpandedArrayHeader::typalign, ExpandedArrayHeader::typbyval, and ExpandedArrayHeader::typlen.

Referenced by array_get_element().

◆ array_get_isnull()

static bool array_get_isnull ( const bits8 nullbitmap,
int  offset 
)
static

Definition at line 4781 of file arrayfuncs.c.

4782{
4783 if (nullbitmap == NULL)
4784 return false; /* assume not null */
4785 if (nullbitmap[offset / 8] & (1 << (offset % 8)))
4786 return false; /* not null */
4787 return true;
4788}

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

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

References ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_LBOUND, ARR_NDIM, ARR_NULLBITMAP, ARR_OVERHEAD_NONULLS, ARR_OVERHEAD_WITHNULLS, array_extract_slice(), array_slice_size(), ArrayGetNItems(), construct_empty_array(), ArrayType::dataoffset, DatumGetArrayTypeP, DatumGetPointer(), ArrayType::elemtype, ereport, errcode(), errmsg(), ERROR, i, InvalidOid, MAXDIM, mda_get_range(), ArrayType::ndim, palloc0(), PointerGetDatum(), and SET_VARSIZE.

Referenced by array_subscript_fetch_old_slice(), array_subscript_fetch_slice(), and trim_array().

◆ array_gt()

Datum array_gt ( PG_FUNCTION_ARGS  )

Definition at line 3955 of file arrayfuncs.c.

3956{
3957 PG_RETURN_BOOL(array_cmp(fcinfo) > 0);
3958}

References array_cmp(), and PG_RETURN_BOOL.

◆ array_in()

Datum array_in ( PG_FUNCTION_ARGS  )

Definition at line 179 of file arrayfuncs.c.

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

References AllocSizeIsValid, ARR_DIMS, ARR_LBOUND, ARR_OVERHEAD_NONULLS, ARR_OVERHEAD_WITHNULLS, ASSGN, att_addlength_datum, att_align_nominal, construct_empty_array(), CopyArrayEls(), ArrayType::dataoffset, ArrayMetaState::element_type, ArrayType::elemtype, ereturn, errcode(), errdetail(), errmsg(), fmgr_info_cxt(), FmgrInfo::fn_mcxt, get_type_io_data(), i, if(), IOFunc_input, MaxAllocSize, MAXDIM, MemoryContextAlloc(), ArrayType::ndim, nitems, palloc0(), pfree(), PG_DETOAST_DATUM, PG_GETARG_CSTRING, PG_GETARG_INT32, PG_GETARG_OID, PG_RETURN_ARRAYTYPE_P, PointerGetDatum(), ArrayMetaState::proc, ReadArrayDimensions(), ReadArrayStr(), scanner_isspace(), SET_VARSIZE, typalign, ArrayMetaState::typalign, ArrayMetaState::typbyval, ArrayMetaState::typdelim, ArrayMetaState::typiofunc, ArrayMetaState::typioparam, ArrayMetaState::typlen, and values.

Referenced by extract_variadic_args(), and text_to_stavalues().

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

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

References ARR_DATA_PTR, ARR_DIMS, ARR_NDIM, ARR_NULLBITMAP, array_bitmap_copy(), array_copy(), array_seek(), ArrayGetNItems(), ArrayGetOffset(), i, j, MAXDIM, mda_get_offset_values(), mda_get_prod(), mda_get_range(), mda_next_tuple(), and typalign.

Referenced by array_set_slice().

◆ array_iterate()

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

Definition at line 4676 of file arrayfuncs.c.

4677{
4678 /* Done if we have reached the end of the array */
4679 if (iterator->current_item >= iterator->nitems)
4680 return false;
4681
4682 if (iterator->slice_ndim == 0)
4683 {
4684 /*
4685 * Scalar case: return one element.
4686 */
4687 if (array_get_isnull(iterator->nullbitmap, iterator->current_item++))
4688 {
4689 *isnull = true;
4690 *value = (Datum) 0;
4691 }
4692 else
4693 {
4694 /* non-NULL, so fetch the individual Datum to return */
4695 char *p = iterator->data_ptr;
4696
4697 *isnull = false;
4698 *value = fetch_att(p, iterator->typbyval, iterator->typlen);
4699
4700 /* Move our data pointer forward to the next element */
4701 p = att_addlength_pointer(p, iterator->typlen, p);
4702 p = (char *) att_align_nominal(p, iterator->typalign);
4703 iterator->data_ptr = p;
4704 }
4705 }
4706 else
4707 {
4708 /*
4709 * Slice case: build and return an array of the requested size.
4710 */
4711 ArrayType *result;
4712 Datum *values = iterator->slice_values;
4713 bool *nulls = iterator->slice_nulls;
4714 char *p = iterator->data_ptr;
4715 int i;
4716
4717 for (i = 0; i < iterator->slice_len; i++)
4718 {
4719 if (array_get_isnull(iterator->nullbitmap,
4720 iterator->current_item++))
4721 {
4722 nulls[i] = true;
4723 values[i] = (Datum) 0;
4724 }
4725 else
4726 {
4727 nulls[i] = false;
4728 values[i] = fetch_att(p, iterator->typbyval, iterator->typlen);
4729
4730 /* Move our data pointer forward to the next element */
4731 p = att_addlength_pointer(p, iterator->typlen, p);
4732 p = (char *) att_align_nominal(p, iterator->typalign);
4733 }
4734 }
4735
4736 iterator->data_ptr = p;
4737
4738 result = construct_md_array(values,
4739 nulls,
4740 iterator->slice_ndim,
4741 iterator->slice_dims,
4742 iterator->slice_lbound,
4743 ARR_ELEMTYPE(iterator->arr),
4744 iterator->typlen,
4745 iterator->typbyval,
4746 iterator->typalign);
4747
4748 *isnull = false;
4749 *value = PointerGetDatum(result);
4750 }
4751
4752 return true;
4753}
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:3494
#define att_addlength_pointer(cur_offset, attlen, attptr)
Definition: tupmacs.h:185
static Datum fetch_att(const void *T, bool attbyval, int attlen)
Definition: tupmacs.h:53

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

5886{
5887 if (array_cmp(fcinfo) > 0)
5889 else
5891}
#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 3961 of file arrayfuncs.c.

3962{
3963 PG_RETURN_BOOL(array_cmp(fcinfo) <= 0);
3964}

References array_cmp(), and PG_RETURN_BOOL.

◆ array_length()

Datum array_length ( PG_FUNCTION_ARGS  )

Definition at line 1763 of file arrayfuncs.c.

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

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

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

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

3950{
3951 PG_RETURN_BOOL(array_cmp(fcinfo) < 0);
3952}

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

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

References AARR_DIMS, AARR_ELEMTYPE, AARR_LBOUND, AARR_NDIM, AllocSizeIsValid, ARR_DIMS, ARR_LBOUND, ARR_OVERHEAD_NONULLS, ARR_OVERHEAD_WITHNULLS, array_iter_next(), array_iter_setup(), ArrayGetNItems(), att_addlength_datum, att_align_nominal, construct_empty_array(), CopyArrayEls(), ArrayType::dataoffset, DatumGetAnyArrayP(), ArrayMetaState::element_type, ArrayType::elemtype, ereport, errcode(), errmsg(), ERROR, ExecEvalExpr(), get_typlenbyvalalign(), i, ExprState::innermost_casenull, ExprState::innermost_caseval, ArrayMapState::inp_extra, MaxAllocSize, ArrayType::ndim, nitems, palloc(), palloc0(), pfree(), PG_DETOAST_DATUM, PointerGetDatum(), ArrayMapState::ret_extra, SET_VARSIZE, typalign, ArrayMetaState::typalign, ArrayMetaState::typbyval, ArrayMetaState::typlen, and values.

Referenced by ExecEvalArrayCoerce().

◆ array_ndims()

Datum array_ndims ( PG_FUNCTION_ARGS  )

Definition at line 1652 of file arrayfuncs.c.

1653{
1655
1656 /* Sanity check: does it look like an array at all? */
1657 if (AARR_NDIM(v) <= 0 || AARR_NDIM(v) > MAXDIM)
1659
1661}

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

3944{
3946}
Datum array_eq(PG_FUNCTION_ARGS)
Definition: arrayfuncs.c:3814

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

4916{
4917 return array_seek(ptr, offset, nullbitmap, nitems,
4918 typlen, typbyval, typalign) - ptr;
4919}

References array_seek(), nitems, and typalign.

Referenced by array_copy(), and array_set_slice().

◆ array_out()

Datum array_out ( PG_FUNCTION_ARGS  )

Definition at line 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 scanner_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:1683
#define PG_RETURN_CSTRING(x)
Definition: fmgr.h:362
@ IOFunc_output
Definition: lsyscache.h:36
char * pstrdup(const char *in)
Definition: mcxt.c:1696
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36

References AARR_DIMS, AARR_ELEMTYPE, AARR_LBOUND, AARR_NDIM, APPENDCHAR, APPENDSTR, array_iter_next(), array_iter_setup(), ArrayGetNItems(), Assert, ASSGN, ArrayMetaState::element_type, fmgr_info_cxt(), FmgrInfo::fn_mcxt, get_type_io_data(), i, if(), IOFunc_output, j, MAXDIM, MemoryContextAlloc(), nitems, OutputFunctionCall(), palloc(), pfree(), PG_GETARG_ANY_ARRAY_P, PG_RETURN_CSTRING, pg_strcasecmp(), ArrayMetaState::proc, pstrdup(), scanner_isspace(), sprintf, typalign, ArrayMetaState::typalign, ArrayMetaState::typbyval, ArrayMetaState::typdelim, ArrayMetaState::typiofunc, ArrayMetaState::typioparam, ArrayMetaState::typlen, and values.

Referenced by anyarray_out(), and anycompatiblearray_out().

◆ array_recv()

Datum array_recv ( PG_FUNCTION_ARGS  )

Definition at line 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));
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:125
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
char * format_type_extended(Oid type_oid, int32 typemod, bits16 flags)
Definition: format_type.c:112
@ IOFunc_receive
Definition: lsyscache.h:37
unsigned int pq_getmsgint(StringInfo msg, int b)
Definition: pqformat.c:415
StringInfoData * StringInfo
Definition: stringinfo.h:54
#define FirstGenbkiObjectId
Definition: transam.h:195

References ARR_DIMS, ARR_LBOUND, ARR_OVERHEAD_NONULLS, ARR_OVERHEAD_WITHNULLS, ArrayCheckBounds(), ArrayGetNItems(), buf, construct_empty_array(), CopyArrayEls(), ArrayType::dataoffset, ArrayMetaState::element_type, ArrayType::elemtype, ereport, errcode(), errmsg(), ERROR, FirstGenbkiObjectId, fmgr_info_cxt(), FmgrInfo::fn_mcxt, FORMAT_TYPE_ALLOW_INVALID, format_type_be(), format_type_extended(), get_type_io_data(), i, if(), IOFunc_receive, MAXDIM, MemoryContextAlloc(), ArrayType::ndim, nitems, OidIsValid, palloc(), palloc0(), pfree(), PG_GETARG_INT32, PG_GETARG_OID, PG_GETARG_POINTER, PG_RETURN_ARRAYTYPE_P, pq_getmsgint(), ArrayMetaState::proc, ReadArrayBinary(), SET_VARSIZE, typalign, ArrayMetaState::typalign, ArrayMetaState::typbyval, ArrayMetaState::typdelim, ArrayMetaState::typiofunc, ArrayMetaState::typioparam, and ArrayMetaState::typlen.

Referenced by int2vectorrecv(), and oidvectorrecv().

◆ array_ref()

Datum array_ref ( ArrayType array,
int  nSubscripts,
int *  indx,
int  arraytyplen,
int  elmlen,
bool  elmbyval,
char  elmalign,
bool *  isNull 
)

Definition at line 3146 of file arrayfuncs.c.

3149{
3150 return array_get_element(PointerGetDatum(array), nSubscripts, indx,
3151 arraytyplen, elmlen, elmbyval, elmalign,
3152 isNull);
3153}
Datum array_get_element(Datum arraydatum, int nSubscripts, int *indx, int arraytyplen, int elmlen, bool elmbyval, char elmalign, bool *isNull)
Definition: arrayfuncs.c:1820

References array_get_element(), and PointerGetDatum().

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

◆ array_remove()

Datum array_remove ( PG_FUNCTION_ARGS  )

Definition at line 6637 of file arrayfuncs.c.

6638{
6639 ArrayType *array;
6640 Datum search = PG_GETARG_DATUM(1);
6641 bool search_isnull = PG_ARGISNULL(1);
6642
6643 if (PG_ARGISNULL(0))
6645 array = PG_GETARG_ARRAYTYPE_P(0);
6646
6647 array = array_replace_internal(array,
6648 search, search_isnull,
6649 (Datum) 0, true,
6650 true, PG_GET_COLLATION(),
6651 fcinfo);
6652 PG_RETURN_ARRAYTYPE_P(array);
6653}
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:6379

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

6660{
6661 ArrayType *array;
6662 Datum search = PG_GETARG_DATUM(1);
6663 bool search_isnull = PG_ARGISNULL(1);
6664 Datum replace = PG_GETARG_DATUM(2);
6665 bool replace_isnull = PG_ARGISNULL(2);
6666
6667 if (PG_ARGISNULL(0))
6669 array = PG_GETARG_ARRAYTYPE_P(0);
6670
6671 array = array_replace_internal(array,
6672 search, search_isnull,
6673 replace, replace_isnull,
6674 false, PG_GET_COLLATION(),
6675 fcinfo);
6676 PG_RETURN_ARRAYTYPE_P(array);
6677}

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

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

References AllocSizeIsValid, ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_LBOUND, ARR_NDIM, ARR_NULLBITMAP, ARR_OVERHEAD_NONULLS, ARR_OVERHEAD_WITHNULLS, ArrayGetNItems(), att_addlength_datum, att_align_nominal, construct_empty_array(), CopyArrayEls(), ArrayType::dataoffset, DatumGetBool(), ArrayType::elemtype, TypeCacheEntry::eq_opr_finfo, ereport, errcode(), errmsg(), ERROR, fetch_att(), FunctionCallInfoBaseData::flinfo, FmgrInfo::fn_extra, FmgrInfo::fn_oid, format_type_be(), FunctionCallInvoke, i, if(), InitFunctionCallInfoData, LOCAL_FCINFO, lookup_type_cache(), MaxAllocSize, ArrayType::ndim, nitems, OidIsValid, palloc(), palloc0(), pfree(), PG_DETOAST_DATUM, PointerGetDatum(), SET_VARSIZE, skip, typalign, TypeCacheEntry::typalign, TypeCacheEntry::typbyval, TypeCacheEntry::type_id, TYPECACHE_EQ_OPR_FINFO, TypeCacheEntry::typlen, and values.

Referenced by array_remove(), and array_replace().

◆ array_seek()

static char * array_seek ( char *  ptr,
int  offset,
bits8 nullbitmap,
int  nitems,
int  typlen,
bool  typbyval,
char  typalign 
)
static

Definition at line 4866 of file arrayfuncs.c.

4868{
4869 int bitmask;
4870 int i;
4871
4872 /* easy if fixed-size elements and no NULLs */
4873 if (typlen > 0 && !nullbitmap)
4874 return ptr + nitems * ((Size) att_align_nominal(typlen, typalign));
4875
4876 /* seems worth having separate loops for NULL and no-NULLs cases */
4877 if (nullbitmap)
4878 {
4879 nullbitmap += offset / 8;
4880 bitmask = 1 << (offset % 8);
4881
4882 for (i = 0; i < nitems; i++)
4883 {
4884 if (*nullbitmap & bitmask)
4885 {
4886 ptr = att_addlength_pointer(ptr, typlen, ptr);
4887 ptr = (char *) att_align_nominal(ptr, typalign);
4888 }
4889 bitmask <<= 1;
4890 if (bitmask == 0x100)
4891 {
4892 nullbitmap++;
4893 bitmask = 1;
4894 }
4895 }
4896 }
4897 else
4898 {
4899 for (i = 0; i < nitems; i++)
4900 {
4901 ptr = att_addlength_pointer(ptr, typlen, ptr);
4902 ptr = (char *) att_align_nominal(ptr, typalign);
4903 }
4904 }
4905 return ptr;
4906}
size_t Size
Definition: c.h:562

References att_addlength_pointer, att_align_nominal, i, nitems, and typalign.

Referenced by array_extract_slice(), array_get_element(), array_insert_slice(), array_nelems_size(), array_set_element(), and array_slice_size().

◆ array_send()

Datum array_send ( PG_FUNCTION_ARGS  )

Definition at line 1548 of file arrayfuncs.c.

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

References AARR_DIMS, AARR_ELEMTYPE, AARR_HASNULL, AARR_LBOUND, AARR_NDIM, array_iter_next(), array_iter_setup(), ArrayGetNItems(), buf, ArrayMetaState::element_type, ereport, errcode(), errmsg(), ERROR, fmgr_info_cxt(), FmgrInfo::fn_mcxt, format_type_be(), get_type_io_data(), i, if(), IOFunc_send, MemoryContextAlloc(), nitems, OidIsValid, pfree(), PG_GETARG_ANY_ARRAY_P, PG_RETURN_BYTEA_P, pq_begintypsend(), pq_endtypsend(), pq_sendbytes(), pq_sendint32(), ArrayMetaState::proc, SendFunctionCall(), typalign, ArrayMetaState::typalign, ArrayMetaState::typbyval, ArrayMetaState::typdelim, ArrayMetaState::typiofunc, ArrayMetaState::typioparam, ArrayMetaState::typlen, VARDATA, VARHDRSZ, and VARSIZE.

Referenced by anyarray_send(), anycompatiblearray_send(), int2vectorsend(), and oidvectorsend().

◆ array_set()

ArrayType * array_set ( ArrayType array,
int  nSubscripts,
int *  indx,
Datum  dataValue,
bool  isNull,
int  arraytyplen,
int  elmlen,
bool  elmbyval,
char  elmalign 
)

Definition at line 3163 of file arrayfuncs.c.

3166{
3168 nSubscripts, indx,
3169 dataValue, isNull,
3170 arraytyplen,
3171 elmlen, elmbyval, elmalign));
3172}
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:2201

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

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

References ARR_DATA_OFFSET, ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_HASNULL, ARR_LBOUND, ARR_NDIM, ARR_NULLBITMAP, ARR_OVERHEAD_NONULLS, ARR_OVERHEAD_WITHNULLS, ARR_SIZE, array_bitmap_copy(), array_get_isnull(), array_seek(), array_set_element_expanded(), array_set_isnull(), ArrayCastAndSet(), ArrayCheckBounds(), ArrayGetNItems(), ArrayGetOffset(), att_addlength_datum, att_addlength_pointer, att_align_nominal, construct_md_array(), ArrayType::dataoffset, DatumGetArrayTypeP, DatumGetPointer(), ArrayType::elemtype, ereport, errcode(), errmsg(), ERROR, i, MaxArraySize, MAXDIM, ArrayType::ndim, palloc(), palloc0(), pg_add_s32_overflow(), PG_DETOAST_DATUM, pg_sub_s32_overflow(), PointerGetDatum(), SET_VARSIZE, and VARATT_IS_EXTERNAL_EXPANDED.

Referenced by array_append(), array_prepend(), array_set(), and array_subscript_assign().

◆ array_set_element_expanded()

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

Definition at line 2501 of file arrayfuncs.c.

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

References ArrayCheckBounds(), ArrayGetNItems(), ArrayGetOffset(), Assert, datumCopy(), DatumGetExpandedArray(), DatumGetPointer(), deconstruct_expanded_array(), ExpandedArrayHeader::dims, ExpandedArrayHeader::dnulls, ExpandedArrayHeader::dvalues, ExpandedArrayHeader::dvalueslen, ExpandedObjectHeader::eoh_context, EOHPGetRWDatum(), ereport, errcode(), errmsg(), ERROR, ExpandedArrayHeader::fendptr, ExpandedArrayHeader::flat_size, ExpandedArrayHeader::fvalue, ExpandedArrayHeader::hdr, i, ExpandedArrayHeader::lbound, Max, MaxArraySize, MAXDIM, MemoryContextAllocZero(), MemoryContextSwitchTo(), ExpandedArrayHeader::ndims, ExpandedArrayHeader::nelems, pfree(), pg_add_s32_overflow(), pg_sub_s32_overflow(), repalloc(), ExpandedArrayHeader::typalign, ExpandedArrayHeader::typbyval, and ExpandedArrayHeader::typlen.

Referenced by array_set_element().

◆ array_set_isnull()

static void array_set_isnull ( bits8 nullbitmap,
int  offset,
bool  isNull 
)
static

Definition at line 4798 of file arrayfuncs.c.

4799{
4800 int bitmask;
4801
4802 nullbitmap += offset / 8;
4803 bitmask = 1 << (offset % 8);
4804 if (isNull)
4805 *nullbitmap &= ~bitmask;
4806 else
4807 *nullbitmap |= bitmask;
4808}

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

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

References ARR_DATA_OFFSET, ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_HASNULL, ARR_LBOUND, ARR_NDIM, ARR_NULLBITMAP, ARR_OVERHEAD_NONULLS, ARR_OVERHEAD_WITHNULLS, ARR_SIZE, array_bitmap_copy(), array_insert_slice(), array_nelems_size(), array_slice_size(), ArrayCheckBounds(), ArrayGetNItems(), Assert, construct_md_array(), ArrayType::dataoffset, DatumGetArrayTypeP, deconstruct_array(), ArrayType::elemtype, ereport, errcode(), errdetail(), errmsg(), ERROR, i, Max, MaxArraySize, MAXDIM, mda_get_range(), Min, ArrayType::ndim, nitems, palloc0(), pg_add_s32_overflow(), pg_sub_s32_overflow(), PointerGetDatum(), and SET_VARSIZE.

Referenced by array_subscript_assign_slice().

◆ array_slice_size()

static int array_slice_size ( char *  arraydataptr,
bits8 arraynullsptr,
int  ndim,
int *  dim,
int *  lb,
int *  st,
int *  endp,
int  typlen,
bool  typbyval,
char  typalign 
)
static

Definition at line 5037 of file arrayfuncs.c.

5041{
5042 int src_offset,
5043 span[MAXDIM],
5044 prod[MAXDIM],
5045 dist[MAXDIM],
5046 indx[MAXDIM];
5047 char *ptr;
5048 int i,
5049 j,
5050 inc;
5051 int count = 0;
5052
5053 mda_get_range(ndim, span, st, endp);
5054
5055 /* Pretty easy for fixed element length without nulls ... */
5056 if (typlen > 0 && !arraynullsptr)
5057 return ArrayGetNItems(ndim, span) * att_align_nominal(typlen, typalign);
5058
5059 /* Else gotta do it the hard way */
5060 src_offset = ArrayGetOffset(ndim, dim, lb, st);
5061 ptr = array_seek(arraydataptr, 0, arraynullsptr, src_offset,
5062 typlen, typbyval, typalign);
5063 mda_get_prod(ndim, dim, prod);
5064 mda_get_offset_values(ndim, dist, prod, span);
5065 for (i = 0; i < ndim; i++)
5066 indx[i] = 0;
5067 j = ndim - 1;
5068 do
5069 {
5070 if (dist[j])
5071 {
5072 ptr = array_seek(ptr, src_offset, arraynullsptr, dist[j],
5073 typlen, typbyval, typalign);
5074 src_offset += dist[j];
5075 }
5076 if (!array_get_isnull(arraynullsptr, src_offset))
5077 {
5078 inc = att_addlength_pointer(0, typlen, ptr);
5079 inc = att_align_nominal(inc, typalign);
5080 ptr += inc;
5081 count += inc;
5082 }
5083 src_offset++;
5084 } while ((j = mda_next_tuple(ndim, indx, span)) != -1);
5085 return count;
5086}

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

5895{
5896 if (array_cmp(fcinfo) < 0)
5898 else
5900}

References array_cmp(), PG_GETARG_DATUM, and PG_RETURN_DATUM.

◆ array_unnest()

Datum array_unnest ( PG_FUNCTION_ARGS  )

Definition at line 6252 of file arrayfuncs.c.

6253{
6254 typedef struct
6255 {
6256 array_iter iter;
6257 int nextelem;
6258 int numelems;
6259 int16 elmlen;
6260 bool elmbyval;
6261 char elmalign;
6262 } array_unnest_fctx;
6263
6264 FuncCallContext *funcctx;
6265 array_unnest_fctx *fctx;
6266 MemoryContext oldcontext;
6267
6268 /* stuff done only on the first call of the function */
6269 if (SRF_IS_FIRSTCALL())
6270 {
6271 AnyArrayType *arr;
6272
6273 /* create a function context for cross-call persistence */
6274 funcctx = SRF_FIRSTCALL_INIT();
6275
6276 /*
6277 * switch to memory context appropriate for multiple function calls
6278 */
6279 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
6280
6281 /*
6282 * Get the array value and detoast if needed. We can't do this
6283 * earlier because if we have to detoast, we want the detoasted copy
6284 * to be in multi_call_memory_ctx, so it will go away when we're done
6285 * and not before. (If no detoast happens, we assume the originally
6286 * passed array will stick around till then.)
6287 */
6288 arr = PG_GETARG_ANY_ARRAY_P(0);
6289
6290 /* allocate memory for user context */
6291 fctx = (array_unnest_fctx *) palloc(sizeof(array_unnest_fctx));
6292
6293 /* initialize state */
6294 array_iter_setup(&fctx->iter, arr);
6295 fctx->nextelem = 0;
6296 fctx->numelems = ArrayGetNItems(AARR_NDIM(arr), AARR_DIMS(arr));
6297
6299 {
6300 /* we can just grab the type data from expanded array */
6301 fctx->elmlen = arr->xpn.typlen;
6302 fctx->elmbyval = arr->xpn.typbyval;
6303 fctx->elmalign = arr->xpn.typalign;
6304 }
6305 else
6307 &fctx->elmlen,
6308 &fctx->elmbyval,
6309 &fctx->elmalign);
6310
6311 funcctx->user_fctx = fctx;
6312 MemoryContextSwitchTo(oldcontext);
6313 }
6314
6315 /* stuff done on every call of the function */
6316 funcctx = SRF_PERCALL_SETUP();
6317 fctx = funcctx->user_fctx;
6318
6319 if (fctx->nextelem < fctx->numelems)
6320 {
6321 int offset = fctx->nextelem++;
6322 Datum elem;
6323
6324 elem = array_iter_next(&fctx->iter, &fcinfo->isnull, offset,
6325 fctx->elmlen, fctx->elmbyval, fctx->elmalign);
6326
6327 SRF_RETURN_NEXT(funcctx, elem);
6328 }
6329 else
6330 {
6331 /* do when there is no more left */
6332 SRF_RETURN_DONE(funcctx);
6333 }
6334}
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:304
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:308
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:310
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:306
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:328
void * user_fctx
Definition: funcapi.h:82
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:101

References AARR_DIMS, AARR_ELEMTYPE, AARR_NDIM, array_iter_next(), array_iter_setup(), ArrayGetNItems(), get_typlenbyvalalign(), MemoryContextSwitchTo(), FuncCallContext::multi_call_memory_ctx, palloc(), PG_GETARG_ANY_ARRAY_P, SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, ExpandedArrayHeader::typalign, ExpandedArrayHeader::typbyval, ExpandedArrayHeader::typlen, FuncCallContext::user_fctx, VARATT_IS_EXPANDED_HEADER, and AnyArrayType::xpn.

◆ array_unnest_support()

Datum array_unnest_support ( PG_FUNCTION_ARGS  )

Definition at line 6343 of file arrayfuncs.c.

6344{
6345 Node *rawreq = (Node *) PG_GETARG_POINTER(0);
6346 Node *ret = NULL;
6347
6348 if (IsA(rawreq, SupportRequestRows))
6349 {
6350 /* Try to estimate the number of rows returned */
6351 SupportRequestRows *req = (SupportRequestRows *) rawreq;
6352
6353 if (is_funcclause(req->node)) /* be paranoid */
6354 {
6355 List *args = ((FuncExpr *) req->node)->args;
6356 Node *arg1;
6357
6358 /* We can use estimated argument values here */
6360
6361 req->rows = estimate_array_length(req->root, arg1);
6362 ret = (Node *) req;
6363 }
6364 }
6365
6366 PG_RETURN_POINTER(ret);
6367}
Node * estimate_expression_value(PlannerInfo *root, Node *node)
Definition: clauses.c:2395
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
static bool is_funcclause(const void *clause)
Definition: nodeFuncs.h:69
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
#define linitial(l)
Definition: pg_list.h:178
double estimate_array_length(PlannerInfo *root, Node *arrayexpr)
Definition: selfuncs.c:2140
Definition: pg_list.h:54
struct PlannerInfo * root
Definition: supportnodes.h:163

References generate_unaccent_rules::args, estimate_array_length(), estimate_expression_value(), is_funcclause(), IsA, linitial, SupportRequestRows::node, PG_GETARG_POINTER, PG_RETURN_POINTER, SupportRequestRows::root, and SupportRequestRows::rows.

◆ array_upper()

Datum array_upper ( PG_FUNCTION_ARGS  )

Definition at line 1733 of file arrayfuncs.c.

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

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

4817{
4818 return fetch_att(value, byval, len);
4819}
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 4827 of file arrayfuncs.c.

4832{
4833 int inc;
4834
4835 if (typlen > 0)
4836 {
4837 if (typbyval)
4838 store_att_byval(dest, src, typlen);
4839 else
4840 memmove(dest, DatumGetPointer(src), typlen);
4841 inc = att_align_nominal(typlen, typalign);
4842 }
4843 else
4844 {
4845 Assert(!typbyval);
4846 inc = att_addlength_datum(0, typlen, src);
4847 memmove(dest, DatumGetPointer(src), inc);
4848 inc = att_align_nominal(inc, typalign);
4849 }
4850
4851 return inc;
4852}
static void store_att_byval(void *T, Datum newdatum, int attlen)
Definition: tupmacs.h:211

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

4561{
4564 Oid collation = PG_GET_COLLATION();
4565 bool result;
4566
4567 result = array_contain_compare(array1, array2, collation, true,
4568 &fcinfo->flinfo->fn_extra);
4569
4570 /* Avoid leaking memory when handed toasted input. */
4571 AARR_FREE_IF_COPY(array1, 0);
4572 AARR_FREE_IF_COPY(array2, 1);
4573
4574 PG_RETURN_BOOL(result);
4575}
static bool array_contain_compare(AnyArrayType *array1, AnyArrayType *array2, Oid collation, bool matchall, void **fn_extra)
Definition: arrayfuncs.c:4381

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

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

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

◆ arrayoverlap()

Datum arrayoverlap ( PG_FUNCTION_ARGS  )

Definition at line 4524 of file arrayfuncs.c.

4525{
4528 Oid collation = PG_GET_COLLATION();
4529 bool result;
4530
4531 result = array_contain_compare(array1, array2, collation, false,
4532 &fcinfo->flinfo->fn_extra);
4533
4534 /* Avoid leaking memory when handed toasted input. */
4535 AARR_FREE_IF_COPY(array1, 0);
4536 AARR_FREE_IF_COPY(array2, 1);
4537
4538 PG_RETURN_BOOL(result);
4539}

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

◆ btarraycmp()

Datum btarraycmp ( PG_FUNCTION_ARGS  )

Definition at line 3973 of file arrayfuncs.c.

3974{
3975 PG_RETURN_INT32(array_cmp(fcinfo));
3976}

References array_cmp(), and PG_RETURN_INT32.

◆ construct_array()

ArrayType * construct_array ( Datum elems,
int  nelems,
Oid  elmtype,
int  elmlen,
bool  elmbyval,
char  elmalign 
)

Definition at line 3361 of file arrayfuncs.c.

3364{
3365 int dims[1];
3366 int lbs[1];
3367
3368 dims[0] = nelems;
3369 lbs[0] = 1;
3370
3371 return construct_md_array(elems, NULL, 1, dims, lbs,
3372 elmtype, elmlen, elmbyval, elmalign);
3373}

References construct_md_array().

Referenced by ATExecAlterColumnType(), construct_array_builtin(), enum_range_internal(), match_orclause_to_indexcol(), serialize_expr_stats(), StoreAttrDefault(), and update_attstats().

◆ construct_array_builtin()

ArrayType * construct_array_builtin ( Datum elems,
int  nelems,
Oid  elmtype 
)

Definition at line 3381 of file arrayfuncs.c.

3382{
3383 int elmlen;
3384 bool elmbyval;
3385 char elmalign;
3386
3387 switch (elmtype)
3388 {
3389 case CHAROID:
3390 elmlen = 1;
3391 elmbyval = true;
3392 elmalign = TYPALIGN_CHAR;
3393 break;
3394
3395 case CSTRINGOID:
3396 elmlen = -2;
3397 elmbyval = false;
3398 elmalign = TYPALIGN_CHAR;
3399 break;
3400
3401 case FLOAT4OID:
3402 elmlen = sizeof(float4);
3403 elmbyval = true;
3404 elmalign = TYPALIGN_INT;
3405 break;
3406
3407 case FLOAT8OID:
3408 elmlen = sizeof(float8);
3409 elmbyval = FLOAT8PASSBYVAL;
3410 elmalign = TYPALIGN_DOUBLE;
3411 break;
3412
3413 case INT2OID:
3414 elmlen = sizeof(int16);
3415 elmbyval = true;
3416 elmalign = TYPALIGN_SHORT;
3417 break;
3418
3419 case INT4OID:
3420 elmlen = sizeof(int32);
3421 elmbyval = true;
3422 elmalign = TYPALIGN_INT;
3423 break;
3424
3425 case INT8OID:
3426 elmlen = sizeof(int64);
3427 elmbyval = FLOAT8PASSBYVAL;
3428 elmalign = TYPALIGN_DOUBLE;
3429 break;
3430
3431 case NAMEOID:
3432 elmlen = NAMEDATALEN;
3433 elmbyval = false;
3434 elmalign = TYPALIGN_CHAR;
3435 break;
3436
3437 case OIDOID:
3438 case REGTYPEOID:
3439 elmlen = sizeof(Oid);
3440 elmbyval = true;
3441 elmalign = TYPALIGN_INT;
3442 break;
3443
3444 case TEXTOID:
3445 elmlen = -1;
3446 elmbyval = false;
3447 elmalign = TYPALIGN_INT;
3448 break;
3449
3450 case TIDOID:
3451 elmlen = sizeof(ItemPointerData);
3452 elmbyval = false;
3453 elmalign = TYPALIGN_SHORT;
3454 break;
3455
3456 case XIDOID:
3457 elmlen = sizeof(TransactionId);
3458 elmbyval = true;
3459 elmalign = TYPALIGN_INT;
3460 break;
3461
3462 default:
3463 elog(ERROR, "type %u not supported by construct_array_builtin()", elmtype);
3464 /* keep compiler quiet */
3465 elmlen = 0;
3466 elmbyval = false;
3467 elmalign = 0;
3468 }
3469
3470 return construct_array(elems, nelems, elmtype, elmlen, elmbyval, elmalign);
3471}
ArrayType * construct_array(Datum *elems, int nelems, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:3361
int64_t int64
Definition: c.h:485
double float8
Definition: c.h:587
#define FLOAT8PASSBYVAL
Definition: c.h:592
float float4
Definition: c.h:586
uint32 TransactionId
Definition: c.h:609
struct ItemPointerData ItemPointerData
#define NAMEDATALEN

References construct_array(), elog, ERROR, FLOAT8PASSBYVAL, and NAMEDATALEN.

Referenced by AlterPolicy(), attribute_statistics_update(), bt_page_print_tuples(), build_regtype_array(), convert_requires_to_datum(), CreateConstraintEntry(), CreateFunction(), CreatePolicy(), CreateStatistics(), current_schemas(), executeItemOptUnwrapTarget(), extension_config_remove(), filter_list_to_array(), float4_accum(), float8_accum(), float8_combine(), float8_regr_accum(), float8_regr_combine(), get_environ(), get_hba_options(), GetWALBlockInfo(), gin_leafpage_items(), gin_page_opaque_info(), gist_page_opaque_info(), GUCArrayAdd(), GUCArrayDelete(), GUCArrayReset(), hash_metapage_info(), heap_tuple_infomask_flags(), hstore_akeys(), int_list_to_array(), interpret_function_parameter_list(), makeMultirangeConstructors(), pg_blocking_pids(), pg_extension_config_dump(), pg_get_logical_snapshot_info(), pg_safe_snapshot_blocking_pids(), pg_settings_get_flags(), publicationListToArray(), RemoveRoleFromObjectPolicy(), serialize_expr_stats(), show_trgm(), test_rls_hooks_permissive(), test_rls_hooks_restrictive(), ts_lexize(), tsvector_to_array(), tsvector_unnest(), typenameTypeMod(), and update_attstats().

◆ construct_empty_array()

◆ construct_empty_expanded_array()

ExpandedArrayHeader * construct_empty_expanded_array ( Oid  element_type,
MemoryContext  parentcontext,
ArrayMetaState metacache 
)

Definition at line 3597 of file arrayfuncs.c.

3600{
3601 ArrayType *array = construct_empty_array(element_type);
3602 Datum d;
3603
3604 d = expand_array(PointerGetDatum(array), parentcontext, metacache);
3605 pfree(array);
3606 return (ExpandedArrayHeader *) DatumGetEOHP(d);
3607}
Datum expand_array(Datum arraydatum, MemoryContext parentcontext, ArrayMetaState *metacache)

References construct_empty_array(), DatumGetEOHP(), expand_array(), pfree(), and PointerGetDatum().

Referenced by fetch_array_arg_replace_nulls().

◆ construct_md_array()

ArrayType * construct_md_array ( Datum elems,
bool *  nulls,
int  ndims,
int *  dims,
int *  lbs,
Oid  elmtype,
int  elmlen,
bool  elmbyval,
char  elmalign 
)

Definition at line 3494 of file arrayfuncs.c.

3500{
3501 ArrayType *result;
3502 bool hasnulls;
3503 int32 nbytes;
3504 int32 dataoffset;
3505 int i;
3506 int nelems;
3507
3508 if (ndims < 0) /* we do allow zero-dimension arrays */
3509 ereport(ERROR,
3510 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3511 errmsg("invalid number of dimensions: %d", ndims)));
3512 if (ndims > MAXDIM)
3513 ereport(ERROR,
3514 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
3515 errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
3516 ndims, MAXDIM)));
3517
3518 /* This checks for overflow of the array dimensions */
3519 nelems = ArrayGetNItems(ndims, dims);
3520 ArrayCheckBounds(ndims, dims, lbs);
3521
3522 /* if ndims <= 0 or any dims[i] == 0, return empty array */
3523 if (nelems <= 0)
3524 return construct_empty_array(elmtype);
3525
3526 /* compute required space */
3527 nbytes = 0;
3528 hasnulls = false;
3529 for (i = 0; i < nelems; i++)
3530 {
3531 if (nulls && nulls[i])
3532 {
3533 hasnulls = true;
3534 continue;
3535 }
3536 /* make sure data is not toasted */
3537 if (elmlen == -1)
3538 elems[i] = PointerGetDatum(PG_DETOAST_DATUM(elems[i]));
3539 nbytes = att_addlength_datum(nbytes, elmlen, elems[i]);
3540 nbytes = att_align_nominal(nbytes, elmalign);
3541 /* check for overflow of total request */
3542 if (!AllocSizeIsValid(nbytes))
3543 ereport(ERROR,
3544 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
3545 errmsg("array size exceeds the maximum allowed (%d)",
3546 (int) MaxAllocSize)));
3547 }
3548
3549 /* Allocate and initialize result array */
3550 if (hasnulls)
3551 {
3552 dataoffset = ARR_OVERHEAD_WITHNULLS(ndims, nelems);
3553 nbytes += dataoffset;
3554 }
3555 else
3556 {
3557 dataoffset = 0; /* marker for no null bitmap */
3558 nbytes += ARR_OVERHEAD_NONULLS(ndims);
3559 }
3560 result = (ArrayType *) palloc0(nbytes);
3561 SET_VARSIZE(result, nbytes);
3562 result->ndim = ndims;
3563 result->dataoffset = dataoffset;
3564 result->elemtype = elmtype;
3565 memcpy(ARR_DIMS(result), dims, ndims * sizeof(int));
3566 memcpy(ARR_LBOUND(result), lbs, ndims * sizeof(int));
3567
3568 CopyArrayEls(result,
3569 elems, nulls, nelems,
3570 elmlen, elmbyval, elmalign,
3571 false);
3572
3573 return result;
3574}

References AllocSizeIsValid, ARR_DIMS, ARR_LBOUND, ARR_OVERHEAD_NONULLS, ARR_OVERHEAD_WITHNULLS, ArrayCheckBounds(), ArrayGetNItems(), att_addlength_datum, att_align_nominal, construct_empty_array(), CopyArrayEls(), ArrayType::dataoffset, ArrayType::elemtype, ereport, errcode(), errmsg(), ERROR, i, MaxAllocSize, MAXDIM, ArrayType::ndim, palloc0(), PG_DETOAST_DATUM, PointerGetDatum(), and SET_VARSIZE.

Referenced by array_iterate(), array_reverse_n(), array_set_element(), array_set_slice(), array_shuffle_n(), build_regexp_match_result(), build_test_info_result(), build_test_match_result(), construct_array(), ExecEvalArrayExpr(), hstore_avals(), hstore_slice_to_array(), hstore_to_array_internal(), makeMdArrayResult(), percentile_cont_multi_final_common(), percentile_disc_multi_final(), plpgsql_fulfill_promise(), and strlist_to_textarray().

◆ CopyArrayEls()

void CopyArrayEls ( ArrayType array,
Datum values,
bool *  nulls,
int  nitems,
int  typlen,
bool  typbyval,
char  typalign,
bool  freedata 
)

Definition at line 961 of file arrayfuncs.c.

969{
970 char *p = ARR_DATA_PTR(array);
971 bits8 *bitmap = ARR_NULLBITMAP(array);
972 int bitval = 0;
973 int bitmask = 1;
974 int i;
975
976 if (typbyval)
977 freedata = false;
978
979 for (i = 0; i < nitems; i++)
980 {
981 if (nulls && nulls[i])
982 {
983 if (!bitmap) /* shouldn't happen */
984 elog(ERROR, "null array element where not supported");
985 /* bitmap bit stays 0 */
986 }
987 else
988 {
989 bitval |= bitmask;
990 p += ArrayCastAndSet(values[i], typlen, typbyval, typalign, p);
991 if (freedata)
993 }
994 if (bitmap)
995 {
996 bitmask <<= 1;
997 if (bitmask == 0x100)
998 {
999 *bitmap++ = bitval;
1000 bitval = 0;
1001 bitmask = 1;
1002 }
1003 }
1004 }
1005
1006 if (bitmap && bitmask != 1)
1007 *bitmap = bitval;
1008}

References ARR_DATA_PTR, ARR_NULLBITMAP, ArrayCastAndSet(), DatumGetPointer(), elog, ERROR, i, nitems, pfree(), typalign, and values.

Referenced by array_in(), array_map(), array_recv(), array_replace_internal(), construct_md_array(), and EA_flatten_into().

◆ create_array_envelope()

static ArrayType * create_array_envelope ( int  ndims,
int *  dimv,
int *  lbsv,
int  nbytes,
Oid  elmtype,
int  dataoffset 
)
static

Definition at line 6066 of file arrayfuncs.c.

6068{
6069 ArrayType *result;
6070
6071 result = (ArrayType *) palloc0(nbytes);
6072 SET_VARSIZE(result, nbytes);
6073 result->ndim = ndims;
6074 result->dataoffset = dataoffset;
6075 result->elemtype = elmtype;
6076 memcpy(ARR_DIMS(result), dimv, ndims * sizeof(int));
6077 memcpy(ARR_LBOUND(result), lbsv, ndims * sizeof(int));
6078
6079 return result;
6080}

References ARR_DIMS, ARR_LBOUND, ArrayType::dataoffset, ArrayType::elemtype, ArrayType::ndim, palloc0(), and SET_VARSIZE.

Referenced by array_fill_internal().

◆ deconstruct_array()

void deconstruct_array ( ArrayType array,
Oid  elmtype,
int  elmlen,
bool  elmbyval,
char  elmalign,
Datum **  elemsp,
bool **  nullsp,
int *  nelemsp 
)

Definition at line 3631 of file arrayfuncs.c.

3635{
3636 Datum *elems;
3637 bool *nulls;
3638 int nelems;
3639 char *p;
3640 bits8 *bitmap;
3641 int bitmask;
3642 int i;
3643
3644 Assert(ARR_ELEMTYPE(array) == elmtype);
3645
3646 nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
3647 *elemsp = elems = (Datum *) palloc(nelems * sizeof(Datum));
3648 if (nullsp)
3649 *nullsp = nulls = (bool *) palloc0(nelems * sizeof(bool));
3650 else
3651 nulls = NULL;
3652 *nelemsp = nelems;
3653
3654 p = ARR_DATA_PTR(array);
3655 bitmap = ARR_NULLBITMAP(array);
3656 bitmask = 1;
3657
3658 for (i = 0; i < nelems; i++)
3659 {
3660 /* Get source element, checking for NULL */
3661 if (bitmap && (*bitmap & bitmask) == 0)
3662 {
3663 elems[i] = (Datum) 0;
3664 if (nulls)
3665 nulls[i] = true;
3666 else
3667 ereport(ERROR,
3668 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
3669 errmsg("null array element not allowed in this context")));
3670 }
3671 else
3672 {
3673 elems[i] = fetch_att(p, elmbyval, elmlen);
3674 p = att_addlength_pointer(p, elmlen, p);
3675 p = (char *) att_align_nominal(p, elmalign);
3676 }
3677
3678 /* advance bitmap pointer if any */
3679 if (bitmap)
3680 {
3681 bitmask <<= 1;
3682 if (bitmask == 0x100)
3683 {
3684 bitmap++;
3685 bitmask = 1;
3686 }
3687 }
3688 }
3689}

References ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_NDIM,