PostgreSQL Source Code git master
Loading...
Searching...
No Matches
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, uint8 typalignby, char *dest)
 
static chararray_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, const Datum *values, const 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 (const ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
 
void deconstruct_array_builtin (const ArrayType *array, Oid elmtype, Datum **elemsp, bool **nullsp, int *nelemsp)
 
bool array_contains_nulls (const 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)
static int fb(int x)

Definition at line 51 of file arrayfuncs.c.

52 { \
54 PG_FREE_IF_COPY(array, n); \
55 } while (0)

◆ 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

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

5369{
5370 MemoryContext oldcontext;
5371
5372 if (astate == NULL)
5373 {
5374 /* First time through --- initialize */
5375 astate = initArrayResult(element_type, rcontext, true);
5376 }
5377 else
5378 {
5379 Assert(astate->element_type == element_type);
5380 }
5381
5382 oldcontext = MemoryContextSwitchTo(astate->mcontext);
5383
5384 /* enlarge dvalues[]/dnulls[] if needed */
5385 if (astate->nelems >= astate->alen)
5386 {
5387 astate->alen *= 2;
5388 /* give an array-related error if we go past MaxAllocSize */
5389 if (!AllocSizeIsValid(astate->alen * sizeof(Datum)))
5390 ereport(ERROR,
5392 errmsg("array size exceeds the maximum allowed (%zu)",
5393 MaxAllocSize)));
5394 astate->dvalues = (Datum *)
5395 repalloc(astate->dvalues, astate->alen * sizeof(Datum));
5396 astate->dnulls = (bool *)
5397 repalloc(astate->dnulls, astate->alen * sizeof(bool));
5398 }
5399
5400 /*
5401 * Ensure pass-by-ref stuff is copied into mcontext; and detoast it too if
5402 * it's varlena. (You might think that detoasting is not needed here
5403 * because construct_md_array can detoast the array elements later.
5404 * However, we must not let construct_md_array modify the ArrayBuildState
5405 * because that would mean array_agg_finalfn damages its input, which is
5406 * verboten. Also, this way frequently saves one copying step.)
5407 */
5408 if (!disnull && !astate->typbyval)
5409 {
5410 if (astate->typlen == -1)
5412 else
5413 dvalue = datumCopy(dvalue, astate->typbyval, astate->typlen);
5414 }
5415
5416 astate->dvalues[astate->nelems] = dvalue;
5417 astate->dnulls[astate->nelems] = disnull;
5418 astate->nelems++;
5419
5420 MemoryContextSwitchTo(oldcontext);
5421
5422 return astate;
5423}
ArrayBuildState * initArrayResult(Oid element_type, MemoryContext rcontext, bool subcontext)
#define Assert(condition)
Definition c.h:885
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition datum.c:132
int errcode(int sqlerrcode)
Definition elog.c:874
int errmsg(const char *fmt,...)
Definition elog.c:1093
#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
void * repalloc(void *pointer, Size size)
Definition mcxt.c:1632
#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:352
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, fb(), 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 5844 of file arrayfuncs.c.

5848{
5849 if (astate == NULL)
5850 astate = initArrayResultAny(input_type, rcontext, true);
5851
5852 if (astate->scalarstate)
5854 dvalue, disnull,
5856 else
5857 (void) accumArrayResultArr(astate->arraystate,
5858 dvalue, disnull,
5860
5861 return astate;
5862}
ArrayBuildState * accumArrayResult(ArrayBuildState *astate, Datum dvalue, bool disnull, Oid element_type, MemoryContext rcontext)
ArrayBuildStateAny * initArrayResultAny(Oid input_type, MemoryContext rcontext, bool subcontext)
ArrayBuildStateArr * accumArrayResultArr(ArrayBuildStateArr *astate, Datum dvalue, bool disnull, Oid array_type, MemoryContext rcontext)
ArrayBuildStateArr * arraystate
Definition array.h:230
ArrayBuildState * scalarstate
Definition array.h:229

References accumArrayResult(), accumArrayResultArr(), ArrayBuildStateAny::arraystate, fb(), 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 5565 of file arrayfuncs.c.

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

4983{
4984 int destbitmask,
4985 destbitval,
4986 srcbitmask,
4987 srcbitval;
4988
4990 if (nitems <= 0)
4991 return; /* don't risk fetch off end of memory */
4992 destbitmap += destoffset / 8;
4993 destbitmask = 1 << (destoffset % 8);
4995 if (srcbitmap)
4996 {
4997 srcbitmap += srcoffset / 8;
4998 srcbitmask = 1 << (srcoffset % 8);
5000 while (nitems-- > 0)
5001 {
5002 if (srcbitval & srcbitmask)
5004 else
5006 destbitmask <<= 1;
5007 if (destbitmask == 0x100)
5008 {
5010 destbitmask = 1;
5011 if (nitems > 0)
5013 }
5014 srcbitmask <<= 1;
5015 if (srcbitmask == 0x100)
5016 {
5017 srcbitmap++;
5018 srcbitmask = 1;
5019 if (nitems > 0)
5021 }
5022 }
5023 if (destbitmask != 1)
5025 }
5026 else
5027 {
5028 while (nitems-- > 0)
5029 {
5031 destbitmask <<= 1;
5032 if (destbitmask == 0x100)
5033 {
5035 destbitmask = 1;
5036 if (nitems > 0)
5038 }
5039 }
5040 if (destbitmask != 1)
5042 }
5043}

References Assert, fb(), 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 1794 of file arrayfuncs.c.

1795{
1797
1799}
#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:355

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

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

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

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

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

◆ array_contains_nulls()

bool array_contains_nulls ( const ArrayType array)

Definition at line 3781 of file arrayfuncs.c.

3782{
3783 int nelems;
3784 bits8 *bitmap;
3785 int bitmask;
3786
3787 /* Easy answer if there's no null bitmap */
3788 if (!ARR_HASNULL(array))
3789 return false;
3790
3791 nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
3792
3793 bitmap = ARR_NULLBITMAP(array);
3794
3795 /* check whole bytes of the bitmap byte-at-a-time */
3796 while (nelems >= 8)
3797 {
3798 if (*bitmap != 0xFF)
3799 return true;
3800 bitmap++;
3801 nelems -= 8;
3802 }
3803
3804 /* check last partial byte */
3805 bitmask = 1;
3806 while (nelems > 0)
3807 {
3808 if ((*bitmap & bitmask) == 0)
3809 return true;
3810 bitmask <<= 1;
3811 nelems--;
3812 }
3813
3814 return false;
3815}

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(), check_mcvlist_array(), 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(), statatt_build_stavalues(), stats_check_arg_array(), 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 4950 of file arrayfuncs.c.

4953{
4954 int numbytes;
4955
4956 numbytes = array_nelems_size(srcptr, offset, nullbitmap, nitems,
4957 typlen, typbyval, typalign);
4959 return numbytes;
4960}
static int array_nelems_size(char *ptr, int offset, bits8 *nullbitmap, int nitems, int typlen, bool typbyval, char typalign)

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

4610{
4612
4613 /*
4614 * Sanity-check inputs --- caller should have got this right already
4615 */
4616 Assert(arr);
4618 elog(ERROR, "invalid arguments to array_create_iterator");
4619
4620 /*
4621 * Remember basic info about the array and its element type
4622 */
4623 iterator->arr = arr;
4624 iterator->nullbitmap = ARR_NULLBITMAP(arr);
4625 iterator->nitems = ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr));
4626
4627 if (mstate != NULL)
4628 {
4629 Assert(mstate->element_type == ARR_ELEMTYPE(arr));
4630
4631 iterator->typlen = mstate->typlen;
4632 iterator->typbyval = mstate->typbyval;
4633 iterator->typalign = mstate->typalign;
4634 }
4635 else
4637 &iterator->typlen,
4638 &iterator->typbyval,
4639 &iterator->typalign);
4640 iterator->typalignby = typalign_to_alignby(iterator->typalign);
4641
4642 /*
4643 * Remember the slicing parameters.
4644 */
4645 iterator->slice_ndim = slice_ndim;
4646
4647 if (slice_ndim > 0)
4648 {
4649 /*
4650 * Get pointers into the array's dims and lbound arrays to represent
4651 * the dims/lbound arrays of a slice. These are the same as the
4652 * rightmost N dimensions of the array.
4653 */
4654 iterator->slice_dims = ARR_DIMS(arr) + ARR_NDIM(arr) - slice_ndim;
4655 iterator->slice_lbound = ARR_LBOUND(arr) + ARR_NDIM(arr) - slice_ndim;
4656
4657 /*
4658 * Compute number of elements in a slice.
4659 */
4660 iterator->slice_len = ArrayGetNItems(slice_ndim,
4661 iterator->slice_dims);
4662
4663 /*
4664 * Create workspace for building sub-arrays.
4665 */
4666 iterator->slice_values = (Datum *)
4667 palloc(iterator->slice_len * sizeof(Datum));
4668 iterator->slice_nulls = (bool *)
4669 palloc(iterator->slice_len * sizeof(bool));
4670 }
4671
4672 /*
4673 * Initialize our data pointer and linear element number. These will
4674 * advance through the array during array_iterate().
4675 */
4676 iterator->data_ptr = ARR_DATA_PTR(arr);
4677 iterator->current_item = 0;
4678
4679 return iterator;
4680}
#define ARR_ELEMTYPE(a)
Definition array.h:292
#define elog(elevel,...)
Definition elog.h:226
#define palloc0_object(type)
Definition fe_memutils.h:75
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition lsyscache.c:2421
static uint8 typalign_to_alignby(char typalign)
Definition tupmacs.h:80

References ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_LBOUND, ARR_NDIM, ARR_NULLBITMAP, ArrayGetNItems(), Assert, elog, ERROR, fb(), get_typlenbyvalalign(), palloc(), palloc0_object, and typalign_to_alignby().

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

1673{
1675 char *p;
1676 int i;
1677 int *dimv,
1678 *lb;
1679
1680 /*
1681 * 33 since we assume 15 digits per number + ':' +'[]'
1682 *
1683 * +1 for trailing null
1684 */
1685 char buf[MAXDIM * 33 + 1];
1686
1687 /* Sanity check: does it look like an array at all? */
1688 if (AARR_NDIM(v) <= 0 || AARR_NDIM(v) > MAXDIM)
1690
1691 dimv = AARR_DIMS(v);
1692 lb = AARR_LBOUND(v);
1693
1694 p = buf;
1695 for (i = 0; i < AARR_NDIM(v); i++)
1696 {
1697 sprintf(p, "[%d:%d]", lb[i], dimv[i] + lb[i] - 1);
1698 p += strlen(p);
1699 }
1700
1702}
#define PG_RETURN_NULL()
Definition fmgr.h:346
#define PG_RETURN_TEXT_P(x)
Definition fmgr.h:374
static char buf[DEFAULT_XLOG_SEG_SIZE]
#define sprintf
Definition port.h:262
text * cstring_to_text(const char *s)
Definition varlena.c:182

References AARR_DIMS, AARR_LBOUND, AARR_NDIM, buf, cstring_to_text(), fb(), 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 3828 of file arrayfuncs.c.

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

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, fb(), FmgrInfo::fn_oid, format_type_be(), FunctionCallInvoke, i, 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 5112 of file arrayfuncs.c.

5123{
5126 char *srcdataptr;
5127 int src_offset,
5129 prod[MAXDIM],
5130 span[MAXDIM],
5131 dist[MAXDIM],
5132 indx[MAXDIM];
5133 int i,
5134 j,
5135 inc;
5136
5137 src_offset = ArrayGetOffset(ndim, dim, lb, st);
5139 typlen, typbyval, typalign);
5140 mda_get_prod(ndim, dim, prod);
5141 mda_get_range(ndim, span, st, endp);
5142 mda_get_offset_values(ndim, dist, prod, span);
5143 for (i = 0; i < ndim; i++)
5144 indx[i] = 0;
5145 dest_offset = 0;
5146 j = ndim - 1;
5147 do
5148 {
5149 if (dist[j])
5150 {
5151 /* skip unwanted elements */
5153 dist[j],
5154 typlen, typbyval, typalign);
5155 src_offset += dist[j];
5156 }
5159 typlen, typbyval, typalign);
5160 if (destnullsptr)
5163 1);
5164 destdataptr += inc;
5165 srcdataptr += inc;
5166 src_offset++;
5167 dest_offset++;
5168 } while ((j = mda_next_tuple(ndim, indx, span)) != -1);
5169}
static int array_copy(char *destptr, int nitems, char *srcptr, int offset, bits8 *nullbitmap, int typlen, bool typbyval, char typalign)
static char * array_seek(char *ptr, int offset, bits8 *nullbitmap, int nitems, int typlen, bool typbyval, char typalign)
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(), fb(), 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 6048 of file arrayfuncs.c.

6049{
6050 ArrayType *dims;
6051 ArrayType *result;
6052 Oid elmtype;
6053 Datum value;
6054 bool isnull;
6055
6056 if (PG_ARGISNULL(1))
6057 ereport(ERROR,
6059 errmsg("dimension array or low bound array cannot be null")));
6060
6061 dims = PG_GETARG_ARRAYTYPE_P(1);
6062
6063 if (!PG_ARGISNULL(0))
6064 {
6066 isnull = false;
6067 }
6068 else
6069 {
6070 value = 0;
6071 isnull = true;
6072 }
6073
6074 elmtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
6075 if (!OidIsValid(elmtype))
6076 elog(ERROR, "could not determine data type of input");
6077
6078 result = array_fill_internal(dims, NULL, value, isnull, elmtype, fcinfo);
6079 PG_RETURN_ARRAYTYPE_P(result);
6080}
#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)
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 @174 value

References array_fill_internal(), elog, ereport, errcode(), errmsg(), ERROR, fb(), 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 6100 of file arrayfuncs.c.

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

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_nominal_alignby, construct_empty_array(), create_array_envelope(), ereport, errcode(), errdetail(), errmsg(), ERROR, fb(), FunctionCallInfoBaseData::flinfo, FmgrInfo::fn_extra, FmgrInfo::fn_mcxt, get_typlenbyvalalign(), i, InvalidOid, MaxAllocSize, MAXDIM, MemoryContextAlloc(), nitems, PG_DETOAST_DATUM, PointerGetDatum(), typalign_to_alignby(), 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 6007 of file arrayfuncs.c.

6008{
6009 ArrayType *dims;
6010 ArrayType *lbs;
6011 ArrayType *result;
6012 Oid elmtype;
6013 Datum value;
6014 bool isnull;
6015
6016 if (PG_ARGISNULL(1) || PG_ARGISNULL(2))
6017 ereport(ERROR,
6019 errmsg("dimension array or low bound array cannot be null")));
6020
6021 dims = PG_GETARG_ARRAYTYPE_P(1);
6022 lbs = PG_GETARG_ARRAYTYPE_P(2);
6023
6024 if (!PG_ARGISNULL(0))
6025 {
6027 isnull = false;
6028 }
6029 else
6030 {
6031 value = 0;
6032 isnull = true;
6033 }
6034
6035 elmtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
6036 if (!OidIsValid(elmtype))
6037 elog(ERROR, "could not determine data type of input");
6038
6039 result = array_fill_internal(dims, lbs, value, isnull, elmtype, fcinfo);
6040 PG_RETURN_ARRAYTYPE_P(result);
6041}

References array_fill_internal(), elog, ereport, errcode(), errmsg(), ERROR, fb(), 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 4772 of file arrayfuncs.c.

4773{
4774 if (iterator->slice_ndim > 0)
4775 {
4776 pfree(iterator->slice_values);
4777 pfree(iterator->slice_nulls);
4778 }
4779 pfree(iterator);
4780}

References fb(), and pfree().

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

◆ array_ge()

Datum array_ge ( PG_FUNCTION_ARGS  )

Definition at line 3979 of file arrayfuncs.c.

3980{
3981 PG_RETURN_BOOL(array_cmp(fcinfo) >= 0);
3982}
static int array_cmp(FunctionCallInfo fcinfo)

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

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

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

References ArrayGetOffset(), Assert, DatumGetEOHP(), deconstruct_expanded_array(), EA_MAGIC, fb(), i, and MAXDIM.

Referenced by array_get_element().

◆ array_get_isnull()

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

Definition at line 4794 of file arrayfuncs.c.

4795{
4796 if (nullbitmap == NULL)
4797 return false; /* assume not null */
4798 if (nullbitmap[offset / 8] & (1 << (offset % 8)))
4799 return false; /* not null */
4800 return true;
4801}

References fb().

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

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

3968{
3969 PG_RETURN_BOOL(array_cmp(fcinfo) > 0);
3970}

References array_cmp(), and PG_RETURN_BOOL.

◆ array_in()

Datum array_in ( PG_FUNCTION_ARGS  )

Definition at line 181 of file arrayfuncs.c.

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

References AllocSizeIsValid, ARR_DIMS, ARR_LBOUND, ARR_OVERHEAD_NONULLS, ARR_OVERHEAD_WITHNULLS, ASSGN, att_addlength_datum, att_nominal_alignby, construct_empty_array(), CopyArrayEls(), ArrayType::dataoffset, ArrayType::elemtype, ereturn, errcode(), errdetail(), errmsg(), fb(), fmgr_info_cxt(), get_type_io_data(), i, 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(), ReadArrayDimensions(), ReadArrayStr(), scanner_isspace(), SET_VARSIZE(), typalign, typalign_to_alignby(), and values.

