PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:132
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#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
Assert(PointerIsAligned(start, uint64))
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:2167
#define AllocSizeIsValid(size)
Definition: memutils.h:45
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 5829 of file arrayfuncs.c.

5833{
5834 if (astate == NULL)
5835 astate = initArrayResultAny(input_type, rcontext, true);
5836
5837 if (astate->scalarstate)
5838 (void) accumArrayResult(astate->scalarstate,
5839 dvalue, disnull,
5840 input_type, rcontext);
5841 else
5842 (void) accumArrayResultArr(astate->arraystate,
5843 dvalue, disnull,
5844 input_type, rcontext);
5845
5846 return astate;
5847}
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 array_sort_internal(), 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:969
char * Pointer
Definition: c.h:493
uint8 bits8
Definition: c.h:509
#define nitems(x)
Definition: indent.h:31
int i
Definition: isn.c:77
void pfree(void *pointer)
Definition: mcxt.c:2147
void * palloc(Size size)
Definition: mcxt.c:1940
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:35
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:975
int32_t int32
Definition: c.h:498
#define OidIsValid(objectId)
Definition: c.h:746
#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:81
char typalign
Definition: pg_type.h:176
static int32 DatumGetInt32(Datum X)
Definition: postgres.h:207
unsigned int Oid
Definition: postgres_ext.h:30
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:77
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:144

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:78
static bool DatumGetBool(Datum X)
Definition: postgres.h:95
Datum * dvalues
Definition: array.h:146
FmgrInfo eq_opr_finfo
Definition: typcache.h:76
#define TYPECACHE_EQ_OPR_FINFO
Definition: typcache.h:143
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:734
#define elog(elevel,...)
Definition: elog.h:226
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2411
void * palloc0(Size size)
Definition: mcxt.c:1970
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(), array_sort_internal(), 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:241
text * cstring_to_text(const char *s)
Definition: varlena.c:192

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

6034{
6035 ArrayType *dims;
6036 ArrayType *result;
6037 Oid elmtype;
6038 Datum value;
6039 bool isnull;
6040
6041 if (PG_ARGISNULL(1))
6042 ereport(ERROR,
6043 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
6044 errmsg("dimension array or low bound array cannot be null")));
6045
6046 dims = PG_GETARG_ARRAYTYPE_P(1);
6047
6048 if (!PG_ARGISNULL(0))
6049 {
6051 isnull = false;
6052 }
6053 else
6054 {
6055 value = 0;
6056 isnull = true;
6057 }
6058
6059 elmtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
6060 if (!OidIsValid(elmtype))
6061 elog(ERROR, "could not determine data type of input");
6062
6063 result = array_fill_internal(dims, NULL, value, isnull, elmtype, fcinfo);
6064 PG_RETURN_ARRAYTYPE_P(result);
6065}
#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:6085
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 @165 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 6085 of file arrayfuncs.c.

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

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

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

◆ 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:278
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:2465
@ IOFunc_input
Definition: lsyscache.h:36
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:135

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

◆ array_larger()

Datum array_larger ( PG_FUNCTION_ARGS  )

Definition at line 5887 of file arrayfuncs.c.

5888{
5889 if (array_cmp(fcinfo) > 0)
5891 else
5893}
#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:415
ArrayMetaState inp_extra
Definition: array.h:253
ArrayMetaState ret_extra
Definition: array.h:254
bool * innermost_casenull
Definition: execnodes.h:139
Datum * innermost_caseval
Definition: execnodes.h:138

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:37
char * pstrdup(const char *in)
Definition: mcxt.c:2322
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:38
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 6639 of file arrayfuncs.c.

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

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

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

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

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

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:663
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:39
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:658
#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:1290
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 5896 of file arrayfuncs.c.

5897{
5898 if (array_cmp(fcinfo) < 0)
5900 else
5902}

References array_cmp(), PG_GETARG_DATUM, and PG_RETURN_DATUM.

◆ array_unnest()

Datum array_unnest ( PG_FUNCTION_ARGS  )

Definition at line 6254 of file arrayfuncs.c.

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

6346{
6347 Node *rawreq = (Node *) PG_GETARG_POINTER(0);
6348 Node *ret = NULL;
6349
6350 if (IsA(rawreq, SupportRequestRows))
6351 {
6352 /* Try to estimate the number of rows returned */
6353 SupportRequestRows *req = (SupportRequestRows *) rawreq;
6354
6355 if (is_funcclause(req->node)) /* be paranoid */
6356 {
6357 List *args = ((FuncExpr *) req->node)->args;
6358 Node *arg1;
6359
6360 /* We can use estimated argument values here */
6362
6363 req->rows = estimate_array_length(req->root, arg1);
6364 ret = (Node *) req;
6365 }
6366 }
6367
6368 PG_RETURN_POINTER(ret);
6369}
Node * estimate_expression_value(PlannerInfo *root, Node *node)
Definition: clauses.c:2397
#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:164
#define linitial(l)
Definition: pg_list.h:178
double estimate_array_length(PlannerInfo *root, Node *arrayexpr)
Definition: selfuncs.c:2144
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(), serialize_expr_stats(), StoreAttrMissingVal(), 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:499
double float8
Definition: c.h:601
#define FLOAT8PASSBYVAL
Definition: c.h:606
float float4
Definition: c.h:600
uint32 TransactionId
Definition: c.h:623
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_get_process_memory_contexts(), 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(), make_SAOP_expr(), 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 6068 of file arrayfuncs.c.

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

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, ARR_NULLBITMAP, ArrayGetNItems(), Assert(), att_addlength_pointer, att_align_nominal, ereport, errcode(), errmsg(), ERROR, fetch_att(), i, palloc(), and palloc0().

Referenced by _bt_preprocess_array_keys(), array_contain_compare(), array_reverse_n(), array_set_slice(), array_shuffle_n(), array_to_json_internal(), array_to_jsonb_internal(), arrayconst_startup_fn(), compute_array_stats(), deconstruct_array_builtin(), deconstruct_expanded_array(), ExecIndexEvalArrayKeys(), extract_variadic_args(), get_attstatsslot(), ginarrayextract(), gincost_scalararrayopexpr(), ginqueryarrayextract(), map_sql_value_to_xml_value(), match_clause_to_partition_key(), mcelem_array_selec(), mcv_get_match_bitmap(), multirange_constructor2(), plperl_ref_from_pg_array(), satisfies_hash_partition(), scalararraysel(), and text_format().

◆ deconstruct_array_builtin()

void deconstruct_array_builtin ( ArrayType array,
Oid  elmtype,
Datum **  elemsp,
bool **  nullsp,
int *  nelemsp 
)

Definition at line 3697 of file arrayfuncs.c.

3700{
3701 int elmlen;
3702 bool elmbyval;
3703 char elmalign;
3704
3705 switch (elmtype)
3706 {
3707 case CHAROID:
3708 elmlen = 1;
3709 elmbyval = true;
3710 elmalign = TYPALIGN_CHAR;
3711 break;
3712
3713 case CSTRINGOID:
3714 elmlen = -2;
3715 elmbyval = false;
3716 elmalign = TYPALIGN_CHAR;
3717 break;
3718
3719 case FLOAT8OID:
3720 elmlen = sizeof(float8);
3721 elmbyval = FLOAT8PASSBYVAL;
3722 elmalign = TYPALIGN_DOUBLE;
3723 break;
3724
3725 case INT2OID:
3726 elmlen = sizeof(int16);
3727 elmbyval = true;
3728 elmalign = TYPALIGN_SHORT;
3729 break;
3730
3731 case OIDOID:
3732 elmlen = sizeof(Oid);
3733 elmbyval = true;
3734 elmalign = TYPALIGN_INT;
3735 break;
3736
3737 case TEXTOID:
3738 elmlen = -1;
3739 elmbyval = false;
3740 elmalign = TYPALIGN_INT;
3741 break;
3742
3743 case TIDOID:
3744 elmlen = sizeof(ItemPointerData);
3745 elmbyval = false;
3746 elmalign = TYPALIGN_SHORT;
3747 break;
3748
3749 default:
3750 elog(ERROR, "type %u not supported by deconstruct_array_builtin()", elmtype);
3751 /* keep compiler quiet */
3752 elmlen = 0;
3753 elmbyval = false;
3754 elmalign = 0;
3755 }
3756
3757 deconstruct_array(array, elmtype, elmlen, elmbyval, elmalign, elemsp, nullsp, nelemsp);
3758}

References deconstruct_array(), elog, ERROR, and FLOAT8PASSBYVAL.

