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 "access/transam.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 51 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 49 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 58 of file arrayfuncs.c.

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

Function Documentation

◆ accumArrayResult()

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

Definition at line 5351 of file arrayfuncs.c.

5355{
5356 MemoryContext oldcontext;
5357
5358 if (astate == NULL)
5359 {
5360 /* First time through --- initialize */
5361 astate = initArrayResult(element_type, rcontext, true);
5362 }
5363 else
5364 {
5365 Assert(astate->element_type == element_type);
5366 }
5367
5368 oldcontext = MemoryContextSwitchTo(astate->mcontext);
5369
5370 /* enlarge dvalues[]/dnulls[] if needed */
5371 if (astate->nelems >= astate->alen)
5372 {
5373 astate->alen *= 2;
5374 /* give an array-related error if we go past MaxAllocSize */
5375 if (!AllocSizeIsValid(astate->alen * sizeof(Datum)))
5376 ereport(ERROR,
5377 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
5378 errmsg("array size exceeds the maximum allowed (%d)",
5379 (int) MaxAllocSize)));
5380 astate->dvalues = (Datum *)
5381 repalloc(astate->dvalues, astate->alen * sizeof(Datum));
5382 astate->dnulls = (bool *)
5383 repalloc(astate->dnulls, astate->alen * sizeof(bool));
5384 }
5385
5386 /*
5387 * Ensure pass-by-ref stuff is copied into mcontext; and detoast it too if
5388 * it's varlena. (You might think that detoasting is not needed here
5389 * because construct_md_array can detoast the array elements later.
5390 * However, we must not let construct_md_array modify the ArrayBuildState
5391 * because that would mean array_agg_finalfn damages its input, which is
5392 * verboten. Also, this way frequently saves one copying step.)
5393 */
5394 if (!disnull && !astate->typbyval)
5395 {
5396 if (astate->typlen == -1)
5397 dvalue = PointerGetDatum(PG_DETOAST_DATUM_COPY(dvalue));
5398 else
5399 dvalue = datumCopy(dvalue, astate->typbyval, astate->typlen);
5400 }
5401
5402 astate->dvalues[astate->nelems] = dvalue;
5403 astate->dnulls[astate->nelems] = disnull;
5404 astate->nelems++;
5405
5406 MemoryContextSwitchTo(oldcontext);
5407
5408 return astate;
5409}
ArrayBuildState * initArrayResult(Oid element_type, MemoryContext rcontext, bool subcontext)
Definition: arrayfuncs.c:5294
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:150
#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:1610
#define AllocSizeIsValid(size)
Definition: memutils.h:42
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:332
uint64_t Datum
Definition: postgres.h:70
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 5830 of file arrayfuncs.c.

5834{
5835 if (astate == NULL)
5836 astate = initArrayResultAny(input_type, rcontext, true);
5837
5838 if (astate->scalarstate)
5839 (void) accumArrayResult(astate->scalarstate,
5840 dvalue, disnull,
5841 input_type, rcontext);
5842 else
5843 (void) accumArrayResultArr(astate->arraystate,
5844 dvalue, disnull,
5845 input_type, rcontext);
5846
5847 return astate;
5848}
ArrayBuildState * accumArrayResult(ArrayBuildState *astate, Datum dvalue, bool disnull, Oid element_type, MemoryContext rcontext)
Definition: arrayfuncs.c:5351
ArrayBuildStateAny * initArrayResultAny(Oid input_type, MemoryContext rcontext, bool subcontext)
Definition: arrayfuncs.c:5783
ArrayBuildStateArr * accumArrayResultArr(ArrayBuildStateArr *astate, Datum dvalue, bool disnull, Oid array_type, MemoryContext rcontext)
Definition: arrayfuncs.c:5551
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 5551 of file arrayfuncs.c.

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

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

Referenced by accumArrayResultAny(), and array_agg_array_transfn().

◆ array_bitmap_copy()

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

Definition at line 4967 of file arrayfuncs.c.

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

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

1792{
1794
1796}
#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 3986 of file arrayfuncs.c.

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

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

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

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

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

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

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

1670{
1672 char *p;
1673 int i;
1674 int *dimv,
1675 *lb;
1676
1677 /*
1678 * 33 since we assume 15 digits per number + ':' +'[]'
1679 *
1680 * +1 for trailing null
1681 */
1682 char buf[MAXDIM * 33 + 1];
1683
1684 /* Sanity check: does it look like an array at all? */
1685 if (AARR_NDIM(v) <= 0 || AARR_NDIM(v) > MAXDIM)
1687
1688 dimv = AARR_DIMS(v);
1689 lb = AARR_LBOUND(v);
1690
1691 p = buf;
1692 for (i = 0; i < AARR_NDIM(v); i++)
1693 {
1694 sprintf(p, "[%d:%d]", lb[i], dimv[i] + lb[i] - 1);
1695 p += strlen(p);
1696 }
1697
1699}
#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:181

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