Referenced by extract_variadic_args(), and statatt_build_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 5185 of file arrayfuncs.c.

5196{
5199 char *srcPtr = ARR_DATA_PTR(srcArray);
5205 int dest_offset,
5207 src_offset,
5208 prod[MAXDIM],
5209 span[MAXDIM],
5210 dist[MAXDIM],
5211 indx[MAXDIM];
5212 int i,
5213 j,
5214 inc;
5215
5216 dest_offset = ArrayGetOffset(ndim, dim, lb, st);
5217 /* copy items before the slice start */
5219 origPtr, 0, origBitmap,
5220 typlen, typbyval, typalign);
5221 destPtr += inc;
5222 origPtr += inc;
5223 if (destBitmap)
5226 mda_get_prod(ndim, dim, prod);
5227 mda_get_range(ndim, span, st, endp);
5228 mda_get_offset_values(ndim, dist, prod, span);
5229 for (i = 0; i < ndim; i++)
5230 indx[i] = 0;
5231 src_offset = 0;
5232 j = ndim - 1;
5233 do
5234 {
5235 /* Copy/advance over elements between here and next part of slice */
5236 if (dist[j])
5237 {
5240 typlen, typbyval, typalign);
5241 destPtr += inc;
5242 origPtr += inc;
5243 if (destBitmap)
5246 dist[j]);
5247 dest_offset += dist[j];
5248 orig_offset += dist[j];
5249 }
5250 /* Copy new element at this slice position */
5251 inc = array_copy(destPtr, 1,
5253 typlen, typbyval, typalign);
5254 if (destBitmap)
5257 1);
5258 destPtr += inc;
5259 srcPtr += inc;
5260 dest_offset++;
5261 src_offset++;
5262 /* Advance over old element at this slice position */
5264 typlen, typbyval, typalign);
5265 orig_offset++;
5266 } while ((j = mda_next_tuple(ndim, indx, span)) != -1);
5267
5268 /* don't miss any data at the end */
5271 typlen, typbyval, typalign);
5272 if (destBitmap)
5276}

References ARR_DATA_PTR, ARR_DIMS, ARR_NDIM, ARR_NULLBITMAP, array_bitmap_copy(), array_copy(), array_seek(), ArrayGetNItems(), ArrayGetOffset(), fb(), 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 4689 of file arrayfuncs.c.

4690{
4691 /* Done if we have reached the end of the array */
4692 if (iterator->current_item >= iterator->nitems)
4693 return false;
4694
4695 if (iterator->slice_ndim == 0)
4696 {
4697 /*
4698 * Scalar case: return one element.
4699 */
4700 if (array_get_isnull(iterator->nullbitmap, iterator->current_item++))
4701 {
4702 *isnull = true;
4703 *value = (Datum) 0;
4704 }
4705 else
4706 {
4707 /* non-NULL, so fetch the individual Datum to return */
4708 char *p = iterator->data_ptr;
4709
4710 *isnull = false;
4711 *value = fetch_att(p, iterator->typbyval, iterator->typlen);
4712
4713 /* Move our data pointer forward to the next element */
4714 p = att_addlength_pointer(p, iterator->typlen, p);
4715 p = (char *) att_nominal_alignby(p, iterator->typalignby);
4716 iterator->data_ptr = p;
4717 }
4718 }
4719 else
4720 {
4721 /*
4722 * Slice case: build and return an array of the requested size.
4723 */
4724 ArrayType *result;
4725 Datum *values = iterator->slice_values;
4726 bool *nulls = iterator->slice_nulls;
4727 char *p = iterator->data_ptr;
4728 int i;
4729
4730 for (i = 0; i < iterator->slice_len; i++)
4731 {
4732 if (array_get_isnull(iterator->nullbitmap,
4733 iterator->current_item++))
4734 {
4735 nulls[i] = true;
4736 values[i] = (Datum) 0;
4737 }
4738 else
4739 {
4740 nulls[i] = false;
4741 values[i] = fetch_att(p, iterator->typbyval, iterator->typlen);
4742
4743 /* Move our data pointer forward to the next element */
4744 p = att_addlength_pointer(p, iterator->typlen, p);
4745 p = (char *) att_nominal_alignby(p, iterator->typalignby);
4746 }
4747 }
4748
4749 iterator->data_ptr = p;
4750
4751 result = construct_md_array(values,
4752 nulls,
4753 iterator->slice_ndim,
4754 iterator->slice_dims,
4755 iterator->slice_lbound,
4756 ARR_ELEMTYPE(iterator->arr),
4757 iterator->typlen,
4758 iterator->typbyval,
4759 iterator->typalign);
4760
4761 *isnull = false;
4762 *value = PointerGetDatum(result);
4763 }
4764
4765 return true;
4766}
ArrayType * construct_md_array(Datum *elems, bool *nulls, int ndims, int *dims, int *lbs, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
#define att_addlength_pointer(cur_offset, attlen, attptr)
Definition tupmacs.h:209
static Datum fetch_att(const void *T, bool attbyval, int attlen)
Definition tupmacs.h:50

References ARR_ELEMTYPE, array_get_isnull(), att_addlength_pointer, att_nominal_alignby, construct_md_array(), fb(), fetch_att(), i, PointerGetDatum(), 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 5902 of file arrayfuncs.c.

5903{
5904 if (array_cmp(fcinfo) > 0)
5906 else
5908}
#define PG_RETURN_DATUM(x)
Definition fmgr.h:354

References array_cmp(), PG_GETARG_DATUM, and PG_RETURN_DATUM.

◆ array_le()

Datum array_le ( PG_FUNCTION_ARGS  )

Definition at line 3973 of file arrayfuncs.c.

3974{
3975 PG_RETURN_BOOL(array_cmp(fcinfo) <= 0);
3976}

References array_cmp(), and PG_RETURN_BOOL.

◆ array_length()

Datum array_length ( PG_FUNCTION_ARGS  )

Definition at line 1767 of file arrayfuncs.c.

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

References AARR_DIMS, AARR_NDIM, fb(), 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 1710 of file arrayfuncs.c.

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

References AARR_LBOUND, AARR_NDIM, fb(), 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 3961 of file arrayfuncs.c.

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

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

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

References AARR_DIMS, AARR_ELEMTYPE, AARR_LBOUND, AARR_NDIM, AllocSizeIsValid, ARR_DIMS, ARR_LBOUND, ARR_OVERHEAD_NONULLS, ARR_OVERHEAD_WITHNULLS, array_iter_next(), array_iter_setup(), ArrayGetNItems(), att_addlength_datum, att_nominal_alignby, construct_empty_array(), CopyArrayEls(), ArrayType::dataoffset, DatumGetAnyArrayP(), ArrayMetaState::element_type, ArrayType::elemtype, ereport, errcode(), errmsg(), ERROR, ExecEvalExpr(), fb(), 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, typalign_to_alignby(), ArrayMetaState::typbyval, ArrayMetaState::typlen, and values.

Referenced by ExecEvalArrayCoerce().

◆ array_ndims()

Datum array_ndims ( PG_FUNCTION_ARGS  )

Definition at line 1656 of file arrayfuncs.c.

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

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

3956{
3958}
Datum array_eq(PG_FUNCTION_ARGS)

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

4930{
4931 return array_seek(ptr, offset, nullbitmap, nitems,
4932 typlen, typbyval, typalign) - ptr;
4933}

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

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

References AARR_DIMS, AARR_ELEMTYPE, AARR_LBOUND, AARR_NDIM, APPENDCHAR, APPENDSTR, array_iter_next(), array_iter_setup(), ArrayGetNItems(), Assert, ASSGN, fb(), fmgr_info_cxt(), get_type_io_data(), i, IOFunc_output, j, MAXDIM, MemoryContextAlloc(), nitems, OutputFunctionCall(), palloc(), pfree(), PG_GETARG_ANY_ARRAY_P, PG_RETURN_CSTRING, pg_strcasecmp(), pstrdup(), scanner_isspace(), sprintf, typalign, and values.

Referenced by anyarray_out(), and anycompatiblearray_out().

◆ array_recv()

Datum array_recv ( PG_FUNCTION_ARGS  )

Definition at line 1275 of file arrayfuncs.c.

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

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

3154{
3156 arraytyplen, elmlen, elmbyval, elmalign,
3157 isNull);
3158}
Datum array_get_element(Datum arraydatum, int nSubscripts, int *indx, int arraytyplen, int elmlen, bool elmbyval, char elmalign, bool *isNull)