Referenced by array_to_tsvector(), ArrayGetIntegerTypmods(), binary_upgrade_create_empty_extension(), build_function_result_tupdesc_d(), DecodeTextArrayToBitmapset(), decompile_column_index_array(), extension_config_remove(), generateClonedIndexStmt(), get_func_arg_info(), get_func_input_arg_names(), get_func_result_name(), get_jsonb_path_all(), get_path_all(), get_reloptions(), ghstore_consistent(), gin_extract_hstore_query(), gin_extract_jsonb_query(), hstore_from_array(), hstore_from_arrays(), hstore_slice_to_array(), hstoreArrayToPairs(), json_object(), json_object_two_arg(), jsonb_delete_array(), jsonb_delete_path(), jsonb_exists_all(), jsonb_exists_any(), jsonb_insert(), jsonb_object(), jsonb_object_two_arg(), jsonb_set(), oid_array_to_list(), parse_key_value_arrays(), parseRelOptionsInternal(), percentile_cont_multi_final_common(), percentile_disc_multi_final(), pg_get_constraintdef_worker(), pg_get_object_address(), pg_get_publication_tables(), pg_logical_slot_get_changes_guts(), textarray_to_stringlist(), textarray_to_strvaluelist(), TidListEval(), transformRelOptions(), tsvector_delete_arr(), tsvector_filter(), tsvector_setweight_by_filter(), untransformRelOptions(), and worker_spi_launch().

◆ generate_subscripts()

Datum generate_subscripts ( PG_FUNCTION_ARGS  )

Definition at line 5917 of file arrayfuncs.c.

5918{
5919 FuncCallContext *funcctx;
5920 MemoryContext oldcontext;
5922
5923 /* stuff done only on the first call of the function */
5924 if (SRF_IS_FIRSTCALL())
5925 {
5927 int reqdim = PG_GETARG_INT32(1);
5928 int *lb,
5929 *dimv;
5930
5931 /* create a function context for cross-call persistence */
5932 funcctx = SRF_FIRSTCALL_INIT();
5933
5934 /* Sanity check: does it look like an array at all? */
5935 if (AARR_NDIM(v) <= 0 || AARR_NDIM(v) > MAXDIM)
5936 SRF_RETURN_DONE(funcctx);
5937
5938 /* Sanity check: was the requested dim valid */
5939 if (reqdim <= 0 || reqdim > AARR_NDIM(v))
5940 SRF_RETURN_DONE(funcctx);
5941
5942 /*
5943 * switch to memory context appropriate for multiple function calls
5944 */
5945 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
5947
5948 lb = AARR_LBOUND(v);
5949 dimv = AARR_DIMS(v);
5950
5951 fctx->lower = lb[reqdim - 1];
5952 fctx->upper = dimv[reqdim - 1] + lb[reqdim - 1] - 1;
5953 fctx->reverse = (PG_NARGS() < 3) ? false : PG_GETARG_BOOL(2);
5954
5955 funcctx->user_fctx = fctx;
5956
5957 MemoryContextSwitchTo(oldcontext);
5958 }
5959
5960 funcctx = SRF_PERCALL_SETUP();
5961
5962 fctx = funcctx->user_fctx;
5963
5964 if (fctx->lower <= fctx->upper)
5965 {
5966 if (!fctx->reverse)
5967 SRF_RETURN_NEXT(funcctx, Int32GetDatum(fctx->lower++));
5968 else
5969 SRF_RETURN_NEXT(funcctx, Int32GetDatum(fctx->upper--));
5970 }
5971 else
5972 /* done when there are no more elements left */
5973 SRF_RETURN_DONE(funcctx);
5974}
#define PG_NARGS()
Definition: fmgr.h:203
#define PG_GETARG_BOOL(n)
Definition: fmgr.h:274
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:217

References AARR_DIMS, AARR_LBOUND, AARR_NDIM, Int32GetDatum(), generate_subscripts_fctx::lower, MAXDIM, MemoryContextSwitchTo(), FuncCallContext::multi_call_memory_ctx, palloc(), PG_GETARG_ANY_ARRAY_P, PG_GETARG_BOOL, PG_GETARG_INT32, PG_NARGS, generate_subscripts_fctx::reverse, SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, generate_subscripts_fctx::upper, and FuncCallContext::user_fctx.

Referenced by generate_subscripts_nodir().

◆ generate_subscripts_nodir()

Datum generate_subscripts_nodir ( PG_FUNCTION_ARGS  )

Definition at line 5981 of file arrayfuncs.c.

5982{
5983 /* just call the other one -- it can handle both cases */
5984 return generate_subscripts(fcinfo);
5985}
Datum generate_subscripts(PG_FUNCTION_ARGS)
Definition: arrayfuncs.c:5917

References generate_subscripts().

◆ hash_array()

Datum hash_array ( PG_FUNCTION_ARGS  )

Definition at line 4158 of file arrayfuncs.c.

4159{
4160 LOCAL_FCINFO(locfcinfo, 1);
4162 int ndims = AARR_NDIM(array);
4163 int *dims = AARR_DIMS(array);
4164 Oid element_type = AARR_ELEMTYPE(array);
4165 uint32 result = 1;
4166 int nitems;
4167 TypeCacheEntry *typentry;
4168 int typlen;
4169 bool typbyval;
4170 char typalign;
4171 int i;
4172 array_iter iter;
4173
4174 /*
4175 * We arrange to look up the hash function only once per series of calls,
4176 * assuming the element type doesn't change underneath us. The typcache
4177 * is used so that we have no memory leakage when being used as an index
4178 * support function.
4179 */
4180 typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
4181 if (typentry == NULL ||
4182 typentry->type_id != element_type)
4183 {
4184 typentry = lookup_type_cache(element_type,
4186 if (!OidIsValid(typentry->hash_proc_finfo.fn_oid) && element_type != RECORDOID)
4187 ereport(ERROR,
4188 (errcode(ERRCODE_UNDEFINED_FUNCTION),
4189 errmsg("could not identify a hash function for type %s",
4190 format_type_be(element_type))));
4191
4192 /*
4193 * The type cache doesn't believe that record is hashable (see
4194 * cache_record_field_properties()), but since we're here, we're
4195 * committed to hashing, so we can assume it does. Worst case, if any
4196 * components of the record don't support hashing, we will fail at
4197 * execution.
4198 */
4199 if (element_type == RECORDOID)
4200 {
4201 MemoryContext oldcontext;
4202 TypeCacheEntry *record_typentry;
4203
4204 oldcontext = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt);
4205
4206 /*
4207 * Make fake type cache entry structure. Note that we can't just
4208 * modify typentry, since that points directly into the type
4209 * cache.
4210 */
4211 record_typentry = palloc0(sizeof(*record_typentry));
4212 record_typentry->type_id = element_type;
4213
4214 /* fill in what we need below */
4215 record_typentry->typlen = typentry->typlen;
4216 record_typentry->typbyval = typentry->typbyval;
4217 record_typentry->typalign = typentry->typalign;
4218 fmgr_info(F_HASH_RECORD, &record_typentry->hash_proc_finfo);
4219
4220 MemoryContextSwitchTo(oldcontext);
4221
4222 typentry = record_typentry;
4223 }
4224
4225 fcinfo->flinfo->fn_extra = typentry;
4226 }
4227
4228 typlen = typentry->typlen;
4229 typbyval = typentry->typbyval;
4230 typalign = typentry->typalign;
4231
4232 /*
4233 * apply the hash function to each array element.
4234 */
4235 InitFunctionCallInfoData(*locfcinfo, &typentry->hash_proc_finfo, 1,
4236 PG_GET_COLLATION(), NULL, NULL);
4237
4238 /* Loop over source data */
4239 nitems = ArrayGetNItems(ndims, dims);
4240 array_iter_setup(&iter, array);
4241
4242 for (i = 0; i < nitems; i++)
4243 {
4244 Datum elt;
4245 bool isnull;
4246 uint32 elthash;
4247
4248 /* Get element, checking for NULL */
4249 elt = array_iter_next(&iter, &isnull, i, typlen, typbyval, typalign);
4250
4251 if (isnull)
4252 {
4253 /* Treat nulls as having hashvalue 0 */
4254 elthash = 0;
4255 }
4256 else
4257 {
4258 /* Apply the hash function */
4259 locfcinfo->args[0].value = elt;
4260 locfcinfo->args[0].isnull = false;
4261 elthash = DatumGetUInt32(FunctionCallInvoke(locfcinfo));
4262 /* We don't expect hash functions to return null */
4263 Assert(!locfcinfo->isnull);
4264 }
4265
4266 /*
4267 * Combine hash values of successive elements by multiplying the
4268 * current value by 31 and adding on the new element's hash value.
4269 *
4270 * The result is a sum in which each element's hash value is
4271 * multiplied by a different power of 31. This is modulo 2^32
4272 * arithmetic, and the powers of 31 modulo 2^32 form a cyclic group of
4273 * order 2^27. So for arrays of up to 2^27 elements, each element's
4274 * hash value is multiplied by a different (odd) number, resulting in
4275 * a good mixing of all the elements' hash values.
4276 */
4277 result = (result << 5) - result + elthash;
4278 }
4279
4280 /* Avoid leaking memory when handed toasted input. */
4281 AARR_FREE_IF_COPY(array, 0);
4282
4283 PG_RETURN_UINT32(result);
4284}
uint32_t uint32
Definition: c.h:502
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:127
#define PG_RETURN_UINT32(x)
Definition: fmgr.h:355
static uint32 DatumGetUInt32(Datum X)
Definition: postgres.h:227
FmgrInfo hash_proc_finfo
Definition: typcache.h:78
#define TYPECACHE_HASH_PROC_FINFO
Definition: typcache.h:145