References array_cmp(), and PG_RETURN_BOOL.

◆ array_in()

Datum array_in ( PG_FUNCTION_ARGS  )

Definition at line 180 of file arrayfuncs.c.

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

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

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

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

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

5889{
5890 if (array_cmp(fcinfo) > 0)
5892 else
5894}
#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 3962 of file arrayfuncs.c.

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

References array_cmp(), and PG_RETURN_BOOL.

◆ array_length()

Datum array_length ( PG_FUNCTION_ARGS  )

Definition at line 1764 of file arrayfuncs.c.

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

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

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

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

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

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

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

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

1654{
1656
1657 /* Sanity check: does it look like an array at all? */
1658 if (AARR_NDIM(v) <= 0 || AARR_NDIM(v) > MAXDIM)
1660
1662}

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

3945{
3947}
Datum array_eq(PG_FUNCTION_ARGS)
Definition: arrayfuncs.c:3815

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

5898{
5899 if (array_cmp(fcinfo) < 0)
5901 else
5903}

References array_cmp(), PG_GETARG_DATUM, and PG_RETURN_DATUM.

◆ array_unnest()

Datum array_unnest ( PG_FUNCTION_ARGS  )

Definition at line 6255 of file arrayfuncs.c.

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

6347{
6348 Node *rawreq = (Node *) PG_GETARG_POINTER(0);
6349 Node *ret = NULL;
6350
6351 if (IsA(rawreq, SupportRequestRows))
6352 {
6353 /* Try to estimate the number of rows returned */
6354 SupportRequestRows *req = (SupportRequestRows *) rawreq;
6355
6356 if (is_funcclause(req->node)) /* be paranoid */
6357 {
6358 List *args = ((FuncExpr *) req->node)->args;
6359 Node *arg1;
6360
6361 /* We can use estimated argument values here */
6363
6364 req->rows = estimate_array_length(req->root, arg1);
6365 ret = (Node *) req;
6366 }
6367 }
6368
6369 PG_RETURN_POINTER(ret);
6370}
Node * estimate_expression_value(PlannerInfo *root, Node *node)
Definition: clauses.c:2403
#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:2154
Definition: pg_list.h:54
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 1734 of file arrayfuncs.c.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

◆ construct_empty_array()

◆ construct_empty_expanded_array()

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

Definition at line 3598 of file arrayfuncs.c.

3601{
3602 ArrayType *array = construct_empty_array(element_type);
3603 Datum d;
3604
3605 d = expand_array(PointerGetDatum(array), parentcontext, metacache);
3606 pfree(array);
3607 return (ExpandedArrayHeader *) DatumGetEOHP(d);
3608}
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 3495 of file arrayfuncs.c.

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

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

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

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

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

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

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

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(), test_bms_overlap_list(), and text_format().

◆ deconstruct_array_builtin()

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

Definition at line 3698 of file arrayfuncs.c.

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

References deconstruct_array(), elog, and ERROR.

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

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

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

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

References generate_subscripts().

◆ hash_array()

Datum hash_array ( PG_FUNCTION_ARGS  )

Definition at line 4159 of file arrayfuncs.c.

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

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

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

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

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

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

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

5313{
5314 ArrayBuildState *astate;
5315 MemoryContext arr_context = rcontext;
5316
5317 /* Make a temporary context to hold all the junk */
5318 if (subcontext)
5319 arr_context = AllocSetContextCreate(rcontext,
5320 "accumArrayResult",
5322
5323 astate = (ArrayBuildState *)
5324 MemoryContextAlloc(arr_context, sizeof(ArrayBuildState));
5325 astate->mcontext = arr_context;
5326 astate->private_cxt = subcontext;
5327 astate->alen = initsize;
5328 astate->dvalues = (Datum *)
5329 MemoryContextAlloc(arr_context, astate->alen * sizeof(Datum));
5330 astate->dnulls = (bool *)
5331 MemoryContextAlloc(arr_context, astate->alen * sizeof(bool));
5332 astate->nelems = 0;
5333 astate->element_type = element_type;
5334 get_typlenbyvalalign(element_type,
5335 &astate->typlen,
5336 &astate->typbyval,
5337 &astate->typalign);
5338
5339 return astate;
5340}
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 5421 of file arrayfuncs.c.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Referenced by ReadArrayToken().