References array_get_element(), fb(), and PointerGetDatum().

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

◆ array_remove()

Datum array_remove ( PG_FUNCTION_ARGS  )

Definition at line 6658 of file arrayfuncs.c.

6659{
6660 ArrayType *array;
6661 Datum search = PG_GETARG_DATUM(1);
6662 bool search_isnull = PG_ARGISNULL(1);
6663
6664 if (PG_ARGISNULL(0))
6666 array = PG_GETARG_ARRAYTYPE_P(0);
6667
6668 array = array_replace_internal(array,
6669 search, search_isnull,
6670 (Datum) 0, true,
6671 true, PG_GET_COLLATION(),
6672 fcinfo);
6673 PG_RETURN_ARRAYTYPE_P(array);
6674}
static ArrayType * array_replace_internal(ArrayType *array, Datum search, bool search_isnull, Datum replace, bool replace_isnull, bool remove, Oid collation, FunctionCallInfo fcinfo)

References array_replace_internal(), fb(), 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 6680 of file arrayfuncs.c.

6681{
6682 ArrayType *array;
6683 Datum search = PG_GETARG_DATUM(1);
6684 bool search_isnull = PG_ARGISNULL(1);
6685 Datum replace = PG_GETARG_DATUM(2);
6686 bool replace_isnull = PG_ARGISNULL(2);
6687
6688 if (PG_ARGISNULL(0))
6690 array = PG_GETARG_ARRAYTYPE_P(0);
6691
6692 array = array_replace_internal(array,
6693 search, search_isnull,
6694 replace, replace_isnull,
6695 false, PG_GET_COLLATION(),
6696 fcinfo);
6697 PG_RETURN_ARRAYTYPE_P(array);
6698}

References array_replace_internal(), fb(), 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 6398 of file arrayfuncs.c.

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

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_nominal_alignby, construct_empty_array(), CopyArrayEls(), ArrayType::dataoffset, DatumGetBool(), ArrayType::elemtype, TypeCacheEntry::eq_opr_finfo, ereport, errcode(), errmsg(), ERROR, fb(), fetch_att(), FunctionCallInfoBaseData::flinfo, FmgrInfo::fn_extra, FmgrInfo::fn_oid, format_type_be(), FunctionCallInvoke, i, InitFunctionCallInfoData, LOCAL_FCINFO, lookup_type_cache(), MaxAllocSize, ArrayType::ndim, nitems, OidIsValid, palloc(), palloc0(), pfree(), PG_DETOAST_DATUM, PointerGetDatum(), SET_VARSIZE(), skip, typalign, TypeCacheEntry::typalign, typalign_to_alignby(), 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 4879 of file arrayfuncs.c.

4881{
4882 uint8 typalignby = typalign_to_alignby(typalign);
4883 int bitmask;
4884 int i;
4885
4886 /* easy if fixed-size elements and no NULLs */
4887 if (typlen > 0 && !nullbitmap)
4888 return ptr + nitems * ((Size) att_nominal_alignby(typlen, typalignby));
4889
4890 /* seems worth having separate loops for NULL and no-NULLs cases */
4891 if (nullbitmap)
4892 {
4893 nullbitmap += offset / 8;
4894 bitmask = 1 << (offset % 8);
4895
4896 for (i = 0; i < nitems; i++)
4897 {
4898 if (*nullbitmap & bitmask)
4899 {
4900 ptr = att_addlength_pointer(ptr, typlen, ptr);
4901 ptr = (char *) att_nominal_alignby(ptr, typalignby);
4902 }
4903 bitmask <<= 1;
4904 if (bitmask == 0x100)
4905 {
4906 nullbitmap++;
4907 bitmask = 1;
4908 }
4909 }
4910 }
4911 else
4912 {
4913 for (i = 0; i < nitems; i++)
4914 {
4915 ptr = att_addlength_pointer(ptr, typlen, ptr);
4916 ptr = (char *) att_nominal_alignby(ptr, typalignby);
4917 }
4918 }
4919 return ptr;
4920}
size_t Size
Definition c.h:631

References att_addlength_pointer, att_nominal_alignby, i, nitems, typalign, and typalign_to_alignby().

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

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

3171{
3174 dataValue, isNull,
3176 elmlen, elmbyval, elmalign));
3177}
Datum array_set_element(Datum arraydatum, int nSubscripts, int *indx, Datum dataValue, bool isNull, int arraytyplen, int elmlen, bool elmbyval, char elmalign)

References array_set_element(), DatumGetArrayTypeP, fb(), 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 2205 of file arrayfuncs.c.

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

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

References ArrayCheckBounds(), ArrayGetNItems(), ArrayGetOffset(), Assert, datumCopy(), DatumGetExpandedArray(), DatumGetPointer(), deconstruct_expanded_array(), EOHPGetRWDatum(), ereport, errcode(), errmsg(), ERROR, fb(), i, Max, MaxArraySize, MAXDIM, MemoryContextAllocZero(), MemoryContextSwitchTo(), pfree(), pg_add_s32_overflow(), pg_sub_s32_overflow(), and repalloc().

Referenced by array_set_element().

◆ array_set_isnull()

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

Definition at line 4811 of file arrayfuncs.c.

4812{
4813 int bitmask;
4814
4815 nullbitmap += offset / 8;
4816 bitmask = 1 << (offset % 8);
4817 if (isNull)
4818 *nullbitmap &= ~bitmask;
4819 else
4820 *nullbitmap |= bitmask;
4821}

References fb().

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

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

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(), DatumGetArrayTypeP, deconstruct_array(), ereport, errcode(), errdetail(), errmsg(), ERROR, fb(), i, Max, MaxArraySize, MAXDIM, mda_get_range(), Min, 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 5051 of file arrayfuncs.c.

5055{
5056 int src_offset,
5057 span[MAXDIM],
5058 prod[MAXDIM],
5059 dist[MAXDIM],
5060 indx[MAXDIM];
5061 char *ptr;
5062 int i,
5063 j,
5064 inc;
5065 int count = 0;
5066 uint8 typalignby = typalign_to_alignby(typalign);
5067
5068 mda_get_range(ndim, span, st, endp);
5069
5070 /* Pretty easy for fixed element length without nulls ... */
5071 if (typlen > 0 && !arraynullsptr)
5072 return ArrayGetNItems(ndim, span) * att_nominal_alignby(typlen, typalignby);
5073
5074 /* Else gotta do it the hard way */
5075 src_offset = ArrayGetOffset(ndim, dim, lb, st);
5077 typlen, typbyval, typalign);
5078 mda_get_prod(ndim, dim, prod);
5079 mda_get_offset_values(ndim, dist, prod, span);
5080 for (i = 0; i < ndim; i++)
5081 indx[i] = 0;
5082 j = ndim - 1;
5083 do
5084 {
5085 if (dist[j])
5086 {
5088 typlen, typbyval, typalign);
5089 src_offset += dist[j];
5090 }
5092 {
5093 inc = att_addlength_pointer(0, typlen, ptr);
5094 inc = att_nominal_alignby(inc, typalignby);
5095 ptr += inc;
5096 count += inc;
5097 }
5098 src_offset++;
5099 } while ((j = mda_next_tuple(ndim, indx, span)) != -1);
5100 return count;
5101}

References array_get_isnull(), array_seek(), ArrayGetNItems(), ArrayGetOffset(), att_addlength_pointer, att_nominal_alignby, fb(), i, j, MAXDIM, mda_get_offset_values(), mda_get_prod(), mda_get_range(), mda_next_tuple(), typalign, and typalign_to_alignby().

Referenced by array_get_slice(), and array_set_slice().

◆ array_smaller()

Datum array_smaller ( PG_FUNCTION_ARGS  )

Definition at line 5911 of file arrayfuncs.c.

5912{
5913 if (array_cmp(fcinfo) < 0)
5915 else
5917}

References array_cmp(), PG_GETARG_DATUM, and PG_RETURN_DATUM.

◆ array_unnest()

Datum array_unnest ( PG_FUNCTION_ARGS  )

Definition at line 6271 of file arrayfuncs.c.