References AARR_DIMS, AARR_ELEMTYPE, AARR_FREE_IF_COPY, AARR_NDIM, array_iter_next(), array_iter_setup(), ArrayGetNItems(), Assert(), DatumGetUInt32(), ereport, errcode(), errmsg(), ERROR, fmgr_info(), FmgrInfo::fn_oid, format_type_be(), FunctionCallInvoke, TypeCacheEntry::hash_proc_finfo, i, if(), InitFunctionCallInfoData, LOCAL_FCINFO, lookup_type_cache(), MemoryContextSwitchTo(), nitems, OidIsValid, palloc0(), PG_GET_COLLATION, PG_GETARG_ANY_ARRAY_P, PG_RETURN_UINT32, typalign, TypeCacheEntry::typalign, TypeCacheEntry::typbyval, TypeCacheEntry::type_id, TYPECACHE_HASH_PROC_FINFO, and TypeCacheEntry::typlen.

◆ hash_array_extended()

Datum hash_array_extended ( PG_FUNCTION_ARGS  )

Definition at line 4291 of file arrayfuncs.c.

4292{
4293 LOCAL_FCINFO(locfcinfo, 2);
4295 uint64 seed = PG_GETARG_INT64(1);
4296 int ndims = AARR_NDIM(array);
4297 int *dims = AARR_DIMS(array);
4298 Oid element_type = AARR_ELEMTYPE(array);
4299 uint64 result = 1;
4300 int nitems;
4301 TypeCacheEntry *typentry;
4302 int typlen;
4303 bool typbyval;
4304 char typalign;
4305 int i;
4306 array_iter iter;
4307
4308 typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
4309 if (typentry == NULL ||
4310 typentry->type_id != element_type)
4311 {
4312 typentry = lookup_type_cache(element_type,
4315 ereport(ERROR,
4316 (errcode(ERRCODE_UNDEFINED_FUNCTION),
4317 errmsg("could not identify an extended hash function for type %s",
4318 format_type_be(element_type))));
4319 fcinfo->flinfo->fn_extra = typentry;
4320 }
4321 typlen = typentry->typlen;
4322 typbyval = typentry->typbyval;
4323 typalign = typentry->typalign;
4324
4325 InitFunctionCallInfoData(*locfcinfo, &typentry->hash_extended_proc_finfo, 2,
4326 PG_GET_COLLATION(), NULL, NULL);
4327
4328 /* Loop over source data */
4329 nitems = ArrayGetNItems(ndims, dims);
4330 array_iter_setup(&iter, array);
4331
4332 for (i = 0; i < nitems; i++)
4333 {
4334 Datum elt;
4335 bool isnull;
4336 uint64 elthash;
4337
4338 /* Get element, checking for NULL */
4339 elt = array_iter_next(&iter, &isnull, i, typlen, typbyval, typalign);
4340
4341 if (isnull)
4342 {
4343 elthash = 0;
4344 }
4345 else
4346 {
4347 /* Apply the hash function */
4348 locfcinfo->args[0].value = elt;
4349 locfcinfo->args[0].isnull = false;
4350 locfcinfo->args[1].value = Int64GetDatum(seed);
4351 locfcinfo->args[1].isnull = false;
4352 elthash = DatumGetUInt64(FunctionCallInvoke(locfcinfo));
4353 /* We don't expect hash functions to return null */
4354 Assert(!locfcinfo->isnull);
4355 }
4356
4357 result = (result << 5) - result + elthash;
4358 }
4359
4360 AARR_FREE_IF_COPY(array, 0);
4361
4362 PG_RETURN_UINT64(result);
4363}
uint64_t uint64
Definition: c.h:503
Datum Int64GetDatum(int64 X)
Definition: fmgr.c:1807
#define PG_GETARG_INT64(n)
Definition: fmgr.h:283
#define PG_RETURN_UINT64(x)
Definition: fmgr.h:369
static uint64 DatumGetUInt64(Datum X)
Definition: postgres.h:424
FmgrInfo hash_extended_proc_finfo
Definition: typcache.h:79
#define TYPECACHE_HASH_EXTENDED_PROC_FINFO
Definition: typcache.h:153

References AARR_DIMS, AARR_ELEMTYPE, AARR_FREE_IF_COPY, AARR_NDIM, array_iter_next(), array_iter_setup(), ArrayGetNItems(), Assert(), DatumGetUInt64(), ereport, errcode(), errmsg(), ERROR, FmgrInfo::fn_oid, format_type_be(), FunctionCallInvoke, TypeCacheEntry::hash_extended_proc_finfo, i, if(), InitFunctionCallInfoData, Int64GetDatum(), LOCAL_FCINFO, lookup_type_cache(), nitems, OidIsValid, PG_GET_COLLATION, PG_GETARG_ANY_ARRAY_P, PG_GETARG_INT64, PG_RETURN_UINT64, typalign, TypeCacheEntry::typalign, TypeCacheEntry::typbyval, TypeCacheEntry::type_id, TYPECACHE_HASH_EXTENDED_PROC_FINFO, and TypeCacheEntry::typlen.

◆ initArrayResult()

ArrayBuildState * initArrayResult ( Oid  element_type,
MemoryContext  rcontext,
bool  subcontext 
)

Definition at line 5293 of file arrayfuncs.c.

5294{
5295 /*
5296 * When using a subcontext, we can afford to start with a somewhat larger
5297 * initial array size. Without subcontexts, we'd better hope that most of
5298 * the states stay small ...
5299 */
5300 return initArrayResultWithSize(element_type, rcontext, subcontext,
5301 subcontext ? 64 : 8);
5302}
ArrayBuildState * initArrayResultWithSize(Oid element_type, MemoryContext rcontext, bool subcontext, int initsize)
Definition: arrayfuncs.c:5310

References initArrayResultWithSize().

Referenced by accumArrayResult(), array_agg_transfn(), array_positions(), array_to_datum_internal(), daitch_mokotoff(), initArrayResultAny(), multirange_agg_transfn(), PLySequence_ToArray_recurse(), populate_array(), range_agg_transfn(), tuple_data_split_internal(), and xpath().

◆ initArrayResultAny()

ArrayBuildStateAny * initArrayResultAny ( Oid  input_type,
MemoryContext  rcontext,
bool  subcontext 
)

Definition at line 5782 of file arrayfuncs.c.

5783{
5784 ArrayBuildStateAny *astate;
5785
5786 /*
5787 * int2vector and oidvector will satisfy both get_element_type and
5788 * get_array_type. We prefer to treat them as scalars, to be consistent
5789 * with get_promoted_array_type. Hence, check get_array_type not
5790 * get_element_type.
5791 */
5792 if (!OidIsValid(get_array_type(input_type)))
5793 {
5794 /* Array case */
5795 ArrayBuildStateArr *arraystate;
5796
5797 arraystate = initArrayResultArr(input_type, InvalidOid, rcontext, subcontext);
5798 astate = (ArrayBuildStateAny *)
5799 MemoryContextAlloc(arraystate->mcontext,
5800 sizeof(ArrayBuildStateAny));
5801 astate->scalarstate = NULL;
5802 astate->arraystate = arraystate;
5803 }
5804 else
5805 {
5806 /* Scalar case */
5807 ArrayBuildState *scalarstate;
5808
5809 scalarstate = initArrayResult(input_type, rcontext, subcontext);
5810 astate = (ArrayBuildStateAny *)
5811 MemoryContextAlloc(scalarstate->mcontext,
5812 sizeof(ArrayBuildStateAny));
5813 astate->scalarstate = scalarstate;
5814 astate->arraystate = NULL;
5815 }
5816
5817 return astate;
5818}
Oid get_array_type(Oid typid)
Definition: lsyscache.c:2927

References ArrayBuildStateAny::arraystate, get_array_type(), initArrayResult(), initArrayResultArr(), InvalidOid, ArrayBuildState::mcontext, ArrayBuildStateArr::mcontext, MemoryContextAlloc(), OidIsValid, and ArrayBuildStateAny::scalarstate.

Referenced by accumArrayResultAny(), ExecScanSubPlan(), and ExecSetParamPlan().

◆ initArrayResultArr()

ArrayBuildStateArr * initArrayResultArr ( Oid  array_type,
Oid  element_type,
MemoryContext  rcontext,
bool  subcontext 
)

Definition at line 5504 of file arrayfuncs.c.

5506{
5507 ArrayBuildStateArr *astate;
5508 MemoryContext arr_context = rcontext; /* by default use the parent ctx */
5509
5510 /* Lookup element type, unless element_type already provided */
5511 if (!OidIsValid(element_type))
5512 {
5513 element_type = get_element_type(array_type);
5514
5515 if (!OidIsValid(element_type))
5516 ereport(ERROR,
5517 (errcode(ERRCODE_DATATYPE_MISMATCH),
5518 errmsg("data type %s is not an array type",
5519 format_type_be(array_type))));
5520 }
5521
5522 /* Make a temporary context to hold all the junk */
5523 if (subcontext)
5524 arr_context = AllocSetContextCreate(rcontext,
5525 "accumArrayResultArr",
5527
5528 /* Note we initialize all fields to zero */
5529 astate = (ArrayBuildStateArr *)
5530 MemoryContextAllocZero(arr_context, sizeof(ArrayBuildStateArr));
5531 astate->mcontext = arr_context;
5532 astate->private_cxt = subcontext;
5533
5534 /* Save relevant datatype information */
5535 astate->array_type = array_type;
5536 astate->element_type = element_type;
5537
5538 return astate;
5539}
Oid get_element_type(Oid typid)
Definition: lsyscache.c:2899
#define AllocSetContextCreate
Definition: memutils.h:149
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:180
bool private_cxt
Definition: array.h:219

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, ArrayBuildStateArr::array_type, ArrayBuildStateArr::element_type, ereport, errcode(), errmsg(), ERROR, format_type_be(), get_element_type(), ArrayBuildStateArr::mcontext, MemoryContextAllocZero(), OidIsValid, and ArrayBuildStateArr::private_cxt.

Referenced by accumArrayResultArr(), array_agg_array_combine(), array_agg_array_deserialize(), array_agg_array_transfn(), and initArrayResultAny().

◆ initArrayResultWithSize()

ArrayBuildState * initArrayResultWithSize ( Oid  element_type,
MemoryContext  rcontext,
bool  subcontext,
int  initsize 
)

Definition at line 5310 of file arrayfuncs.c.

5312{
5313 ArrayBuildState *astate;
5314 MemoryContext arr_context = rcontext;
5315
5316 /* Make a temporary context to hold all the junk */
5317 if (subcontext)
5318 arr_context = AllocSetContextCreate(rcontext,
5319 "accumArrayResult",
5321
5322 astate = (ArrayBuildState *)
5323 MemoryContextAlloc(arr_context, sizeof(ArrayBuildState));
5324 astate->mcontext = arr_context;
5325 astate->private_cxt = subcontext;
5326 astate->alen = initsize;
5327 astate->dvalues = (Datum *)
5328 MemoryContextAlloc(arr_context, astate->alen * sizeof(Datum));
5329 astate->dnulls = (bool *)
5330 MemoryContextAlloc(arr_context, astate->alen * sizeof(bool));
5331 astate->nelems = 0;
5332 astate->element_type = element_type;
5333 get_typlenbyvalalign(element_type,
5334 &astate->typlen,
5335 &astate->typbyval,
5336 &astate->typalign);
5337
5338 return astate;
5339}
bool private_cxt
Definition: array.h:198
char typalign
Definition: array.h:197

References ArrayBuildState::alen, ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, ArrayBuildState::dnulls, ArrayBuildState::dvalues, ArrayBuildState::element_type, get_typlenbyvalalign(), ArrayBuildState::mcontext, MemoryContextAlloc(), ArrayBuildState::nelems, ArrayBuildState::private_cxt, ArrayBuildState::typalign, ArrayBuildState::typbyval, and ArrayBuildState::typlen.

Referenced by array_agg_combine(), array_agg_deserialize(), and initArrayResult().

◆ makeArrayResult()

Datum makeArrayResult ( ArrayBuildState astate,
MemoryContext  rcontext 
)

Definition at line 5420 of file arrayfuncs.c.

5422{
5423 int ndims;
5424 int dims[1];
5425 int lbs[1];
5426
5427 /* If no elements were presented, we want to create an empty array */
5428 ndims = (astate->nelems > 0) ? 1 : 0;
5429 dims[0] = astate->nelems;
5430 lbs[0] = 1;
5431
5432 return makeMdArrayResult(astate, ndims, dims, lbs, rcontext,
5433 astate->private_cxt);
5434}
Datum makeMdArrayResult(ArrayBuildState *astate, int ndims, int *dims, int *lbs, MemoryContext rcontext, bool release)
Definition: arrayfuncs.c:5452

References makeMdArrayResult(), ArrayBuildState::nelems, and ArrayBuildState::private_cxt.

Referenced by array_positions(), brin_minmax_multi_summary_out(), daitch_mokotoff(), dblink_get_connections(), optionListToArray(), parse_ident(), pg_get_statisticsobjdef_expressions(), pg_stats_ext_mcvlist_items(), regexp_split_to_array(), serialize_expr_stats(), text_to_array(), transformRelOptions(), tuple_data_split_internal(), and xpath().

◆ makeArrayResultAny()

Datum makeArrayResultAny ( ArrayBuildStateAny astate,
MemoryContext  rcontext,
bool  release 
)

Definition at line 5857 of file arrayfuncs.c.

5859{
5860 Datum result;
5861
5862 if (astate->scalarstate)
5863 {
5864 /* Must use makeMdArrayResult to support "release" parameter */
5865 int ndims;
5866 int dims[1];
5867 int lbs[1];
5868
5869 /* If no elements were presented, we want to create an empty array */
5870 ndims = (astate->scalarstate->nelems > 0) ? 1 : 0;
5871 dims[0] = astate->scalarstate->nelems;
5872 lbs[0] = 1;
5873
5874 result = makeMdArrayResult(astate->scalarstate, ndims, dims, lbs,
5875 rcontext, release);
5876 }
5877 else
5878 {
5879 result = makeArrayResultArr(astate->arraystate,
5880 rcontext, release);
5881 }
5882 return result;
5883}
Datum makeArrayResultArr(ArrayBuildStateArr *astate, MemoryContext rcontext, bool release)
Definition: arrayfuncs.c:5703

References ArrayBuildStateAny::arraystate, makeArrayResultArr(), makeMdArrayResult(), ArrayBuildState::nelems, and ArrayBuildStateAny::scalarstate.

Referenced by array_sort_internal(), ExecScanSubPlan(), and ExecSetParamPlan().

◆ makeArrayResultArr()

Datum makeArrayResultArr ( ArrayBuildStateArr astate,
MemoryContext  rcontext,
bool  release 
)

Definition at line 5703 of file arrayfuncs.c.

5706{
5707 ArrayType *result;
5708 MemoryContext oldcontext;
5709
5710 /* Build the final array result in rcontext */
5711 oldcontext = MemoryContextSwitchTo(rcontext);
5712
5713 if (astate->ndims == 0)
5714 {
5715 /* No inputs, return empty array */
5716 result = construct_empty_array(astate->element_type);
5717 }
5718 else
5719 {
5720 int dataoffset,
5721 nbytes;
5722
5723 /* Check for overflow of the array dimensions */
5724 (void) ArrayGetNItems(astate->ndims, astate->dims);
5725 ArrayCheckBounds(astate->ndims, astate->dims, astate->lbs);
5726
5727 /* Compute required space */
5728 nbytes = astate->nbytes;
5729 if (astate->nullbitmap != NULL)
5730 {
5731 dataoffset = ARR_OVERHEAD_WITHNULLS(astate->ndims, astate->nitems);
5732 nbytes += dataoffset;
5733 }
5734 else
5735 {
5736 dataoffset = 0;
5737 nbytes += ARR_OVERHEAD_NONULLS(astate->ndims);
5738 }
5739
5740 result = (ArrayType *) palloc0(nbytes);
5741 SET_VARSIZE(result, nbytes);
5742 result->ndim = astate->ndims;
5743 result->dataoffset = dataoffset;
5744 result->elemtype = astate->element_type;
5745
5746 memcpy(ARR_DIMS(result), astate->dims, astate->ndims * sizeof(int));
5747 memcpy(ARR_LBOUND(result), astate->lbs, astate->ndims * sizeof(int));
5748 memcpy(ARR_DATA_PTR(result), astate->data, astate->nbytes);
5749
5750 if (astate->nullbitmap != NULL)
5752 astate->nullbitmap, 0,
5753 astate->nitems);
5754 }
5755
5756 MemoryContextSwitchTo(oldcontext);
5757
5758 /* Clean up all the junk */
5759 if (release)
5760 {
5761 Assert(astate->private_cxt);
5763 }
5764
5765 return PointerGetDatum(result);
5766}
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:485

References ARR_DATA_PTR, ARR_DIMS, ARR_LBOUND, ARR_NULLBITMAP, ARR_OVERHEAD_NONULLS, ARR_OVERHEAD_WITHNULLS, array_bitmap_copy(), ArrayCheckBounds(), ArrayGetNItems(), Assert(), construct_empty_array(), ArrayBuildStateArr::data, ArrayType::dataoffset, ArrayBuildStateArr::dims, ArrayBuildStateArr::element_type, ArrayType::elemtype, ArrayBuildStateArr::lbs, ArrayBuildStateArr::mcontext, MemoryContextDelete(), MemoryContextSwitchTo(), ArrayBuildStateArr::nbytes, ArrayType::ndim, ArrayBuildStateArr::ndims, ArrayBuildStateArr::nitems, ArrayBuildStateArr::nullbitmap, palloc0(), PointerGetDatum(), ArrayBuildStateArr::private_cxt, and SET_VARSIZE.

Referenced by array_agg_array_finalfn(), and makeArrayResultAny().

◆ makeMdArrayResult()

Datum makeMdArrayResult ( ArrayBuildState astate,
int  ndims,
int *  dims,
int *  lbs,
MemoryContext  rcontext,
bool  release 
)

Definition at line 5452 of file arrayfuncs.c.

5458{
5459 ArrayType *result;
5460 MemoryContext oldcontext;
5461
5462 /* Build the final array result in rcontext */
5463 oldcontext = MemoryContextSwitchTo(rcontext);
5464
5465 result = construct_md_array(astate->dvalues,
5466 astate->dnulls,
5467 ndims,
5468 dims,
5469 lbs,
5470 astate->element_type,
5471 astate->typlen,
5472 astate->typbyval,
5473 astate->typalign);
5474
5475 MemoryContextSwitchTo(oldcontext);
5476
5477 /* Clean up all the junk */
5478 if (release)
5479 {
5480 Assert(astate->private_cxt);
5482 }
5483
5484 return PointerGetDatum(result);
5485}

References Assert(), construct_md_array(), ArrayBuildState::dnulls, ArrayBuildState::dvalues, ArrayBuildState::element_type, ArrayBuildState::mcontext, MemoryContextDelete(), MemoryContextSwitchTo(), PointerGetDatum(), ArrayBuildState::private_cxt, ArrayBuildState::typalign, ArrayBuildState::typbyval, and ArrayBuildState::typlen.

Referenced by array_agg_finalfn(), makeArrayResult(), makeArrayResultAny(), plperl_array_to_datum(), PLySequence_ToArray(), and populate_array().

◆ ReadArrayBinary()

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

Definition at line 1454 of file arrayfuncs.c.

1466{
1467 int i;
1468 bool hasnull;
1469 int32 totbytes;
1470
1471 for (i = 0; i < nitems; i++)
1472 {
1473 int itemlen;
1474 StringInfoData elem_buf;
1475
1476 /* Get and check the item length */
1477 itemlen = pq_getmsgint(buf, 4);
1478 if (itemlen < -1 || itemlen > (buf->len - buf->cursor))
1479 ereport(ERROR,
1480 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
1481 errmsg("insufficient data left in message")));
1482
1483 if (itemlen == -1)
1484 {
1485 /* -1 length means NULL */
1486 values[i] = ReceiveFunctionCall(receiveproc, NULL,
1487 typioparam, typmod);
1488 nulls[i] = true;
1489 continue;
1490 }
1491
1492 /*
1493 * Rather than copying data around, we just initialize a StringInfo
1494 * pointing to the correct portion of the message buffer.
1495 */
1496 initReadOnlyStringInfo(&elem_buf, &buf->data[buf->cursor], itemlen);
1497
1498 buf->cursor += itemlen;
1499
1500 /* Now call the element's receiveproc */
1501 values[i] = ReceiveFunctionCall(receiveproc, &elem_buf,
1502 typioparam, typmod);
1503 nulls[i] = false;
1504
1505 /* Trouble if it didn't eat the whole buffer */
1506 if (elem_buf.cursor != itemlen)
1507 ereport(ERROR,
1508 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
1509 errmsg("improper binary format in array element %d",
1510 i + 1)));
1511 }
1512
1513 /*
1514 * Check for nulls, compute total data space needed
1515 */
1516 hasnull = false;
1517 totbytes = 0;
1518 for (i = 0; i < nitems; i++)
1519 {
1520 if (nulls[i])
1521 hasnull = true;
1522 else
1523 {
1524 /* let's just make sure data is not toasted */
1525 if (typlen == -1)
1527 totbytes = att_addlength_datum(totbytes, typlen, values[i]);
1528 totbytes = att_align_nominal(totbytes, typalign);
1529 /* check for overflow of total request */
1530 if (!AllocSizeIsValid(totbytes))
1531 ereport(ERROR,
1532 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1533 errmsg("array size exceeds the maximum allowed (%d)",
1534 (int) MaxAllocSize)));
1535 }
1536 }
1537 *hasnulls = hasnull;
1538 *nbytes = totbytes;
1539}
Datum ReceiveFunctionCall(FmgrInfo *flinfo, StringInfo buf, Oid typioparam, int32 typmod)
Definition: fmgr.c:1697
static void initReadOnlyStringInfo(StringInfo str, char *data, int len)
Definition: stringinfo.h:157