6272{
6273 typedef struct
6274 {
6275 array_iter iter;
6276 int nextelem;
6277 int numelems;
6279
6282 MemoryContext oldcontext;
6283
6284 /* stuff done only on the first call of the function */
6285 if (SRF_IS_FIRSTCALL())
6286 {
6287 AnyArrayType *arr;
6288 int16 elmlen;
6289 bool elmbyval;
6290 char elmalign;
6291
6292 /* create a function context for cross-call persistence */
6294
6295 /*
6296 * switch to memory context appropriate for multiple function calls
6297 */
6298 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
6299
6300 /*
6301 * Get the array value and detoast if needed. We can't do this
6302 * earlier because if we have to detoast, we want the detoasted copy
6303 * to be in multi_call_memory_ctx, so it will go away when we're done
6304 * and not before. (If no detoast happens, we assume the originally
6305 * passed array will stick around till then.)
6306 */
6307 arr = PG_GETARG_ANY_ARRAY_P(0);
6308
6309 /* allocate memory for user context */
6311
6312 /* get element-type data */
6314 {
6315 /* we can just grab the type data from expanded array */
6316 elmlen = arr->xpn.typlen;
6317 elmbyval = arr->xpn.typbyval;
6318 elmalign = arr->xpn.typalign;
6319 }
6320 else
6322 &elmlen,
6323 &elmbyval,
6324 &elmalign);
6325
6326 /* initialize state */
6327 array_iter_setup(&fctx->iter, arr, elmlen, elmbyval, elmalign);
6328 fctx->nextelem = 0;
6329 fctx->numelems = ArrayGetNItems(AARR_NDIM(arr), AARR_DIMS(arr));
6330
6331 funcctx->user_fctx = fctx;
6332 MemoryContextSwitchTo(oldcontext);
6333 }
6334
6335 /* stuff done on every call of the function */
6337 fctx = funcctx->user_fctx;
6338
6339 if (fctx->nextelem < fctx->numelems)
6340 {
6341 int offset = fctx->nextelem++;
6342 Datum elem;
6343
6344 elem = array_iter_next(&fctx->iter, &fcinfo->isnull, offset);
6345
6346 SRF_RETURN_NEXT(funcctx, elem);
6347 }
6348 else
6349 {
6350 /* do when there is no more left */
6352 }
6353}
#define palloc_object(type)
Definition fe_memutils.h:74
#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
ExpandedArrayHeader xpn
Definition array.h:180

References AARR_DIMS, AARR_ELEMTYPE, AARR_NDIM, array_iter_next(), array_iter_setup(), ArrayGetNItems(), fb(), get_typlenbyvalalign(), MemoryContextSwitchTo(), palloc_object, 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, VARATT_IS_EXPANDED_HEADER, and AnyArrayType::xpn.

◆ array_unnest_support()

Datum array_unnest_support ( PG_FUNCTION_ARGS  )

Definition at line 6362 of file arrayfuncs.c.

6363{
6365 Node *ret = NULL;
6366
6368 {
6369 /* Try to estimate the number of rows returned */
6371
6372 if (is_funcclause(req->node)) /* be paranoid */
6373 {
6374 List *args = ((FuncExpr *) req->node)->args;
6375 Node *arg1;
6376
6377 /* We can use estimated argument values here */
6379
6380 req->rows = estimate_array_length(req->root, arg1);
6381 ret = (Node *) req;
6382 }
6383 }
6384
6385 PG_RETURN_POINTER(ret);
6386}
Node * estimate_expression_value(PlannerInfo *root, Node *node)
Definition clauses.c:2408
#define PG_RETURN_POINTER(x)
Definition fmgr.h:363
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:2223
Definition pg_list.h:54

References estimate_array_length(), estimate_expression_value(), fb(), is_funcclause(), IsA, linitial, PG_GETARG_POINTER, and PG_RETURN_POINTER.

◆ array_upper()

Datum array_upper ( PG_FUNCTION_ARGS  )

Definition at line 1737 of file arrayfuncs.c.

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

References AARR_DIMS, AARR_LBOUND, AARR_NDIM, fb(), 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 4829 of file arrayfuncs.c.

4830{
4831 return fetch_att(value, byval, len);
4832}
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,
uint8  typalignby,
char dest 
)
static

Definition at line 4840 of file arrayfuncs.c.

4845{
4846 int inc;
4847
4848 if (typlen > 0)
4849 {
4850 if (typbyval)
4851 store_att_byval(dest, src, typlen);
4852 else
4853 memmove(dest, DatumGetPointer(src), typlen);
4854 inc = att_nominal_alignby(typlen, typalignby);
4855 }
4856 else
4857 {
4858 Assert(!typbyval);
4859 inc = att_addlength_datum(0, typlen, src);
4860 memmove(dest, DatumGetPointer(src), inc);
4861 inc = att_nominal_alignby(inc, typalignby);
4862 }
4863
4864 return inc;
4865}
static void store_att_byval(void *T, Datum newdatum, int attlen)
Definition tupmacs.h:235

References Assert, att_addlength_datum, att_nominal_alignby, DatumGetPointer(), fb(), and store_att_byval().

Referenced by array_fill_internal(), array_set_element(), and CopyArrayEls().

◆ arraycontained()

Datum arraycontained ( PG_FUNCTION_ARGS  )

Definition at line 4572 of file arrayfuncs.c.

4573{
4576 Oid collation = PG_GET_COLLATION();
4577 bool result;
4578
4579 result = array_contain_compare(array1, array2, collation, true,
4580 &fcinfo->flinfo->fn_extra);
4581
4582 /* Avoid leaking memory when handed toasted input. */
4585
4586 PG_RETURN_BOOL(result);
4587}
static bool array_contain_compare(AnyArrayType *array1, AnyArrayType *array2, Oid collation, bool matchall, void **fn_extra)

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

◆ arraycontains()

Datum arraycontains ( PG_FUNCTION_ARGS  )

Definition at line 4554 of file arrayfuncs.c.

4555{
4558 Oid collation = PG_GET_COLLATION();
4559 bool result;
4560
4561 result = array_contain_compare(array2, array1, collation, true,
4562 &fcinfo->flinfo->fn_extra);
4563
4564 /* Avoid leaking memory when handed toasted input. */
4567
4568 PG_RETURN_BOOL(result);
4569}

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

◆ arrayoverlap()

Datum arrayoverlap ( PG_FUNCTION_ARGS  )

Definition at line 4536 of file arrayfuncs.c.

4537{
4540 Oid collation = PG_GET_COLLATION();
4541 bool result;
4542
4543 result = array_contain_compare(array1, array2, collation, false,
4544 &fcinfo->flinfo->fn_extra);
4545
4546 /* Avoid leaking memory when handed toasted input. */
4549
4550 PG_RETURN_BOOL(result);
4551}

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

◆ btarraycmp()

Datum btarraycmp ( PG_FUNCTION_ARGS  )

Definition at line 3985 of file arrayfuncs.c.

3986{
3987 PG_RETURN_INT32(array_cmp(fcinfo));
3988}

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

3370{
3371 int dims[1];
3372 int lbs[1];
3373
3374 dims[0] = nelems;
3375 lbs[0] = 1;
3376
3377 return construct_md_array(elems, NULL, 1, dims, lbs,
3378 elmtype, elmlen, elmbyval, elmalign);
3379}

References construct_md_array(), and fb().

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

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

References construct_array(), elog, ERROR, fb(), 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(), test_text_to_wchars(), 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 3604 of file arrayfuncs.c.

3607{
3608 ArrayType *array = construct_empty_array(element_type);
3609 Datum d;
3610
3612 pfree(array);
3613 return (ExpandedArrayHeader *) DatumGetEOHP(d);
3614}
Datum expand_array(Datum arraydatum, MemoryContext parentcontext, ArrayMetaState *metacache)

References construct_empty_array(), DatumGetEOHP(), expand_array(), fb(), 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 3500 of file arrayfuncs.c.

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

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

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,
const Datum values,
const bool nulls,
int  nitems,
int  typlen,
bool  typbyval,
char  typalign,
bool  freedata 
)

Definition at line 965 of file arrayfuncs.c.

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

References ARR_DATA_PTR, ARR_NULLBITMAP, ArrayCastAndSet(), DatumGetPointer(), elog, ERROR, fb(), i, nitems, pfree(), typalign, typalign_to_alignby(), 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 6083 of file arrayfuncs.c.

6085{
6086 ArrayType *result;
6087
6088 result = (ArrayType *) palloc0(nbytes);
6089 SET_VARSIZE(result, nbytes);
6090 result->ndim = ndims;
6091 result->dataoffset = dataoffset;
6092 result->elemtype = elmtype;
6093 memcpy(ARR_DIMS(result), dimv, ndims * sizeof(int));
6094 memcpy(ARR_LBOUND(result), lbsv, ndims * sizeof(int));
6095
6096 return result;
6097}

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

Referenced by array_fill_internal().

◆ deconstruct_array()

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

Definition at line 3638 of file arrayfuncs.c.