References AllocSizeIsValid, att_addlength_datum, att_align_nominal, buf, StringInfoData::cursor, ereport, errcode(), errmsg(), ERROR, i, initReadOnlyStringInfo(), MaxAllocSize, nitems, PG_DETOAST_DATUM, PointerGetDatum(), pq_getmsgint(), ReceiveFunctionCall(), typalign, and values.

Referenced by array_recv().

◆ ReadArrayDimensions()

static bool ReadArrayDimensions ( char **  srcptr,
int *  ndim_p,
int *  dim,
int *  lBound,
const char *  origStr,
Node escontext 
)
static

Definition at line 402 of file arrayfuncs.c.

404{
405 char *p = *srcptr;
406 int ndim;
407
408 /*
409 * Dimension info takes the form of one or more [n] or [m:n] items. This
410 * loop iterates once per dimension item.
411 */
412 ndim = 0;
413 for (;;)
414 {
415 char *q;
416 int ub;
417 int i;
418
419 /*
420 * Note: we currently allow whitespace between, but not within,
421 * dimension items.
422 */
423 while (scanner_isspace(*p))
424 p++;
425 if (*p != '[')
426 break; /* no more dimension items */
427 p++;
428 if (ndim >= MAXDIM)
429 ereturn(escontext, false,
430 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
431 errmsg("number of array dimensions exceeds the maximum allowed (%d)",
432 MAXDIM)));
433
434 q = p;
435 if (!ReadDimensionInt(&p, &i, origStr, escontext))
436 return false;
437 if (p == q) /* no digits? */
438 ereturn(escontext, false,
439 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
440 errmsg("malformed array literal: \"%s\"", origStr),
441 errdetail("\"[\" must introduce explicitly-specified array dimensions.")));
442
443 if (*p == ':')
444 {
445 /* [m:n] format */
446 lBound[ndim] = i;
447 p++;
448 q = p;
449 if (!ReadDimensionInt(&p, &ub, origStr, escontext))
450 return false;
451 if (p == q) /* no digits? */
452 ereturn(escontext, false,
453 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
454 errmsg("malformed array literal: \"%s\"", origStr),
455 errdetail("Missing array dimension value.")));
456 }
457 else
458 {
459 /* [n] format */
460 lBound[ndim] = 1;
461 ub = i;
462 }
463 if (*p != ']')
464 ereturn(escontext, false,
465 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
466 errmsg("malformed array literal: \"%s\"", origStr),
467 errdetail("Missing \"%s\" after array dimensions.",
468 "]")));
469 p++;
470
471 /*
472 * Note: we could accept ub = lb-1 to represent a zero-length
473 * dimension. However, that would result in an empty array, for which
474 * we don't keep any dimension data, so that e.g. [1:0] and [101:100]
475 * would be equivalent. Given the lack of field demand, there seems
476 * little point in allowing such cases.
477 */
478 if (ub < lBound[ndim])
479 ereturn(escontext, false,
480 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
481 errmsg("upper bound cannot be less than lower bound")));
482
483 /* Upper bound of INT_MAX must be disallowed, cf ArrayCheckBounds() */
484 if (ub == INT_MAX)
485 ereturn(escontext, false,
486 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
487 errmsg("array upper bound is too large: %d", ub)));
488
489 /* Compute "ub - lBound[ndim] + 1", detecting overflow */
490 if (pg_sub_s32_overflow(ub, lBound[ndim], &ub) ||
491 pg_add_s32_overflow(ub, 1, &ub))
492 ereturn(escontext, false,
493 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
494 errmsg("array size exceeds the maximum allowed (%d)",
495 (int) MaxArraySize)));
496
497 dim[ndim] = ub;
498 ndim++;
499 }
500
501 *srcptr = p;
502 *ndim_p = ndim;
503 return true;
504}
static bool ReadDimensionInt(char **srcptr, int *result, const char *origStr, Node *escontext)
Definition: arrayfuncs.c:519