3642{
3643 Datum *elems;
3644 bool *nulls;
3645 int nelems;
3646 char *p;
3647 bits8 *bitmap;
3648 int bitmask;
3649 int i;
3650 uint8 elmalignby = typalign_to_alignby(elmalign);
3651
3652 Assert(ARR_ELEMTYPE(array) == elmtype);
3653
3654 nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
3655 *elemsp = elems = palloc_array(Datum, nelems);
3656 if (nullsp)
3657 *nullsp = nulls = palloc0_array(bool, nelems);
3658 else
3659 nulls = NULL;
3660 *nelemsp = nelems;
3661
3662 p = ARR_DATA_PTR(array);
3663 bitmap = ARR_NULLBITMAP(array);
3664 bitmask = 1;
3665
3666 for (i = 0; i < nelems; i++)
3667 {
3668 /* Get source element, checking for NULL */
3669 if (bitmap && (*bitmap & bitmask) == 0)
3670 {
3671 elems[i] = (Datum) 0;
3672 if (nulls)
3673 nulls[i] = true;
3674 else
3675 ereport(ERROR,
3677 errmsg("null array element not allowed in this context")));
3678 }
3679 else
3680 {
3681 elems[i] = fetch_att(p, elmbyval, elmlen);
3682 p = att_addlength_pointer(p, elmlen, p);
3683 p = (char *) att_nominal_alignby(p, elmalignby);
3684 }
3685
3686 /* advance bitmap pointer if any */
3687 if (bitmap)
3688 {
3689 bitmask <<= 1;
3690 if (bitmask == 0x100)
3691 {
3692 bitmap++;
3693 bitmask = 1;
3694 }
3695 }
3696 }
3697}
#define palloc_array(type, count)
Definition fe_memutils.h:76
#define palloc0_array(type, count)
Definition fe_memutils.h:77

References ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_NDIM, ARR_NULLBITMAP, ArrayGetNItems(), Assert, att_addlength_pointer, att_nominal_alignby, ereport, errcode(), errmsg(), ERROR, fb(), fetch_att(), i, palloc0_array, palloc_array, and typalign_to_alignby().

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 ( const ArrayType array,
Oid  elmtype,
Datum **  elemsp,
bool **  nullsp,
int nelemsp 
)

Definition at line 3705 of file arrayfuncs.c.

3708{
3709 int elmlen;
3710 bool elmbyval;
3711 char elmalign;
3712
3713 switch (elmtype)
3714 {
3715 case CHAROID:
3716 elmlen = 1;
3717 elmbyval = true;
3719 break;
3720
3721 case CSTRINGOID:
3722 elmlen = -2;
3723 elmbyval = false;
3725 break;
3726
3727 case FLOAT8OID:
3728 elmlen = sizeof(float8);
3729 elmbyval = true;
3731 break;
3732
3733 case INT2OID:
3734 elmlen = sizeof(int16);
3735 elmbyval = true;
3737 break;
3738
3739 case INT4OID:
3740 elmlen = sizeof(int32);
3741 elmbyval = true;
3743 break;
3744
3745 case OIDOID:
3746 elmlen = sizeof(Oid);
3747 elmbyval = true;
3749 break;
3750
3751 case TEXTOID:
3752 elmlen = -1;
3753 elmbyval = false;
3755 break;
3756
3757 case TIDOID:
3758 elmlen = sizeof(ItemPointerData);
3759 elmbyval = false;
3761 break;
3762
3763 default:
3764 elog(ERROR, "type %u not supported by deconstruct_array_builtin()", elmtype);
3765 /* keep compiler quiet */
3766 elmlen = 0;
3767 elmbyval = false;
3768 elmalign = 0;
3769 }
3770
3771 deconstruct_array(array, elmtype, elmlen, elmbyval, elmalign, elemsp, nullsp, nelemsp);
3772}

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

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(), import_mcv(), InsertOneProargdefaultsValue(), 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(), test_wchars_to_text(), 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 5932 of file arrayfuncs.c.

5933{
5935 MemoryContext oldcontext;
5937
5938 /* stuff done only on the first call of the function */
5939 if (SRF_IS_FIRSTCALL())
5940 {
5942 int reqdim = PG_GETARG_INT32(1);
5943 int *lb,
5944 *dimv;
5945
5946 /* create a function context for cross-call persistence */
5948
5949 /* Sanity check: does it look like an array at all? */
5950 if (AARR_NDIM(v) <= 0 || AARR_NDIM(v) > MAXDIM)
5952
5953 /* Sanity check: was the requested dim valid */
5956
5957 /*
5958 * switch to memory context appropriate for multiple function calls
5959 */
5960 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
5962
5963 lb = AARR_LBOUND(v);
5964 dimv = AARR_DIMS(v);
5965
5966 fctx->lower = lb[reqdim - 1];
5967 fctx->upper = dimv[reqdim - 1] + lb[reqdim - 1] - 1;
5968 fctx->reverse = (PG_NARGS() < 3) ? false : PG_GETARG_BOOL(2);
5969
5970 funcctx->user_fctx = fctx;
5971
5972 MemoryContextSwitchTo(oldcontext);
5973 }
5974
5976
5977 fctx = funcctx->user_fctx;
5978
5979 if (fctx->lower <= fctx->upper)
5980 {
5981 if (!fctx->reverse)
5983 else
5985 }
5986 else
5987 /* done when there are no more elements left */
5989}
#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, fb(), Int32GetDatum(), MAXDIM, MemoryContextSwitchTo(), palloc_object, PG_GETARG_ANY_ARRAY_P, PG_GETARG_BOOL, PG_GETARG_INT32, PG_NARGS, SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, and SRF_RETURN_NEXT.

Referenced by generate_subscripts_nodir().

◆ generate_subscripts_nodir()

Datum generate_subscripts_nodir ( PG_FUNCTION_ARGS  )

Definition at line 5996 of file arrayfuncs.c.

5997{
5998 /* just call the other one -- it can handle both cases */
5999 return generate_subscripts(fcinfo);
6000}
Datum generate_subscripts(PG_FUNCTION_ARGS)

References generate_subscripts().

◆ hash_array()

Datum hash_array ( PG_FUNCTION_ARGS  )

Definition at line 4170 of file arrayfuncs.c.

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