References ereturn, errcode(), errdetail(), errmsg(), i, MaxArraySize, MAXDIM, pg_add_s32_overflow(), pg_sub_s32_overflow(), ReadDimensionInt(), and scanner_isspace().

Referenced by array_in().

◆ ReadArrayStr()

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

Definition at line 579 of file arrayfuncs.c.

594{
595 int ndim = *ndim_p;
596 bool dimensions_specified = (ndim != 0);
597 int maxitems;
598 Datum *values;
599 bool *nulls;
600 StringInfoData elembuf;
601 int nest_level;
602 int nitems;
603 bool ndim_frozen;
604 bool expect_delim;
605 int nelems[MAXDIM];
606
607 /* Allocate some starting output workspace; we'll enlarge as needed */
608 maxitems = 16;
609 values = palloc_array(Datum, maxitems);
610 nulls = palloc_array(bool, maxitems);
611
612 /* Allocate workspace to hold (string representation of) one element */
613 initStringInfo(&elembuf);
614
615 /* Loop below assumes first token is ATOK_LEVEL_START */
616 Assert(**srcptr == '{');
617
618 /* Parse tokens until we reach the matching right brace */
619 nest_level = 0;
620 nitems = 0;
621 ndim_frozen = dimensions_specified;
622 expect_delim = false;
623 do
624 {
625 ArrayToken tok;
626
627 tok = ReadArrayToken(srcptr, &elembuf, typdelim, origStr, escontext);
628
629 switch (tok)
630 {
631 case ATOK_LEVEL_START:
632 /* Can't write left brace where delim is expected */
633 if (expect_delim)
634 ereturn(escontext, false,
635 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
636 errmsg("malformed array literal: \"%s\"", origStr),
637 errdetail("Unexpected \"%c\" character.", '{')));
638
639 /* Initialize element counting in the new level */
640 if (nest_level >= MAXDIM)
641 ereturn(escontext, false,
642 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
643 errmsg("number of array dimensions exceeds the maximum allowed (%d)",
644 MAXDIM)));
645
646 nelems[nest_level] = 0;
647 nest_level++;
648 if (nest_level > ndim)
649 {
650 /* Can't increase ndim once it's frozen */
651 if (ndim_frozen)
652 goto dimension_error;
653 ndim = nest_level;
654 }
655 break;
656
657 case ATOK_LEVEL_END:
658 /* Can't get here with nest_level == 0 */
659 Assert(nest_level > 0);
660
661 /*
662 * We allow a right brace to terminate an empty sub-array,
663 * otherwise it must occur where we expect a delimiter.
664 */
665 if (nelems[nest_level - 1] > 0 && !expect_delim)
666 ereturn(escontext, false,
667 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
668 errmsg("malformed array literal: \"%s\"", origStr),
669 errdetail("Unexpected \"%c\" character.",
670 '}')));
671 nest_level--;
672 /* Nested sub-arrays count as elements of outer level */
673 if (nest_level > 0)
674 nelems[nest_level - 1]++;
675
676 /*
677 * Note: if we had dimensionality info, then dim[nest_level]
678 * is initially non-negative, and we'll check each sub-array's
679 * length against that.
680 */
681 if (dim[nest_level] < 0)
682 {
683 /* Save length of first sub-array of this level */
684 dim[nest_level] = nelems[nest_level];
685 }
686 else if (nelems[nest_level] != dim[nest_level])
687 {
688 /* Subsequent sub-arrays must have same length */
689 goto dimension_error;
690 }
691
692 /*
693 * Must have a delim or another right brace following, unless
694 * we have reached nest_level 0, where this won't matter.
695 */
696 expect_delim = true;
697 break;
698
699 case ATOK_DELIM:
700 if (!expect_delim)
701 ereturn(escontext, false,
702 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
703 errmsg("malformed array literal: \"%s\"", origStr),
704 errdetail("Unexpected \"%c\" character.",
705 typdelim)));
706 expect_delim = false;
707 break;
708
709 case ATOK_ELEM:
710 case ATOK_ELEM_NULL:
711 /* Can't get here with nest_level == 0 */
712 Assert(nest_level > 0);
713
714 /* Disallow consecutive ELEM tokens */
715 if (expect_delim)
716 ereturn(escontext, false,
717 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
718 errmsg("malformed array literal: \"%s\"", origStr),
719 errdetail("Unexpected array element.")));
720
721 /* Enlarge the values/nulls arrays if needed */
722 if (nitems >= maxitems)
723 {
724 if (maxitems >= MaxArraySize)
725 ereturn(escontext, false,
726 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
727 errmsg("array size exceeds the maximum allowed (%d)",
728 (int) MaxArraySize)));
729 maxitems = Min(maxitems * 2, MaxArraySize);
730 values = repalloc_array(values, Datum, maxitems);
731 nulls = repalloc_array(nulls, bool, maxitems);
732 }
733
734 /* Read the element's value, or check that NULL is allowed */
735 if (!InputFunctionCallSafe(inputproc,
736 (tok == ATOK_ELEM_NULL) ? NULL : elembuf.data,
737 typioparam, typmod,
738 escontext,
739 &values[nitems]))
740 return false;
741 nulls[nitems] = (tok == ATOK_ELEM_NULL);
742 nitems++;
743
744 /*
745 * Once we have found an element, the number of dimensions can
746 * no longer increase, and subsequent elements must all be at
747 * the same nesting depth.
748 */
749 ndim_frozen = true;
750 if (nest_level != ndim)
751 goto dimension_error;
752 /* Count the new element */
753 nelems[nest_level - 1]++;
754
755 /* Must have a delim or a right brace following */
756 expect_delim = true;
757 break;
758
759 case ATOK_ERROR:
760 return false;
761 }
762 } while (nest_level > 0);
763
764 /* Clean up and return results */
765 pfree(elembuf.data);
766
767 *ndim_p = ndim;
768 *nitems_p = nitems;
769 *values_p = values;
770 *nulls_p = nulls;
771 return true;
772
773dimension_error:
774 if (dimensions_specified)
775 ereturn(escontext, false,
776 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
777 errmsg("malformed array literal: \"%s\"", origStr),
778 errdetail("Specified array dimensions do not match array contents.")));
779 else
780 ereturn(escontext, false,
781 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
782 errmsg("malformed array literal: \"%s\"", origStr),
783 errdetail("Multidimensional arrays must have sub-arrays with matching dimensions.")));
784}
static ArrayToken ReadArrayToken(char **srcptr, StringInfo elembuf, char typdelim, const char *origStr, Node *escontext)
Definition: arrayfuncs.c:796
#define repalloc_array(pointer, type, count)
Definition: fe_memutils.h:78
#define palloc_array(type, count)
Definition: fe_memutils.h:76
bool InputFunctionCallSafe(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod, fmNodePtr escontext, Datum *result)
Definition: fmgr.c:1585
void initStringInfo(StringInfo str)
Definition: stringinfo.c:97

References Assert(), ATOK_DELIM, ATOK_ELEM, ATOK_ELEM_NULL, ATOK_ERROR, ATOK_LEVEL_END, ATOK_LEVEL_START, StringInfoData::data, ereturn, errcode(), errdetail(), errmsg(), initStringInfo(), InputFunctionCallSafe(), MaxArraySize, MAXDIM, Min, nitems, palloc_array, pfree(), ReadArrayToken(), repalloc_array, and values.

Referenced by array_in().

◆ ReadArrayToken()

static ArrayToken ReadArrayToken ( char **  srcptr,
StringInfo  elembuf,
char  typdelim,
const char *  origStr,
Node escontext 
)
static

Definition at line 796 of file arrayfuncs.c.

798{
799 char *p = *srcptr;
800 int dstlen;
801 bool has_escapes;
802
803 resetStringInfo(elembuf);
804
805 /* Identify token type. Loop advances over leading whitespace. */
806 for (;;)
807 {
808 switch (*p)
809 {
810 case '\0':
811 goto ending_error;
812 case '{':
813 *srcptr = p + 1;
814 return ATOK_LEVEL_START;
815 case '}':
816 *srcptr = p + 1;
817 return ATOK_LEVEL_END;
818 case '"':
819 p++;
820 goto quoted_element;
821 default:
822 if (*p == typdelim)
823 {
824 *srcptr = p + 1;
825 return ATOK_DELIM;
826 }
827 if (scanner_isspace(*p))
828 {
829 p++;
830 continue;
831 }
832 goto unquoted_element;
833 }
834 }
835
836quoted_element:
837 for (;;)
838 {
839 switch (*p)
840 {
841 case '\0':
842 goto ending_error;
843 case '\\':
844 /* Skip backslash, copy next character as-is. */
845 p++;
846 if (*p == '\0')
847 goto ending_error;
848 appendStringInfoChar(elembuf, *p++);
849 break;
850 case '"':
851
852 /*
853 * If next non-whitespace isn't typdelim or a brace, complain
854 * about incorrect quoting. While we could leave such cases
855 * to be detected as incorrect token sequences, the resulting
856 * message wouldn't be as helpful. (We could also give the
857 * incorrect-quoting error when next is '{', but treating that
858 * as a token sequence error seems better.)
859 */
860 while (*(++p) != '\0')
861 {
862 if (*p == typdelim || *p == '}' || *p == '{')
863 {
864 *srcptr = p;
865 return ATOK_ELEM;
866 }
867 if (!scanner_isspace(*p))
868 ereturn(escontext, ATOK_ERROR,
869 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
870 errmsg("malformed array literal: \"%s\"", origStr),
871 errdetail("Incorrectly quoted array element.")));
872 }
873 goto ending_error;
874 default:
875 appendStringInfoChar(elembuf, *p++);
876 break;
877 }
878 }
879
880unquoted_element:
881
882 /*
883 * We don't include trailing whitespace in the result. dstlen tracks how
884 * much of the output string is known to not be trailing whitespace.
885 */
886 dstlen = 0;
887 has_escapes = false;
888 for (;;)
889 {
890 switch (*p)
891 {
892 case '\0':
893 goto ending_error;
894 case '{':
895 ereturn(escontext, ATOK_ERROR,
896 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
897 errmsg("malformed array literal: \"%s\"", origStr),
898 errdetail("Unexpected \"%c\" character.",
899 '{')));
900 case '"':
901 /* Must double-quote all or none of an element. */
902 ereturn(escontext, ATOK_ERROR,
903 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
904 errmsg("malformed array literal: \"%s\"", origStr),
905 errdetail("Incorrectly quoted array element.")));
906 case '\\':
907 /* Skip backslash, copy next character as-is. */
908 p++;
909 if (*p == '\0')
910 goto ending_error;
911 appendStringInfoChar(elembuf, *p++);
912 dstlen = elembuf->len; /* treat it as non-whitespace */
913 has_escapes = true;
914 break;
915 default:
916 /* End of elem? */
917 if (*p == typdelim || *p == '}')
918 {
919 /* hack: truncate the output string to dstlen */
920 elembuf->data[dstlen] = '\0';
921 elembuf->len = dstlen;
922 *srcptr = p;
923 /* Check if it's unquoted "NULL" */
924 if (Array_nulls && !has_escapes &&
925 pg_strcasecmp(elembuf->data, "NULL") == 0)
926 return ATOK_ELEM_NULL;
927 else
928 return ATOK_ELEM;
929 }
930 appendStringInfoChar(elembuf, *p);
931 if (!scanner_isspace(*p))
932 dstlen = elembuf->len;
933 p++;
934 break;
935 }
936 }
937
938ending_error:
939 ereturn(escontext, ATOK_ERROR,
940 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
941 errmsg("malformed array literal: \"%s\"", origStr),
942 errdetail("Unexpected end of input.")));
943}
bool Array_nulls
Definition: arrayfuncs.c:43
void resetStringInfo(StringInfo str)
Definition: stringinfo.c:126
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:242