4304{
4307 uint64 seed = PG_GETARG_INT64(1);
4308 int ndims = AARR_NDIM(array);
4309 int *dims = AARR_DIMS(array);
4310 Oid element_type = AARR_ELEMTYPE(array);
4311 uint64 result = 1;
4312 int nitems;
4313 TypeCacheEntry *typentry;
4314 int typlen;
4315 bool typbyval;
4316 char typalign;
4317 int i;
4318 array_iter iter;
4319
4320 typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
4321 if (typentry == NULL ||
4322 typentry->type_id != element_type)
4323 {
4324 typentry = lookup_type_cache(element_type,
4326 if (!OidIsValid(typentry->hash_extended_proc_finfo.fn_oid))
4327 ereport(ERROR,
4329 errmsg("could not identify an extended hash function for type %s",
4330 format_type_be(element_type))));
4331 fcinfo->flinfo->fn_extra = typentry;
4332 }
4333 typlen = typentry->typlen;
4334 typbyval = typentry->typbyval;
4335 typalign = typentry->typalign;
4336
4337 InitFunctionCallInfoData(*locfcinfo, &typentry->hash_extended_proc_finfo, 2,
4339
4340 /* Loop over source data */
4341 nitems = ArrayGetNItems(ndims, dims);
4342 array_iter_setup(&iter, array, typlen, typbyval, typalign);
4343
4344 for (i = 0; i < nitems; i++)
4345 {
4346 Datum elt;
4347 bool isnull;
4349
4350 /* Get element, checking for NULL */
4351 elt = array_iter_next(&iter, &isnull, i);
4352
4353 if (isnull)
4354 {
4355 elthash = 0;
4356 }
4357 else
4358 {
4359 /* Apply the hash function */
4360 locfcinfo->args[0].value = elt;
4361 locfcinfo->args[0].isnull = false;
4362 locfcinfo->args[1].value = Int64GetDatum(seed);
4363 locfcinfo->args[1].isnull = false;
4365 /* We don't expect hash functions to return null */
4366 Assert(!locfcinfo->isnull);
4367 }
4368
4369 result = (result << 5) - result + elthash;
4370 }
4371
4372 AARR_FREE_IF_COPY(array, 0);
4373
4374 PG_RETURN_UINT64(result);
4375}
uint64_t uint64
Definition c.h:559
#define PG_GETARG_INT64(n)
Definition fmgr.h:284
#define PG_RETURN_UINT64(x)
Definition fmgr.h:371
static Datum Int64GetDatum(int64 X)
Definition postgres.h:423
static uint64 DatumGetUInt64(Datum X)
Definition postgres.h:433
#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, fb(), FmgrInfo::fn_oid, format_type_be(), FunctionCallInvoke, TypeCacheEntry::hash_extended_proc_finfo, i, 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 5308 of file arrayfuncs.c.

5309{
5310 /*
5311 * When using a subcontext, we can afford to start with a somewhat larger
5312 * initial array size. Without subcontexts, we'd better hope that most of
5313 * the states stay small ...
5314 */
5315 return initArrayResultWithSize(element_type, rcontext, subcontext,
5316 subcontext ? 64 : 8);
5317}
ArrayBuildState * initArrayResultWithSize(Oid element_type, MemoryContext rcontext, bool subcontext, int initsize)

References fb(), and 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 5797 of file arrayfuncs.c.

5798{
5799 ArrayBuildStateAny *astate;
5800
5801 /*
5802 * int2vector and oidvector will satisfy both get_element_type and
5803 * get_array_type. We prefer to treat them as scalars, to be consistent
5804 * with get_promoted_array_type. Hence, check get_array_type not
5805 * get_element_type.
5806 */
5808 {
5809 /* Array case */
5810 ArrayBuildStateArr *arraystate;
5811
5812 arraystate = initArrayResultArr(input_type, InvalidOid, rcontext, subcontext);
5813 astate = (ArrayBuildStateAny *)
5814 MemoryContextAlloc(arraystate->mcontext,
5815 sizeof(ArrayBuildStateAny));
5816 astate->scalarstate = NULL;
5817 astate->arraystate = arraystate;
5818 }
5819 else
5820 {
5821 /* Scalar case */
5822 ArrayBuildState *scalarstate;
5823
5824 scalarstate = initArrayResult(input_type, rcontext, subcontext);
5825 astate = (ArrayBuildStateAny *)
5826 MemoryContextAlloc(scalarstate->mcontext,
5827 sizeof(ArrayBuildStateAny));
5828 astate->scalarstate = scalarstate;
5829 astate->arraystate = NULL;
5830 }
5831
5832 return astate;
5833}
Oid get_array_type(Oid typid)
Definition lsyscache.c:2939

References ArrayBuildStateAny::arraystate, fb(), 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 5519 of file arrayfuncs.c.

5521{
5522 ArrayBuildStateArr *astate;
5523 MemoryContext arr_context = rcontext; /* by default use the parent ctx */
5524
5525 /* Lookup element type, unless element_type already provided */
5526 if (!OidIsValid(element_type))
5527 {
5528 element_type = get_element_type(array_type);
5529
5530 if (!OidIsValid(element_type))
5531 ereport(ERROR,
5533 errmsg("data type %s is not an array type",
5534 format_type_be(array_type))));
5535 }
5536
5537 /* Make a temporary context to hold all the junk */
5538 if (subcontext)
5540 "accumArrayResultArr",
5542
5543 /* Note we initialize all fields to zero */
5544 astate = (ArrayBuildStateArr *)
5546 astate->mcontext = arr_context;
5547 astate->private_cxt = subcontext;
5548
5549 /* Save relevant datatype information */
5550 astate->array_type = array_type;
5551 astate->element_type = element_type;
5552
5553 return astate;
5554}
Oid get_element_type(Oid typid)
Definition lsyscache.c:2911
#define AllocSetContextCreate
Definition memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition memutils.h:160

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, ArrayBuildStateArr::array_type, ArrayBuildStateArr::element_type, ereport, errcode(), errmsg(), ERROR, fb(), 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 5325 of file arrayfuncs.c.

5327{
5328 ArrayBuildState *astate;
5330
5331 /* Make a temporary context to hold all the junk */
5332 if (subcontext)
5334 "accumArrayResult",
5336
5337 astate = (ArrayBuildState *)
5339 astate->mcontext = arr_context;
5340 astate->private_cxt = subcontext;
5341 astate->alen = initsize;
5342 astate->dvalues = (Datum *)
5343 MemoryContextAlloc(arr_context, astate->alen * sizeof(Datum));
5344 astate->dnulls = (bool *)
5345 MemoryContextAlloc(arr_context, astate->alen * sizeof(bool));
5346 astate->nelems = 0;
5347 astate->element_type = element_type;
5348 get_typlenbyvalalign(element_type,
5349 &astate->typlen,
5350 &astate->typbyval,
5351 &astate->typalign);
5352
5353 return astate;
5354}
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, fb(), 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 5435 of file arrayfuncs.c.

5437{
5438 int ndims;
5439 int dims[1];
5440 int lbs[1];
5441
5442 /* If no elements were presented, we want to create an empty array */
5443 ndims = (astate->nelems > 0) ? 1 : 0;
5444 dims[0] = astate->nelems;
5445 lbs[0] = 1;
5446
5447 return makeMdArrayResult(astate, ndims, dims, lbs, rcontext,
5448 astate->private_cxt);
5449}
Datum makeMdArrayResult(ArrayBuildState *astate, int ndims, int *dims, int *lbs, MemoryContext rcontext, bool release)

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

5874{
5875 Datum result;
5876
5877 if (astate->scalarstate)
5878 {
5879 /* Must use makeMdArrayResult to support "release" parameter */
5880 int ndims;
5881 int dims[1];
5882 int lbs[1];
5883
5884 /* If no elements were presented, we want to create an empty array */
5885 ndims = (astate->scalarstate->nelems > 0) ? 1 : 0;
5886 dims[0] = astate->scalarstate->nelems;
5887 lbs[0] = 1;
5888
5889 result = makeMdArrayResult(astate->scalarstate, ndims, dims, lbs,
5890 rcontext, release);
5891 }
5892 else
5893 {
5894 result = makeArrayResultArr(astate->arraystate,
5895 rcontext, release);
5896 }
5897 return result;
5898}
Datum makeArrayResultArr(ArrayBuildStateArr *astate, MemoryContext rcontext, bool release)

References ArrayBuildStateAny::arraystate, fb(), 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 5718 of file arrayfuncs.c.

5721{
5722 ArrayType *result;
5723 MemoryContext oldcontext;
5724
5725 /* Build the final array result in rcontext */
5726 oldcontext = MemoryContextSwitchTo(rcontext);
5727
5728 if (astate->ndims == 0)
5729 {
5730 /* No inputs, return empty array */
5731 result = construct_empty_array(astate->element_type);
5732 }
5733 else
5734 {
5735 int dataoffset,
5736 nbytes;
5737
5738 /* Check for overflow of the array dimensions */
5739 (void) ArrayGetNItems(astate->ndims, astate->dims);
5740 ArrayCheckBounds(astate->ndims, astate->dims, astate->lbs);
5741
5742 /* Compute required space */
5743 nbytes = astate->nbytes;
5744 if (astate->nullbitmap != NULL)
5745 {
5746 dataoffset = ARR_OVERHEAD_WITHNULLS(astate->ndims, astate->nitems);
5747 nbytes += dataoffset;
5748 }
5749 else
5750 {
5751 dataoffset = 0;
5752 nbytes += ARR_OVERHEAD_NONULLS(astate->ndims);
5753 }
5754
5755 result = (ArrayType *) palloc0(nbytes);
5756 SET_VARSIZE(result, nbytes);
5757 result->ndim = astate->ndims;
5758 result->dataoffset = dataoffset;
5759 result->elemtype = astate->element_type;
5760
5761 memcpy(ARR_DIMS(result), astate->dims, astate->ndims * sizeof(int));
5762 memcpy(ARR_LBOUND(result), astate->lbs, astate->ndims * sizeof(int));
5763 memcpy(ARR_DATA_PTR(result), astate->data, astate->nbytes);
5764
5765 if (astate->nullbitmap != NULL)
5767 astate->nullbitmap, 0,
5768 astate->nitems);
5769 }
5770
5771 MemoryContextSwitchTo(oldcontext);
5772
5773 /* Clean up all the junk */
5774 if (release)
5775 {
5776 Assert(astate->private_cxt);
5778 }
5779
5780 return PointerGetDatum(result);
5781}
void MemoryContextDelete(MemoryContext context)
Definition mcxt.c:472

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

5473{
5474 ArrayType *result;
5475 MemoryContext oldcontext;
5476
5477 /* Build the final array result in rcontext */
5478 oldcontext = MemoryContextSwitchTo(rcontext);
5479
5480 result = construct_md_array(astate->dvalues,
5481 astate->dnulls,
5482 ndims,
5483 dims,
5484 lbs,
5485 astate->element_type,
5486 astate->typlen,
5487 astate->typbyval,
5488 astate->typalign);
5489
5490 MemoryContextSwitchTo(oldcontext);
5491
5492 /* Clean up all the junk */
5493 if (release)
5494 {
5495 Assert(astate->private_cxt);
5497 }
5498
5499 return PointerGetDatum(result);
5500}

References Assert, construct_md_array(), ArrayBuildState::dnulls, ArrayBuildState::dvalues, ArrayBuildState::element_type, fb(), 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 1458 of file arrayfuncs.c.

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

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