References appendStringInfoChar(), Array_nulls, ATOK_DELIM, ATOK_ELEM, ATOK_ELEM_NULL, ATOK_ERROR, ATOK_LEVEL_END, ATOK_LEVEL_START, StringInfoData::data, ereturn, errcode(), errdetail(), errmsg(), StringInfoData::len, pg_strcasecmp(), resetStringInfo(), and scanner_isspace().

Referenced by ReadArrayStr().

◆ ReadDimensionInt()

static bool ReadDimensionInt ( char **  srcptr,
int *  result,
const char *  origStr,
Node escontext 
)
static

Definition at line 519 of file arrayfuncs.c.

521{
522 char *p = *srcptr;
523 long l;
524
525 /* don't accept leading whitespace */
526 if (!isdigit((unsigned char) *p) && *p != '-' && *p != '+')
527 {
528 *result = 0;
529 return true;
530 }
531
532 errno = 0;
533 l = strtol(p, srcptr, 10);
534
535 if (errno == ERANGE || l > PG_INT32_MAX || l < PG_INT32_MIN)
536 ereturn(escontext, false,
537 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
538 errmsg("array bound is out of integer range")));
539
540 *result = (int) l;
541 return true;
542}
#define PG_INT32_MAX
Definition: c.h:560
#define PG_INT32_MIN
Definition: c.h:559

References ereturn, errcode(), errmsg(), PG_INT32_MAX, and PG_INT32_MIN.

Referenced by ReadArrayDimensions().

◆ trim_array()

Datum trim_array ( PG_FUNCTION_ARGS  )

Definition at line 6922 of file arrayfuncs.c.

6923{
6925 int n = PG_GETARG_INT32(1);
6926 int array_length = (ARR_NDIM(v) > 0) ? ARR_DIMS(v)[0] : 0;
6927 int16 elmlen;
6928 bool elmbyval;
6929 char elmalign;
6930 int lower[MAXDIM];
6931 int upper[MAXDIM];
6932 bool lowerProvided[MAXDIM];
6933 bool upperProvided[MAXDIM];
6934 Datum result;
6935
6936 /* Per spec, throw an error if out of bounds */
6937 if (n < 0 || n > array_length)
6938 ereport(ERROR,
6939 (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
6940 errmsg("number of elements to trim must be between 0 and %d",
6941 array_length)));
6942
6943 /* Set all the bounds as unprovided except the first upper bound */
6944 memset(lowerProvided, false, sizeof(lowerProvided));
6945 memset(upperProvided, false, sizeof(upperProvided));
6946 if (ARR_NDIM(v) > 0)
6947 {
6948 upper[0] = ARR_LBOUND(v)[0] + array_length - n - 1;
6949 upperProvided[0] = true;
6950 }
6951
6952 /* Fetch the needed information about the element type */
6953 get_typlenbyvalalign(ARR_ELEMTYPE(v), &elmlen, &elmbyval, &elmalign);
6954
6955 /* Get the slice */
6956 result = array_get_slice(PointerGetDatum(v), 1,
6957 upper, lower, upperProvided, lowerProvided,
6958 -1, elmlen, elmbyval, elmalign);
6959
6960 PG_RETURN_DATUM(result);
6961}
Datum array_length(PG_FUNCTION_ARGS)
Definition: arrayfuncs.c:1763
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: arrayfuncs.c:2030
Datum lower(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:49
Datum upper(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:80

References ARR_DIMS, ARR_ELEMTYPE, ARR_LBOUND, ARR_NDIM, array_get_slice(), array_length(), ereport, errcode(), errmsg(), ERROR, get_typlenbyvalalign(), lower(), MAXDIM, PG_GETARG_ARRAYTYPE_P, PG_GETARG_INT32, PG_RETURN_DATUM, PointerGetDatum(), and upper().

◆ width_bucket_array()

Datum width_bucket_array ( PG_FUNCTION_ARGS  )

Definition at line 6690 of file arrayfuncs.c.

6691{
6692 Datum operand = PG_GETARG_DATUM(0);
6693 ArrayType *thresholds = PG_GETARG_ARRAYTYPE_P(1);
6694 Oid collation = PG_GET_COLLATION();
6695 Oid element_type = ARR_ELEMTYPE(thresholds);
6696 int result;
6697
6698 /* Check input */
6699 if (ARR_NDIM(thresholds) > 1)
6700 ereport(ERROR,
6701 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
6702 errmsg("thresholds must be one-dimensional array")));
6703
6704 if (array_contains_nulls(thresholds))
6705 ereport(ERROR,
6706 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
6707 errmsg("thresholds array must not contain NULLs")));
6708
6709 /* We have a dedicated implementation for float8 data */
6710 if (element_type == FLOAT8OID)
6711 result = width_bucket_array_float8(operand, thresholds);
6712 else
6713 {
6714 TypeCacheEntry *typentry;
6715
6716 /* Cache information about the input type */
6717 typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
6718 if (typentry == NULL ||
6719 typentry->type_id != element_type)
6720 {
6721 typentry = lookup_type_cache(element_type,
6723 if (!OidIsValid(typentry->cmp_proc_finfo.fn_oid))
6724 ereport(ERROR,
6725 (errcode(ERRCODE_UNDEFINED_FUNCTION),
6726 errmsg("could not identify a comparison function for type %s",
6727 format_type_be(element_type))));
6728 fcinfo->flinfo->fn_extra = typentry;
6729 }
6730
6731 /*
6732 * We have separate implementation paths for fixed- and variable-width
6733 * types, since indexing the array is a lot cheaper in the first case.
6734 */
6735 if (typentry->typlen > 0)
6736 result = width_bucket_array_fixed(operand, thresholds,
6737 collation, typentry);
6738 else
6739 result = width_bucket_array_variable(operand, thresholds,
6740 collation, typentry);
6741 }
6742
6743 /* Avoid leaking memory when handed toasted input. */
6744 PG_FREE_IF_COPY(thresholds, 1);
6745
6746 PG_RETURN_INT32(result);
6747}
static int width_bucket_array_float8(Datum operand, ArrayType *thresholds)
Definition: arrayfuncs.c:6753
static int width_bucket_array_fixed(Datum operand, ArrayType *thresholds, Oid collation, TypeCacheEntry *typentry)
Definition: arrayfuncs.c:6797
static int width_bucket_array_variable(Datum operand, ArrayType *thresholds, Oid collation, TypeCacheEntry *typentry)
Definition: arrayfuncs.c:6852
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:260

References ARR_ELEMTYPE, ARR_NDIM, array_contains_nulls(), TypeCacheEntry::cmp_proc_finfo, ereport, errcode(), errmsg(), ERROR, FmgrInfo::fn_oid, format_type_be(), if(), lookup_type_cache(), OidIsValid, PG_FREE_IF_COPY, PG_GET_COLLATION, PG_GETARG_ARRAYTYPE_P, PG_GETARG_DATUM, PG_RETURN_INT32, TypeCacheEntry::type_id, TYPECACHE_CMP_PROC_FINFO, TypeCacheEntry::typlen, width_bucket_array_fixed(), width_bucket_array_float8(), and width_bucket_array_variable().

◆ width_bucket_array_fixed()

static int width_bucket_array_fixed ( Datum  operand,
ArrayType thresholds,
Oid  collation,
TypeCacheEntry typentry 
)
static

Definition at line 6797 of file arrayfuncs.c.

6801{
6802 LOCAL_FCINFO(locfcinfo, 2);
6803 char *thresholds_data;
6804 int typlen = typentry->typlen;
6805 bool typbyval = typentry->typbyval;
6806 int left;
6807 int right;
6808
6809 /*
6810 * Since we know the array contains no NULLs, we can just index it
6811 * directly.
6812 */
6813 thresholds_data = (char *) ARR_DATA_PTR(thresholds);
6814
6815 InitFunctionCallInfoData(*locfcinfo, &typentry->cmp_proc_finfo, 2,
6816 collation, NULL, NULL);
6817
6818 /* Find the bucket */
6819 left = 0;
6820 right = ArrayGetNItems(ARR_NDIM(thresholds), ARR_DIMS(thresholds));
6821 while (left < right)
6822 {
6823 int mid = (left + right) / 2;
6824 char *ptr;
6825 int32 cmpresult;
6826
6827 ptr = thresholds_data + mid * typlen;
6828
6829 locfcinfo->args[0].value = operand;
6830 locfcinfo->args[0].isnull = false;
6831 locfcinfo->args[1].value = fetch_att(ptr, typbyval, typlen);
6832 locfcinfo->args[1].isnull = false;
6833
6834 cmpresult = DatumGetInt32(FunctionCallInvoke(locfcinfo));
6835
6836 /* We don't expect comparison support functions to return null */
6837 Assert(!locfcinfo->isnull);
6838
6839 if (cmpresult < 0)
6840 right = mid;
6841 else
6842 left = mid + 1;
6843 }
6844
6845 return left;
6846}

References ARR_DATA_PTR, ARR_DIMS, ARR_NDIM, ArrayGetNItems(), Assert(), TypeCacheEntry::cmp_proc_finfo, DatumGetInt32(), fetch_att(), FunctionCallInvoke, InitFunctionCallInfoData, LOCAL_FCINFO, TypeCacheEntry::typbyval, and TypeCacheEntry::typlen.

Referenced by width_bucket_array().

◆ width_bucket_array_float8()

static int width_bucket_array_float8 ( Datum  operand,
ArrayType thresholds 
)
static

Definition at line 6753 of file arrayfuncs.c.

6754{
6755 float8 op = DatumGetFloat8(operand);
6756 float8 *thresholds_data;
6757 int left;
6758 int right;
6759
6760 /*
6761 * Since we know the array contains no NULLs, we can just index it
6762 * directly.
6763 */
6764 thresholds_data = (float8 *) ARR_DATA_PTR(thresholds);
6765
6766 left = 0;
6767 right = ArrayGetNItems(ARR_NDIM(thresholds), ARR_DIMS(thresholds));
6768
6769 /*
6770 * If the probe value is a NaN, it's greater than or equal to all possible
6771 * threshold values (including other NaNs), so we need not search. Note
6772 * that this would give the same result as searching even if the array
6773 * contains multiple NaNs (as long as they're correctly sorted), since the
6774 * loop logic will find the rightmost of multiple equal threshold values.
6775 */
6776 if (isnan(op))
6777 return right;
6778
6779 /* Find the bucket */
6780 while (left < right)
6781 {
6782 int mid = (left + right) / 2;
6783
6784 if (isnan(thresholds_data[mid]) || op < thresholds_data[mid])
6785 right = mid;
6786 else
6787 left = mid + 1;
6788 }
6789
6790 return left;
6791}
static float8 DatumGetFloat8(Datum X)
Definition: postgres.h:499

References ARR_DATA_PTR, ARR_DIMS, ARR_NDIM, ArrayGetNItems(), and DatumGetFloat8().

Referenced by width_bucket_array().

◆ width_bucket_array_variable()

static int width_bucket_array_variable ( Datum  operand,
ArrayType thresholds,
Oid  collation,
TypeCacheEntry typentry 
)
static

Definition at line 6852 of file arrayfuncs.c.

6856{
6857 LOCAL_FCINFO(locfcinfo, 2);
6858 char *thresholds_data;
6859 int typlen = typentry->typlen;
6860 bool typbyval = typentry->typbyval;
6861 char typalign = typentry->typalign;
6862 int left;
6863 int right;
6864
6865 thresholds_data = (char *) ARR_DATA_PTR(thresholds);
6866
6867 InitFunctionCallInfoData(*locfcinfo, &typentry->cmp_proc_finfo, 2,
6868 collation, NULL, NULL);
6869
6870 /* Find the bucket */
6871 left = 0;
6872 right = ArrayGetNItems(ARR_NDIM(thresholds), ARR_DIMS(thresholds));
6873 while (left < right)
6874 {
6875 int mid = (left + right) / 2;
6876 char *ptr;
6877 int i;
6878 int32 cmpresult;
6879
6880 /* Locate mid'th array element by advancing from left element */
6881 ptr = thresholds_data;
6882 for (i = left; i < mid; i++)
6883 {
6884 ptr = att_addlength_pointer(ptr, typlen, ptr);
6885 ptr = (char *) att_align_nominal(ptr, typalign);
6886 }
6887
6888 locfcinfo->args[0].value = operand;
6889 locfcinfo->args[0].isnull = false;
6890 locfcinfo->args[1].value = fetch_att(ptr, typbyval, typlen);
6891 locfcinfo->args[1].isnull = false;
6892
6893 cmpresult = DatumGetInt32(FunctionCallInvoke(locfcinfo));
6894
6895 /* We don't expect comparison support functions to return null */
6896 Assert(!locfcinfo->isnull);
6897
6898 if (cmpresult < 0)
6899 right = mid;
6900 else
6901 {
6902 left = mid + 1;
6903
6904 /*
6905 * Move the thresholds pointer to match new "left" index, so we
6906 * don't have to seek over those elements again. This trick
6907 * ensures we do only O(N) array indexing work, not O(N^2).
6908 */
6909 ptr = att_addlength_pointer(ptr, typlen, ptr);
6910 thresholds_data = (char *) att_align_nominal(ptr, typalign);
6911 }
6912 }
6913
6914 return left;
6915}

References ARR_DATA_PTR, ARR_DIMS, ARR_NDIM, ArrayGetNItems(), Assert(), att_addlength_pointer, att_align_nominal, TypeCacheEntry::cmp_proc_finfo, DatumGetInt32(), fetch_att(), FunctionCallInvoke, i, InitFunctionCallInfoData, LOCAL_FCINFO, typalign, TypeCacheEntry::typalign, TypeCacheEntry::typbyval, and TypeCacheEntry::typlen.

Referenced by width_bucket_array().

Variable Documentation

◆ Array_nulls

bool Array_nulls = true

Definition at line 43 of file arrayfuncs.c.

Referenced by ReadArrayToken().