References ereturn, errcode(), errdetail(), errmsg(), fb(), 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 583 of file arrayfuncs.c.

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

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

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

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

Referenced by ReadArrayDimensions().

◆ trim_array()

Datum trim_array ( PG_FUNCTION_ARGS  )

Definition at line 6942 of file arrayfuncs.c.

6943{
6945 int n = PG_GETARG_INT32(1);
6946 int array_length = (ARR_NDIM(v) > 0) ? ARR_DIMS(v)[0] : 0;
6947 int16 elmlen;
6948 bool elmbyval;
6949 char elmalign;
6950 int lower[MAXDIM];
6951 int upper[MAXDIM];
6952 bool lowerProvided[MAXDIM];
6953 bool upperProvided[MAXDIM];
6954 Datum result;
6955
6956 /* Per spec, throw an error if out of bounds */
6958 ereport(ERROR,
6960 errmsg("number of elements to trim must be between 0 and %d",
6961 array_length)));
6962
6963 /* Set all the bounds as unprovided except the first upper bound */
6964 memset(lowerProvided, false, sizeof(lowerProvided));
6965 memset(upperProvided, false, sizeof(upperProvided));
6966 if (ARR_NDIM(v) > 0)
6967 {
6968 upper[0] = ARR_LBOUND(v)[0] + array_length - n - 1;
6969 upperProvided[0] = true;
6970 }
6971
6972 /* Fetch the needed information about the element type */
6973 get_typlenbyvalalign(ARR_ELEMTYPE(v), &elmlen, &elmbyval, &elmalign);
6974
6975 /* Get the slice */
6976 result = array_get_slice(PointerGetDatum(v), 1,
6978 -1, elmlen, elmbyval, elmalign);
6979
6980 PG_RETURN_DATUM(result);
6981}
Datum array_length(PG_FUNCTION_ARGS)
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 lower(PG_FUNCTION_ARGS)
Datum upper(PG_FUNCTION_ARGS)

References ARR_DIMS, ARR_ELEMTYPE, ARR_LBOUND, ARR_NDIM, array_get_slice(), array_length(), ereport, errcode(), errmsg(), ERROR, fb(), 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 6709 of file arrayfuncs.c.

6710{
6711 Datum operand = PG_GETARG_DATUM(0);
6713 Oid collation = PG_GET_COLLATION();
6714 Oid element_type = ARR_ELEMTYPE(thresholds);
6715 int result;
6716
6717 /* Check input */
6718 if (ARR_NDIM(thresholds) > 1)
6719 ereport(ERROR,
6721 errmsg("thresholds must be one-dimensional array")));
6722
6724 ereport(ERROR,
6726 errmsg("thresholds array must not contain NULLs")));
6727
6728 /* We have a dedicated implementation for float8 data */
6729 if (element_type == FLOAT8OID)
6730 result = width_bucket_array_float8(operand, thresholds);
6731 else
6732 {
6733 TypeCacheEntry *typentry;
6734
6735 /* Cache information about the input type */
6736 typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
6737 if (typentry == NULL ||
6738 typentry->type_id != element_type)
6739 {
6740 typentry = lookup_type_cache(element_type,
6742 if (!OidIsValid(typentry->cmp_proc_finfo.fn_oid))
6743 ereport(ERROR,
6745 errmsg("could not identify a comparison function for type %s",
6746 format_type_be(element_type))));
6747 fcinfo->flinfo->fn_extra = typentry;
6748 }
6749
6750 /*
6751 * We have separate implementation paths for fixed- and variable-width
6752 * types, since indexing the array is a lot cheaper in the first case.
6753 */
6754 if (typentry->typlen > 0)
6755 result = width_bucket_array_fixed(operand, thresholds,
6756 collation, typentry);
6757 else
6758 result = width_bucket_array_variable(operand, thresholds,
6759 collation, typentry);
6760 }
6761
6762 /* Avoid leaking memory when handed toasted input. */
6764
6765 PG_RETURN_INT32(result);
6766}
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)
#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, fb(), FmgrInfo::fn_oid, format_type_be(), 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 6816 of file arrayfuncs.c.

6820{
6822 char *thresholds_data;
6823 int typlen = typentry->typlen;
6824 bool typbyval = typentry->typbyval;
6825 int left;
6826 int right;
6827
6828 /*
6829 * Since we know the array contains no NULLs, we can just index it
6830 * directly.
6831 */
6833
6835 collation, NULL, NULL);
6836
6837 /* Find the bucket */
6838 left = 0;
6840 while (left < right)
6841 {
6842 int mid = (left + right) / 2;
6843 char *ptr;
6845
6846 ptr = thresholds_data + mid * typlen;
6847
6848 locfcinfo->args[0].value = operand;
6849 locfcinfo->args[0].isnull = false;
6850 locfcinfo->args[1].value = fetch_att(ptr, typbyval, typlen);
6851 locfcinfo->args[1].isnull = false;
6852
6854
6855 /* We don't expect comparison support functions to return null */
6856 Assert(!locfcinfo->isnull);
6857
6858 if (cmpresult < 0)
6859 right = mid;
6860 else
6861 left = mid + 1;
6862 }
6863
6864 return left;
6865}

References ARR_DATA_PTR, ARR_DIMS, ARR_NDIM, ArrayGetNItems(), Assert, TypeCacheEntry::cmp_proc_finfo, DatumGetInt32(), fb(), 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 6772 of file arrayfuncs.c.

6773{
6774 float8 op = DatumGetFloat8(operand);
6776 int left;
6777 int right;
6778
6779 /*
6780 * Since we know the array contains no NULLs, we can just index it
6781 * directly.
6782 */
6784
6785 left = 0;
6787
6788 /*
6789 * If the probe value is a NaN, it's greater than or equal to all possible
6790 * threshold values (including other NaNs), so we need not search. Note
6791 * that this would give the same result as searching even if the array
6792 * contains multiple NaNs (as long as they're correctly sorted), since the
6793 * loop logic will find the rightmost of multiple equal threshold values.
6794 */
6795 if (isnan(op))
6796 return right;
6797
6798 /* Find the bucket */
6799 while (left < right)
6800 {
6801 int mid = (left + right) / 2;
6802
6803 if (isnan(thresholds_data[mid]) || op < thresholds_data[mid])
6804 right = mid;
6805 else
6806 left = mid + 1;
6807 }
6808
6809 return left;
6810}
static float8 DatumGetFloat8(Datum X)
Definition postgres.h:495

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

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

6875{
6877 char *thresholds_data;
6878 int typlen = typentry->typlen;
6879 bool typbyval = typentry->typbyval;
6880 char typalign = typentry->typalign;
6881 uint8 typalignby = typalign_to_alignby(typalign);
6882 int left;
6883 int right;
6884
6886
6888 collation, NULL, NULL);
6889
6890 /* Find the bucket */
6891 left = 0;
6893 while (left < right)
6894 {
6895 int mid = (left + right) / 2;
6896 char *ptr;
6897 int i;
6899
6900 /* Locate mid'th array element by advancing from left element */
6901 ptr = thresholds_data;
6902 for (i = left; i < mid; i++)
6903 {
6904 ptr = att_addlength_pointer(ptr, typlen, ptr);
6905 ptr = (char *) att_nominal_alignby(ptr, typalignby);
6906 }
6907
6908 locfcinfo->args[0].value = operand;
6909 locfcinfo->args[0].isnull = false;
6910 locfcinfo->args[1].value = fetch_att(ptr, typbyval, typlen);
6911 locfcinfo->args[1].isnull = false;
6912
6914
6915 /* We don't expect comparison support functions to return null */
6916 Assert(!locfcinfo->isnull);
6917
6918 if (cmpresult < 0)
6919 right = mid;
6920 else
6921 {
6922 left = mid + 1;
6923
6924 /*
6925 * Move the thresholds pointer to match new "left" index, so we
6926 * don't have to seek over those elements again. This trick
6927 * ensures we do only O(N) array indexing work, not O(N^2).
6928 */
6929 ptr = att_addlength_pointer(ptr, typlen, ptr);
6930 thresholds_data = (char *) att_nominal_alignby(ptr, typalignby);
6931 }
6932 }
6933
6934 return left;
6935}

References ARR_DATA_PTR, ARR_DIMS, ARR_NDIM, ArrayGetNItems(), Assert, att_addlength_pointer, att_nominal_alignby, TypeCacheEntry::cmp_proc_finfo, DatumGetInt32(), fb(), fetch_att(), FunctionCallInvoke, i, InitFunctionCallInfoData, LOCAL_FCINFO, typalign, TypeCacheEntry::typalign, typalign_to_alignby(), 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().