aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/arrayfuncs.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/adt/arrayfuncs.c')
-rw-r--r--src/backend/utils/adt/arrayfuncs.c991
1 files changed, 599 insertions, 392 deletions
diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c
index 9117a5515a9..82d79977d7a 100644
--- a/src/backend/utils/adt/arrayfuncs.c
+++ b/src/backend/utils/adt/arrayfuncs.c
@@ -20,11 +20,15 @@
#endif
#include <math.h>
+/* See arrayaccess.h */
+#define ARRAYACCESS_INCLUDE_DEFINITIONS
+
#include "access/htup_details.h"
#include "catalog/pg_type.h"
#include "funcapi.h"
#include "libpq/pqformat.h"
#include "utils/array.h"
+#include "utils/arrayaccess.h"
#include "utils/builtins.h"
#include "utils/datum.h"
#include "utils/lsyscache.h"
@@ -42,6 +46,12 @@ bool Array_nulls = true;
*/
#define ASSGN "="
+#define AARR_FREE_IF_COPY(array,n) \
+ do { \
+ if (!VARATT_IS_EXPANDED_HEADER(array)) \
+ PG_FREE_IF_COPY(array, n); \
+ } while (0)
+
typedef enum
{
ARRAY_NO_LEVEL,
@@ -93,10 +103,16 @@ static void ReadArrayBinary(StringInfo buf, int nitems,
int typlen, bool typbyval, char typalign,
Datum *values, bool *nulls,
bool *hasnulls, int32 *nbytes);
-static void CopyArrayEls(ArrayType *array,
- Datum *values, bool *nulls, int nitems,
- int typlen, bool typbyval, char typalign,
- bool freedata);
+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);
@@ -939,7 +955,7 @@ ReadArrayStr(char *arrayStr,
* the values are not toasted. (Doing it here doesn't work since the
* caller has already allocated space for the array...)
*/
-static void
+void
CopyArrayEls(ArrayType *array,
Datum *values,
bool *nulls,
@@ -997,8 +1013,8 @@ CopyArrayEls(ArrayType *array,
Datum
array_out(PG_FUNCTION_ARGS)
{
- ArrayType *v = PG_GETARG_ARRAYTYPE_P(0);
- Oid element_type = ARR_ELEMTYPE(v);
+ AnyArrayType *v = PG_GETARG_ANY_ARRAY(0);
+ Oid element_type = AARR_ELEMTYPE(v);
int typlen;
bool typbyval;
char typalign;
@@ -1014,8 +1030,6 @@ array_out(PG_FUNCTION_ARGS)
*
* +2 allows for assignment operator + trailing null
*/
- bits8 *bitmap;
- int bitmask;
bool *needquotes,
needdims = false;
int nitems,
@@ -1027,6 +1041,7 @@ array_out(PG_FUNCTION_ARGS)
int ndim,
*dims,
*lb;
+ array_iter iter;
ArrayMetaState *my_extra;
/*
@@ -1061,9 +1076,9 @@ array_out(PG_FUNCTION_ARGS)
typalign = my_extra->typalign;
typdelim = my_extra->typdelim;
- ndim = ARR_NDIM(v);
- dims = ARR_DIMS(v);
- lb = ARR_LBOUND(v);
+ ndim = AARR_NDIM(v);
+ dims = AARR_DIMS(v);
+ lb = AARR_LBOUND(v);
nitems = ArrayGetNItems(ndim, dims);
if (nitems == 0)
@@ -1094,16 +1109,19 @@ array_out(PG_FUNCTION_ARGS)
needquotes = (bool *) palloc(nitems * sizeof(bool));
overall_length = 1; /* don't forget to count \0 at end. */
- p = ARR_DATA_PTR(v);
- bitmap = ARR_NULLBITMAP(v);
- bitmask = 1;
+ array_iter_setup(&iter, v);
for (i = 0; i < nitems; i++)
{
+ Datum itemvalue;
+ bool isnull;
bool needquote;
/* Get source element, checking for NULL */
- if (bitmap && (*bitmap & bitmask) == 0)
+ itemvalue = array_iter_next(&iter, &isnull, i,
+ typlen, typbyval, typalign);
+
+ if (isnull)
{
values[i] = pstrdup("NULL");
overall_length += 4;
@@ -1111,12 +1129,7 @@ array_out(PG_FUNCTION_ARGS)
}
else
{
- Datum itemvalue;
-
- itemvalue = fetch_att(p, typbyval, typlen);
values[i] = OutputFunctionCall(&my_extra->proc, itemvalue);
- p = att_addlength_pointer(p, typlen, p);
- p = (char *) att_align_nominal(p, typalign);
/* count data plus backslashes; detect chars needing quotes */
if (values[i][0] == '\0')
@@ -1149,17 +1162,6 @@ array_out(PG_FUNCTION_ARGS)
overall_length += 2;
/* and the comma */
overall_length += 1;
-
- /* advance bitmap pointer if any */
- if (bitmap)
- {
- bitmask <<= 1;
- if (bitmask == 0x100)
- {
- bitmap++;
- bitmask = 1;
- }
- }
}
/*
@@ -1534,19 +1536,18 @@ ReadArrayBinary(StringInfo buf,
Datum
array_send(PG_FUNCTION_ARGS)
{
- ArrayType *v = PG_GETARG_ARRAYTYPE_P(0);
- Oid element_type = ARR_ELEMTYPE(v);
+ AnyArrayType *v = PG_GETARG_ANY_ARRAY(0);
+ Oid element_type = AARR_ELEMTYPE(v);
int typlen;
bool typbyval;
char typalign;
- char *p;
- bits8 *bitmap;
- int bitmask;
int nitems,
i;
int ndim,
- *dim;
+ *dim,
+ *lb;
StringInfoData buf;
+ array_iter iter;
ArrayMetaState *my_extra;
/*
@@ -1583,60 +1584,49 @@ array_send(PG_FUNCTION_ARGS)
typbyval = my_extra->typbyval;
typalign = my_extra->typalign;
- ndim = ARR_NDIM(v);
- dim = ARR_DIMS(v);
+ ndim = AARR_NDIM(v);
+ dim = AARR_DIMS(v);
+ lb = AARR_LBOUND(v);
nitems = ArrayGetNItems(ndim, dim);
pq_begintypsend(&buf);
/* Send the array header information */
pq_sendint(&buf, ndim, 4);
- pq_sendint(&buf, ARR_HASNULL(v) ? 1 : 0, 4);
+ pq_sendint(&buf, AARR_HASNULL(v) ? 1 : 0, 4);
pq_sendint(&buf, element_type, sizeof(Oid));
for (i = 0; i < ndim; i++)
{
- pq_sendint(&buf, ARR_DIMS(v)[i], 4);
- pq_sendint(&buf, ARR_LBOUND(v)[i], 4);
+ pq_sendint(&buf, dim[i], 4);
+ pq_sendint(&buf, lb[i], 4);
}
/* Send the array elements using the element's own sendproc */
- p = ARR_DATA_PTR(v);
- bitmap = ARR_NULLBITMAP(v);
- bitmask = 1;
+ array_iter_setup(&iter, v);
for (i = 0; i < nitems; i++)
{
+ Datum itemvalue;
+ bool isnull;
+
/* Get source element, checking for NULL */
- if (bitmap && (*bitmap & bitmask) == 0)
+ itemvalue = array_iter_next(&iter, &isnull, i,
+ typlen, typbyval, typalign);
+
+ if (isnull)
{
/* -1 length means a NULL */
pq_sendint(&buf, -1, 4);
}
else
{
- Datum itemvalue;
bytea *outputbytes;
- itemvalue = fetch_att(p, typbyval, typlen);
outputbytes = SendFunctionCall(&my_extra->proc, itemvalue);
pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4);
pq_sendbytes(&buf, VARDATA(outputbytes),
VARSIZE(outputbytes) - VARHDRSZ);
pfree(outputbytes);
-
- p = att_addlength_pointer(p, typlen, p);
- p = (char *) att_align_nominal(p, typalign);
- }
-
- /* advance bitmap pointer if any */
- if (bitmap)
- {
- bitmask <<= 1;
- if (bitmask == 0x100)
- {
- bitmap++;
- bitmask = 1;
- }
}
}
@@ -1650,13 +1640,13 @@ array_send(PG_FUNCTION_ARGS)
Datum
array_ndims(PG_FUNCTION_ARGS)
{
- ArrayType *v = PG_GETARG_ARRAYTYPE_P(0);
+ AnyArrayType *v = PG_GETARG_ANY_ARRAY(0);
/* Sanity check: does it look like an array at all? */
- if (ARR_NDIM(v) <= 0 || ARR_NDIM(v) > MAXDIM)
+ if (AARR_NDIM(v) <= 0 || AARR_NDIM(v) > MAXDIM)
PG_RETURN_NULL();
- PG_RETURN_INT32(ARR_NDIM(v));
+ PG_RETURN_INT32(AARR_NDIM(v));
}
/*
@@ -1666,7 +1656,7 @@ array_ndims(PG_FUNCTION_ARGS)
Datum
array_dims(PG_FUNCTION_ARGS)
{
- ArrayType *v = PG_GETARG_ARRAYTYPE_P(0);
+ AnyArrayType *v = PG_GETARG_ANY_ARRAY(0);
char *p;
int i;
int *dimv,
@@ -1680,14 +1670,14 @@ array_dims(PG_FUNCTION_ARGS)
char buf[MAXDIM * 33 + 1];
/* Sanity check: does it look like an array at all? */
- if (ARR_NDIM(v) <= 0 || ARR_NDIM(v) > MAXDIM)
+ if (AARR_NDIM(v) <= 0 || AARR_NDIM(v) > MAXDIM)
PG_RETURN_NULL();
- dimv = ARR_DIMS(v);
- lb = ARR_LBOUND(v);
+ dimv = AARR_DIMS(v);
+ lb = AARR_LBOUND(v);
p = buf;
- for (i = 0; i < ARR_NDIM(v); i++)
+ for (i = 0; i < AARR_NDIM(v); i++)
{
sprintf(p, "[%d:%d]", lb[i], dimv[i] + lb[i] - 1);
p += strlen(p);
@@ -1704,20 +1694,20 @@ array_dims(PG_FUNCTION_ARGS)
Datum
array_lower(PG_FUNCTION_ARGS)
{
- ArrayType *v = PG_GETARG_ARRAYTYPE_P(0);
+ AnyArrayType *v = PG_GETARG_ANY_ARRAY(0);
int reqdim = PG_GETARG_INT32(1);
int *lb;
int result;
/* Sanity check: does it look like an array at all? */
- if (ARR_NDIM(v) <= 0 || ARR_NDIM(v) > MAXDIM)
+ if (AARR_NDIM(v) <= 0 || AARR_NDIM(v) > MAXDIM)
PG_RETURN_NULL();
/* Sanity check: was the requested dim valid */
- if (reqdim <= 0 || reqdim > ARR_NDIM(v))
+ if (reqdim <= 0 || reqdim > AARR_NDIM(v))
PG_RETURN_NULL();
- lb = ARR_LBOUND(v);
+ lb = AARR_LBOUND(v);
result = lb[reqdim - 1];
PG_RETURN_INT32(result);
@@ -1731,22 +1721,22 @@ array_lower(PG_FUNCTION_ARGS)
Datum
array_upper(PG_FUNCTION_ARGS)
{
- ArrayType *v = PG_GETARG_ARRAYTYPE_P(0);
+ AnyArrayType *v = PG_GETARG_ANY_ARRAY(0);
int reqdim = PG_GETARG_INT32(1);
int *dimv,
*lb;
int result;
/* Sanity check: does it look like an array at all? */
- if (ARR_NDIM(v) <= 0 || ARR_NDIM(v) > MAXDIM)
+ if (AARR_NDIM(v) <= 0 || AARR_NDIM(v) > MAXDIM)
PG_RETURN_NULL();
/* Sanity check: was the requested dim valid */
- if (reqdim <= 0 || reqdim > ARR_NDIM(v))
+ if (reqdim <= 0 || reqdim > AARR_NDIM(v))
PG_RETURN_NULL();
- lb = ARR_LBOUND(v);
- dimv = ARR_DIMS(v);
+ lb = AARR_LBOUND(v);
+ dimv = AARR_DIMS(v);
result = dimv[reqdim - 1] + lb[reqdim - 1] - 1;
@@ -1761,20 +1751,20 @@ array_upper(PG_FUNCTION_ARGS)
Datum
array_length(PG_FUNCTION_ARGS)
{
- ArrayType *v = PG_GETARG_ARRAYTYPE_P(0);
+ AnyArrayType *v = PG_GETARG_ANY_ARRAY(0);
int reqdim = PG_GETARG_INT32(1);
int *dimv;
int result;
/* Sanity check: does it look like an array at all? */
- if (ARR_NDIM(v) <= 0 || ARR_NDIM(v) > MAXDIM)
+ if (AARR_NDIM(v) <= 0 || AARR_NDIM(v) > MAXDIM)
PG_RETURN_NULL();
/* Sanity check: was the requested dim valid */
- if (reqdim <= 0 || reqdim > ARR_NDIM(v))
+ if (reqdim <= 0 || reqdim > AARR_NDIM(v))
PG_RETURN_NULL();
- dimv = ARR_DIMS(v);
+ dimv = AARR_DIMS(v);
result = dimv[reqdim - 1];
@@ -1788,9 +1778,9 @@ array_length(PG_FUNCTION_ARGS)
Datum
array_cardinality(PG_FUNCTION_ARGS)
{
- ArrayType *v = PG_GETARG_ARRAYTYPE_P(0);
+ AnyArrayType *v = PG_GETARG_ANY_ARRAY(0);
- PG_RETURN_INT32(ArrayGetNItems(ARR_NDIM(v), ARR_DIMS(v)));
+ PG_RETURN_INT32(ArrayGetNItems(AARR_NDIM(v), AARR_DIMS(v)));
}
@@ -1825,7 +1815,6 @@ array_get_element(Datum arraydatum,
char elmalign,
bool *isNull)
{
- ArrayType *array;
int i,
ndim,
*dim,
@@ -1850,10 +1839,22 @@ array_get_element(Datum arraydatum,
arraydataptr = (char *) DatumGetPointer(arraydatum);
arraynullsptr = NULL;
}
+ else if (VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(arraydatum)))
+ {
+ /* expanded array: let's do this in a separate function */
+ return array_get_element_expanded(arraydatum,
+ nSubscripts,
+ indx,
+ arraytyplen,
+ elmlen,
+ elmbyval,
+ elmalign,
+ isNull);
+ }
else
{
- /* detoast input array if necessary */
- array = DatumGetArrayTypeP(arraydatum);
+ /* detoast array if necessary, producing normal varlena input */
+ ArrayType *array = DatumGetArrayTypeP(arraydatum);
ndim = ARR_NDIM(array);
dim = ARR_DIMS(array);
@@ -1903,6 +1904,88 @@ array_get_element(Datum arraydatum,
}
/*
+ * Implementation of array_get_element() for an expanded array
+ */
+static Datum
+array_get_element_expanded(Datum arraydatum,
+ int nSubscripts, int *indx,
+ int arraytyplen,
+ int elmlen, bool elmbyval, char elmalign,
+ bool *isNull)
+{
+ ExpandedArrayHeader *eah;
+ int i,
+ ndim,
+ *dim,
+ *lb,
+ offset;
+ Datum *dvalues;
+ bool *dnulls;
+
+ eah = (ExpandedArrayHeader *) DatumGetEOHP(arraydatum);
+ Assert(eah->ea_magic == EA_MAGIC);
+
+ /* sanity-check caller's info against object */
+ Assert(arraytyplen == -1);
+ Assert(elmlen == eah->typlen);
+ Assert(elmbyval == eah->typbyval);
+ Assert(elmalign == eah->typalign);
+
+ ndim = eah->ndims;
+ dim = eah->dims;
+ lb = eah->lbound;
+
+ /*
+ * Return NULL for invalid subscript
+ */
+ if (ndim != nSubscripts || ndim <= 0 || ndim > MAXDIM)
+ {
+ *isNull = true;
+ return (Datum) 0;
+ }
+ for (i = 0; i < ndim; i++)
+ {
+ if (indx[i] < lb[i] || indx[i] >= (dim[i] + lb[i]))
+ {
+ *isNull = true;
+ return (Datum) 0;
+ }
+ }
+
+ /*
+ * Calculate the element number
+ */
+ offset = ArrayGetOffset(nSubscripts, dim, lb, indx);
+
+ /*
+ * Deconstruct array if we didn't already. Note that we apply this even
+ * if the input is nominally read-only: it should be safe enough.
+ */
+ deconstruct_expanded_array(eah);
+
+ dvalues = eah->dvalues;
+ dnulls = eah->dnulls;
+
+ /*
+ * Check for NULL array element
+ */
+ if (dnulls && dnulls[offset])
+ {
+ *isNull = true;
+ return (Datum) 0;
+ }
+
+ /*
+ * OK, get the element. It's OK to return a pass-by-ref value as a
+ * pointer into the expanded array, for the same reason that regular
+ * array_get_element can return a pointer into flat arrays: the value is
+ * assumed not to change for as long as the Datum reference can exist.
+ */
+ *isNull = false;
+ return dvalues[offset];
+}
+
+/*
* array_get_slice :
* This routine takes an array and a range of indices (upperIndex and
* lowerIndx), creates a new array structure for the referred elements
@@ -2083,7 +2166,9 @@ array_get_slice(Datum arraydatum,
*
* Result:
* A new array is returned, just like the old except for the one
- * modified entry. The original array object is not changed.
+ * modified entry. The original array object is not changed,
+ * unless what is passed is a read-write reference to an expanded
+ * array object; in that case the expanded array is updated in-place.
*
* For one-dimensional arrays only, we allow the array to be extended
* by assigning to a position outside the existing subscript range; any
@@ -2166,6 +2251,20 @@ array_set_element(Datum arraydatum,
if (elmlen == -1 && !isNull)
dataValue = PointerGetDatum(PG_DETOAST_DATUM(dataValue));
+ if (VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(arraydatum)))
+ {
+ /* expanded array: let's do this in a separate function */
+ return array_set_element_expanded(arraydatum,
+ nSubscripts,
+ indx,
+ dataValue,
+ isNull,
+ arraytyplen,
+ elmlen,
+ elmbyval,
+ elmalign);
+ }
+
/* detoast input array if necessary */
array = DatumGetArrayTypeP(arraydatum);
@@ -2355,6 +2454,251 @@ array_set_element(Datum arraydatum,
}
/*
+ * Implementation of array_set_element() for an expanded array
+ *
+ * Note: as with any operation on a read/write expanded object, we must
+ * take pains not to leave the object in a corrupt state if we fail partway
+ * through.
+ */
+static Datum
+array_set_element_expanded(Datum arraydatum,
+ int nSubscripts, int *indx,
+ Datum dataValue, bool isNull,
+ int arraytyplen,
+ int elmlen, bool elmbyval, char elmalign)
+{
+ ExpandedArrayHeader *eah;
+ Datum *dvalues;
+ bool *dnulls;
+ int i,
+ ndim,
+ dim[MAXDIM],
+ lb[MAXDIM],
+ offset;
+ bool dimschanged,
+ newhasnulls;
+ int addedbefore,
+ addedafter;
+ char *oldValue;
+
+ /* Convert to R/W object if not so already */
+ eah = DatumGetExpandedArray(arraydatum);
+
+ /* Sanity-check caller's info against object; we don't use it otherwise */
+ Assert(arraytyplen == -1);
+ Assert(elmlen == eah->typlen);
+ Assert(elmbyval == eah->typbyval);
+ Assert(elmalign == eah->typalign);
+
+ /*
+ * Copy dimension info into local storage. This allows us to modify the
+ * dimensions if needed, while not messing up the expanded value if we
+ * fail partway through.
+ */
+ ndim = eah->ndims;
+ Assert(ndim >= 0 && ndim <= MAXDIM);
+ memcpy(dim, eah->dims, ndim * sizeof(int));
+ memcpy(lb, eah->lbound, ndim * sizeof(int));
+ dimschanged = false;
+
+ /*
+ * if number of dims is zero, i.e. an empty array, create an array with
+ * nSubscripts dimensions, and set the lower bounds to the supplied
+ * subscripts.
+ */
+ if (ndim == 0)
+ {
+ /*
+ * Allocate adequate space for new dimension info. This is harmless
+ * if we fail later.
+ */
+ Assert(nSubscripts > 0 && nSubscripts <= MAXDIM);
+ eah->dims = (int *) MemoryContextAllocZero(eah->hdr.eoh_context,
+ nSubscripts * sizeof(int));
+ eah->lbound = (int *) MemoryContextAllocZero(eah->hdr.eoh_context,
+ nSubscripts * sizeof(int));
+
+ /* Update local copies of dimension info */
+ ndim = nSubscripts;
+ for (i = 0; i < nSubscripts; i++)
+ {
+ dim[i] = 0;
+ lb[i] = indx[i];
+ }
+ dimschanged = true;
+ }
+ else if (ndim != nSubscripts)
+ ereport(ERROR,
+ (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
+ errmsg("wrong number of array subscripts")));
+
+ /*
+ * Deconstruct array if we didn't already. (Someday maybe add a special
+ * case path for fixed-length, no-nulls cases, where we can overwrite an
+ * element in place without ever deconstructing. But today is not that
+ * day.)
+ */
+ deconstruct_expanded_array(eah);
+
+ /*
+ * Copy new element into array's context, if needed (we assume it's
+ * already detoasted, so no junk should be created). If we fail further
+ * down, this memory is leaked, but that's reasonably harmless.
+ */
+ if (!eah->typbyval && !isNull)
+ {
+ MemoryContext oldcxt = MemoryContextSwitchTo(eah->hdr.eoh_context);
+
+ dataValue = datumCopy(dataValue, false, eah->typlen);
+ MemoryContextSwitchTo(oldcxt);
+ }
+
+ dvalues = eah->dvalues;
+ dnulls = eah->dnulls;
+
+ newhasnulls = ((dnulls != NULL) || isNull);
+ addedbefore = addedafter = 0;
+
+ /*
+ * Check subscripts (this logic matches original array_set_element)
+ */
+ if (ndim == 1)
+ {
+ if (indx[0] < lb[0])
+ {
+ addedbefore = lb[0] - indx[0];
+ dim[0] += addedbefore;
+ lb[0] = indx[0];
+ dimschanged = true;
+ if (addedbefore > 1)
+ newhasnulls = true; /* will insert nulls */
+ }
+ if (indx[0] >= (dim[0] + lb[0]))
+ {
+ addedafter = indx[0] - (dim[0] + lb[0]) + 1;
+ dim[0] += addedafter;
+ dimschanged = true;
+ if (addedafter > 1)
+ newhasnulls = true; /* will insert nulls */
+ }
+ }
+ else
+ {
+ /*
+ * XXX currently we do not support extending multi-dimensional arrays
+ * during assignment
+ */
+ for (i = 0; i < ndim; i++)
+ {
+ if (indx[i] < lb[i] ||
+ indx[i] >= (dim[i] + lb[i]))
+ ereport(ERROR,
+ (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
+ errmsg("array subscript out of range")));
+ }
+ }
+
+ /* Now we can calculate linear offset of target item in array */
+ offset = ArrayGetOffset(nSubscripts, dim, lb, indx);
+
+ /* Physically enlarge existing dvalues/dnulls arrays if needed */
+ if (dim[0] > eah->dvalueslen)
+ {
+ /* We want some extra space if we're enlarging */
+ int newlen = dim[0] + dim[0] / 8;
+
+ newlen = Max(newlen, dim[0]); /* integer overflow guard */
+ eah->dvalues = dvalues = (Datum *)
+ repalloc(dvalues, newlen * sizeof(Datum));
+ if (dnulls)
+ eah->dnulls = dnulls = (bool *)
+ repalloc(dnulls, newlen * sizeof(bool));
+ eah->dvalueslen = newlen;
+ }
+
+ /*
+ * If we need a nulls bitmap and don't already have one, create it, being
+ * sure to mark all existing entries as not null.
+ */
+ if (newhasnulls && dnulls == NULL)
+ eah->dnulls = dnulls = (bool *)
+ MemoryContextAllocZero(eah->hdr.eoh_context,
+ eah->dvalueslen * sizeof(bool));
+
+ /*
+ * We now have all the needed space allocated, so we're ready to make
+ * irreversible changes. Be very wary of allowing failure below here.
+ */
+
+ /* Flattened value will no longer represent array accurately */
+ eah->fvalue = NULL;
+ /* And we don't know the flattened size either */
+ eah->flat_size = 0;
+
+ /* Update dimensionality info if needed */
+ if (dimschanged)
+ {
+ eah->ndims = ndim;
+ memcpy(eah->dims, dim, ndim * sizeof(int));
+ memcpy(eah->lbound, lb, ndim * sizeof(int));
+ }
+
+ /* Reposition items if needed, and fill addedbefore items with nulls */
+ if (addedbefore > 0)
+ {
+ memmove(dvalues + addedbefore, dvalues, eah->nelems * sizeof(Datum));
+ for (i = 0; i < addedbefore; i++)
+ dvalues[i] = (Datum) 0;
+ if (dnulls)
+ {
+ memmove(dnulls + addedbefore, dnulls, eah->nelems * sizeof(bool));
+ for (i = 0; i < addedbefore; i++)
+ dnulls[i] = true;
+ }
+ eah->nelems += addedbefore;
+ }
+
+ /* fill addedafter items with nulls */
+ if (addedafter > 0)
+ {
+ for (i = 0; i < addedafter; i++)
+ dvalues[eah->nelems + i] = (Datum) 0;
+ if (dnulls)
+ {
+ for (i = 0; i < addedafter; i++)
+ dnulls[eah->nelems + i] = true;
+ }
+ eah->nelems += addedafter;
+ }
+
+ /* Grab old element value for pfree'ing, if needed. */
+ if (!eah->typbyval && (dnulls == NULL || !dnulls[offset]))
+ oldValue = (char *) DatumGetPointer(dvalues[offset]);
+ else
+ oldValue = NULL;
+
+ /* And finally we can insert the new element. */
+ dvalues[offset] = dataValue;
+ if (dnulls)
+ dnulls[offset] = isNull;
+
+ /*
+ * Free old element if needed; this keeps repeated element replacements
+ * from bloating the array's storage. If the pfree somehow fails, it
+ * won't corrupt the array.
+ */
+ if (oldValue)
+ {
+ /* Don't try to pfree a part of the original flat array */
+ if (oldValue < eah->fstartptr || oldValue >= eah->fendptr)
+ pfree(oldValue);
+ }
+
+ /* Done, return standard TOAST pointer for object */
+ return EOHPGetRWDatum(&eah->hdr);
+}
+
+/*
* array_set_slice :
* This routine sets the value of a range of array locations (specified
* by upper and lower subscript values) to new values passed as
@@ -2734,8 +3078,6 @@ array_set(ArrayType *array, int nSubscripts, int *indx,
* the function fn(), and if nargs > 1 then argument positions after the
* first must be preset to the additional values to be passed. The
* first argument position initially holds the input array value.
- * * inpType: OID of element type of input array. This must be the same as,
- * or binary-compatible with, the first argument type of fn().
* * retType: OID of element type of output array. This must be the same as,
* or binary-compatible with, the result type of fn().
* * amstate: workspace for array_map. Must be zeroed by caller before
@@ -2749,14 +3091,12 @@ array_set(ArrayType *array, int nSubscripts, int *indx,
* the array are OK however.
*/
Datum
-array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType,
- ArrayMapState *amstate)
+array_map(FunctionCallInfo fcinfo, Oid retType, ArrayMapState *amstate)
{
- ArrayType *v;
+ AnyArrayType *v;
ArrayType *result;
Datum *values;
bool *nulls;
- Datum elt;
int *dim;
int ndim;
int nitems;
@@ -2764,15 +3104,14 @@ array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType,
int32 nbytes = 0;
int32 dataoffset;
bool hasnulls;
+ Oid inpType;
int inp_typlen;
bool inp_typbyval;
char inp_typalign;
int typlen;
bool typbyval;
char typalign;
- char *s;
- bits8 *bitmap;
- int bitmask;
+ array_iter iter;
ArrayMetaState *inp_extra;
ArrayMetaState *ret_extra;
@@ -2781,12 +3120,11 @@ array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType,
elog(ERROR, "invalid nargs: %d", fcinfo->nargs);
if (PG_ARGISNULL(0))
elog(ERROR, "null input array");
- v = PG_GETARG_ARRAYTYPE_P(0);
-
- Assert(ARR_ELEMTYPE(v) == inpType);
+ v = PG_GETARG_ANY_ARRAY(0);
- ndim = ARR_NDIM(v);
- dim = ARR_DIMS(v);
+ inpType = AARR_ELEMTYPE(v);
+ ndim = AARR_NDIM(v);
+ dim = AARR_DIMS(v);
nitems = ArrayGetNItems(ndim, dim);
/* Check for empty array */
@@ -2833,9 +3171,7 @@ array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType,
nulls = (bool *) palloc(nitems * sizeof(bool));
/* Loop over source data */
- s = ARR_DATA_PTR(v);
- bitmap = ARR_NULLBITMAP(v);
- bitmask = 1;
+ array_iter_setup(&iter, v);
hasnulls = false;
for (i = 0; i < nitems; i++)
@@ -2843,18 +3179,8 @@ array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType,
bool callit = true;
/* Get source element, checking for NULL */
- if (bitmap && (*bitmap & bitmask) == 0)
- {
- fcinfo->argnull[0] = true;
- }
- else
- {
- elt = fetch_att(s, inp_typbyval, inp_typlen);
- s = att_addlength_datum(s, inp_typlen, elt);
- s = (char *) att_align_nominal(s, inp_typalign);
- fcinfo->arg[0] = elt;
- fcinfo->argnull[0] = false;
- }
+ fcinfo->arg[0] = array_iter_next(&iter, &fcinfo->argnull[0], i,
+ inp_typlen, inp_typbyval, inp_typalign);
/*
* Apply the given function to source elt and extra args.
@@ -2899,17 +3225,6 @@ array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType,
errmsg("array size exceeds the maximum allowed (%d)",
(int) MaxAllocSize)));
}
-
- /* advance bitmap pointer if any */
- if (bitmap)
- {
- bitmask <<= 1;
- if (bitmask == 0x100)
- {
- bitmap++;
- bitmask = 1;
- }
- }
}
/* Allocate and initialize the result array */
@@ -2928,7 +3243,8 @@ array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType,
result->ndim = ndim;
result->dataoffset = dataoffset;
result->elemtype = retType;
- memcpy(ARR_DIMS(result), ARR_DIMS(v), 2 * ndim * sizeof(int));
+ memcpy(ARR_DIMS(result), AARR_DIMS(v), ndim * sizeof(int));
+ memcpy(ARR_LBOUND(result), AARR_LBOUND(v), ndim * sizeof(int));
/*
* Note: do not risk trying to pfree the results of the called function
@@ -3092,6 +3408,23 @@ construct_empty_array(Oid elmtype)
}
/*
+ * construct_empty_expanded_array: make an empty expanded array
+ * given only type information. (metacache can be NULL if not needed.)
+ */
+ExpandedArrayHeader *
+construct_empty_expanded_array(Oid element_type,
+ MemoryContext parentcontext,
+ ArrayMetaState *metacache)
+{
+ ArrayType *array = construct_empty_array(element_type);
+ Datum d;
+
+ d = expand_array(PointerGetDatum(array), parentcontext, metacache);
+ pfree(array);
+ return (ExpandedArrayHeader *) DatumGetEOHP(d);
+}
+
+/*
* deconstruct_array --- simple method for extracting data from an array
*
* array: array object to examine (must not be NULL)
@@ -3229,36 +3562,36 @@ array_contains_nulls(ArrayType *array)
Datum
array_eq(PG_FUNCTION_ARGS)
{
- ArrayType *array1 = PG_GETARG_ARRAYTYPE_P(0);
- ArrayType *array2 = PG_GETARG_ARRAYTYPE_P(1);
+ AnyArrayType *array1 = PG_GETARG_ANY_ARRAY(0);
+ AnyArrayType *array2 = PG_GETARG_ANY_ARRAY(1);
Oid collation = PG_GET_COLLATION();
- int ndims1 = ARR_NDIM(array1);
- int ndims2 = ARR_NDIM(array2);
- int *dims1 = ARR_DIMS(array1);
- int *dims2 = ARR_DIMS(array2);
- Oid element_type = ARR_ELEMTYPE(array1);
+ int ndims1 = AARR_NDIM(array1);
+ int ndims2 = AARR_NDIM(array2);
+ int *dims1 = AARR_DIMS(array1);
+ int *dims2 = AARR_DIMS(array2);
+ int *lbs1 = AARR_LBOUND(array1);
+ int *lbs2 = AARR_LBOUND(array2);
+ Oid element_type = AARR_ELEMTYPE(array1);
bool result = true;
int nitems;
TypeCacheEntry *typentry;
int typlen;
bool typbyval;
char typalign;
- char *ptr1;
- char *ptr2;
- bits8 *bitmap1;
- bits8 *bitmap2;
- int bitmask;
+ array_iter it1;
+ array_iter it2;
int i;
FunctionCallInfoData locfcinfo;
- if (element_type != ARR_ELEMTYPE(array2))
+ if (element_type != AARR_ELEMTYPE(array2))
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("cannot compare arrays of different element types")));
/* fast path if the arrays do not have the same dimensionality */
if (ndims1 != ndims2 ||
- memcmp(dims1, dims2, 2 * ndims1 * sizeof(int)) != 0)
+ memcmp(dims1, dims2, ndims1 * sizeof(int)) != 0 ||
+ memcmp(lbs1, lbs2, ndims1 * sizeof(int)) != 0)
result = false;
else
{
@@ -3293,11 +3626,8 @@ array_eq(PG_FUNCTION_ARGS)
/* Loop over source data */
nitems = ArrayGetNItems(ndims1, dims1);
- ptr1 = ARR_DATA_PTR(array1);
- ptr2 = ARR_DATA_PTR(array2);
- bitmap1 = ARR_NULLBITMAP(array1);
- bitmap2 = ARR_NULLBITMAP(array2);
- bitmask = 1; /* use same bitmask for both arrays */
+ array_iter_setup(&it1, array1);
+ array_iter_setup(&it2, array2);
for (i = 0; i < nitems; i++)
{
@@ -3308,42 +3638,10 @@ array_eq(PG_FUNCTION_ARGS)
bool oprresult;
/* Get elements, checking for NULL */
- if (bitmap1 && (*bitmap1 & bitmask) == 0)
- {
- isnull1 = true;
- elt1 = (Datum) 0;
- }
- else
- {
- isnull1 = false;
- elt1 = fetch_att(ptr1, typbyval, typlen);
- ptr1 = att_addlength_pointer(ptr1, typlen, ptr1);
- ptr1 = (char *) att_align_nominal(ptr1, typalign);
- }
-
- if (bitmap2 && (*bitmap2 & bitmask) == 0)
- {
- isnull2 = true;
- elt2 = (Datum) 0;
- }
- else
- {
- isnull2 = false;
- elt2 = fetch_att(ptr2, typbyval, typlen);
- ptr2 = att_addlength_pointer(ptr2, typlen, ptr2);
- ptr2 = (char *) att_align_nominal(ptr2, typalign);
- }
-
- /* advance bitmap pointers if any */
- bitmask <<= 1;
- if (bitmask == 0x100)
- {
- if (bitmap1)
- bitmap1++;
- if (bitmap2)
- bitmap2++;
- bitmask = 1;
- }
+ elt1 = array_iter_next(&it1, &isnull1, i,
+ typlen, typbyval, typalign);
+ elt2 = array_iter_next(&it2, &isnull2, i,
+ typlen, typbyval, typalign);
/*
* We consider two NULLs equal; NULL and not-NULL are unequal.
@@ -3374,8 +3672,8 @@ array_eq(PG_FUNCTION_ARGS)
}
/* Avoid leaking memory when handed toasted input. */
- PG_FREE_IF_COPY(array1, 0);
- PG_FREE_IF_COPY(array2, 1);
+ AARR_FREE_IF_COPY(array1, 0);
+ AARR_FREE_IF_COPY(array2, 1);
PG_RETURN_BOOL(result);
}
@@ -3435,31 +3733,28 @@ btarraycmp(PG_FUNCTION_ARGS)
static int
array_cmp(FunctionCallInfo fcinfo)
{
- ArrayType *array1 = PG_GETARG_ARRAYTYPE_P(0);
- ArrayType *array2 = PG_GETARG_ARRAYTYPE_P(1);
+ AnyArrayType *array1 = PG_GETARG_ANY_ARRAY(0);
+ AnyArrayType *array2 = PG_GETARG_ANY_ARRAY(1);
Oid collation = PG_GET_COLLATION();
- int ndims1 = ARR_NDIM(array1);
- int ndims2 = ARR_NDIM(array2);
- int *dims1 = ARR_DIMS(array1);
- int *dims2 = ARR_DIMS(array2);
+ int ndims1 = AARR_NDIM(array1);
+ int ndims2 = AARR_NDIM(array2);
+ int *dims1 = AARR_DIMS(array1);
+ int *dims2 = AARR_DIMS(array2);
int nitems1 = ArrayGetNItems(ndims1, dims1);
int nitems2 = ArrayGetNItems(ndims2, dims2);
- Oid element_type = ARR_ELEMTYPE(array1);
+ Oid element_type = AARR_ELEMTYPE(array1);
int result = 0;
TypeCacheEntry *typentry;
int typlen;
bool typbyval;
char typalign;
int min_nitems;
- char *ptr1;
- char *ptr2;
- bits8 *bitmap1;
- bits8 *bitmap2;
- int bitmask;
+ array_iter it1;
+ array_iter it2;
int i;
FunctionCallInfoData locfcinfo;
- if (element_type != ARR_ELEMTYPE(array2))
+ if (element_type != AARR_ELEMTYPE(array2))
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("cannot compare arrays of different element types")));
@@ -3495,11 +3790,8 @@ array_cmp(FunctionCallInfo fcinfo)
/* Loop over source data */
min_nitems = Min(nitems1, nitems2);
- ptr1 = ARR_DATA_PTR(array1);
- ptr2 = ARR_DATA_PTR(array2);
- bitmap1 = ARR_NULLBITMAP(array1);
- bitmap2 = ARR_NULLBITMAP(array2);
- bitmask = 1; /* use same bitmask for both arrays */
+ array_iter_setup(&it1, array1);
+ array_iter_setup(&it2, array2);
for (i = 0; i < min_nitems; i++)
{
@@ -3510,42 +3802,8 @@ array_cmp(FunctionCallInfo fcinfo)
int32 cmpresult;
/* Get elements, checking for NULL */
- if (bitmap1 && (*bitmap1 & bitmask) == 0)
- {
- isnull1 = true;
- elt1 = (Datum) 0;
- }
- else
- {
- isnull1 = false;
- elt1 = fetch_att(ptr1, typbyval, typlen);
- ptr1 = att_addlength_pointer(ptr1, typlen, ptr1);
- ptr1 = (char *) att_align_nominal(ptr1, typalign);
- }
-
- if (bitmap2 && (*bitmap2 & bitmask) == 0)
- {
- isnull2 = true;
- elt2 = (Datum) 0;
- }
- else
- {
- isnull2 = false;
- elt2 = fetch_att(ptr2, typbyval, typlen);
- ptr2 = att_addlength_pointer(ptr2, typlen, ptr2);
- ptr2 = (char *) att_align_nominal(ptr2, typalign);
- }
-
- /* advance bitmap pointers if any */
- bitmask <<= 1;
- if (bitmask == 0x100)
- {
- if (bitmap1)
- bitmap1++;
- if (bitmap2)
- bitmap2++;
- bitmask = 1;
- }
+ elt1 = array_iter_next(&it1, &isnull1, i, typlen, typbyval, typalign);
+ elt2 = array_iter_next(&it2, &isnull2, i, typlen, typbyval, typalign);
/*
* We consider two NULLs equal; NULL > not-NULL.
@@ -3604,8 +3862,7 @@ array_cmp(FunctionCallInfo fcinfo)
result = (ndims1 < ndims2) ? -1 : 1;
else
{
- /* this relies on LB array immediately following DIMS array */
- for (i = 0; i < ndims1 * 2; i++)
+ for (i = 0; i < ndims1; i++)
{
if (dims1[i] != dims2[i])
{
@@ -3613,12 +3870,26 @@ array_cmp(FunctionCallInfo fcinfo)
break;
}
}
+ if (result == 0)
+ {
+ int *lbound1 = AARR_LBOUND(array1);
+ int *lbound2 = AARR_LBOUND(array2);
+
+ for (i = 0; i < ndims1; i++)
+ {
+ if (lbound1[i] != lbound2[i])
+ {
+ result = (lbound1[i] < lbound2[i]) ? -1 : 1;
+ break;
+ }
+ }
+ }
}
}
/* Avoid leaking memory when handed toasted input. */
- PG_FREE_IF_COPY(array1, 0);
- PG_FREE_IF_COPY(array2, 1);
+ AARR_FREE_IF_COPY(array1, 0);
+ AARR_FREE_IF_COPY(array2, 1);
return result;
}
@@ -3633,20 +3904,18 @@ array_cmp(FunctionCallInfo fcinfo)
Datum
hash_array(PG_FUNCTION_ARGS)
{
- ArrayType *array = PG_GETARG_ARRAYTYPE_P(0);
- int ndims = ARR_NDIM(array);
- int *dims = ARR_DIMS(array);
- Oid element_type = ARR_ELEMTYPE(array);
+ AnyArrayType *array = PG_GETARG_ANY_ARRAY(0);
+ int ndims = AARR_NDIM(array);
+ int *dims = AARR_DIMS(array);
+ Oid element_type = AARR_ELEMTYPE(array);
uint32 result = 1;
int nitems;
TypeCacheEntry *typentry;
int typlen;
bool typbyval;
char typalign;
- char *ptr;
- bits8 *bitmap;
- int bitmask;
int i;
+ array_iter iter;
FunctionCallInfoData locfcinfo;
/*
@@ -3680,28 +3949,24 @@ hash_array(PG_FUNCTION_ARGS)
/* Loop over source data */
nitems = ArrayGetNItems(ndims, dims);
- ptr = ARR_DATA_PTR(array);
- bitmap = ARR_NULLBITMAP(array);
- bitmask = 1;
+ array_iter_setup(&iter, array);
for (i = 0; i < nitems; i++)
{
+ Datum elt;
+ bool isnull;
uint32 elthash;
/* Get element, checking for NULL */
- if (bitmap && (*bitmap & bitmask) == 0)
+ elt = array_iter_next(&iter, &isnull, i, typlen, typbyval, typalign);
+
+ if (isnull)
{
/* Treat nulls as having hashvalue 0 */
elthash = 0;
}
else
{
- Datum elt;
-
- elt = fetch_att(ptr, typbyval, typlen);
- ptr = att_addlength_pointer(ptr, typlen, ptr);
- ptr = (char *) att_align_nominal(ptr, typalign);
-
/* Apply the hash function */
locfcinfo.arg[0] = elt;
locfcinfo.argnull[0] = false;
@@ -3709,17 +3974,6 @@ hash_array(PG_FUNCTION_ARGS)
elthash = DatumGetUInt32(FunctionCallInvoke(&locfcinfo));
}
- /* advance bitmap pointer if any */
- if (bitmap)
- {
- bitmask <<= 1;
- if (bitmask == 0x100)
- {
- bitmap++;
- bitmask = 1;
- }
- }
-
/*
* Combine hash values of successive elements by multiplying the
* current value by 31 and adding on the new element's hash value.
@@ -3735,7 +3989,7 @@ hash_array(PG_FUNCTION_ARGS)
}
/* Avoid leaking memory when handed toasted input. */
- PG_FREE_IF_COPY(array, 0);
+ AARR_FREE_IF_COPY(array, 0);
PG_RETURN_UINT32(result);
}
@@ -3756,11 +4010,11 @@ hash_array(PG_FUNCTION_ARGS)
* When matchall is false, return true if any members of array1 are in array2.
*/
static bool
-array_contain_compare(ArrayType *array1, ArrayType *array2, Oid collation,
+array_contain_compare(AnyArrayType *array1, AnyArrayType *array2, Oid collation,
bool matchall, void **fn_extra)
{
bool result = matchall;
- Oid element_type = ARR_ELEMTYPE(array1);
+ Oid element_type = AARR_ELEMTYPE(array1);
TypeCacheEntry *typentry;
int nelems1;
Datum *values2;
@@ -3769,14 +4023,12 @@ array_contain_compare(ArrayType *array1, ArrayType *array2, Oid collation,
int typlen;
bool typbyval;
char typalign;
- char *ptr1;
- bits8 *bitmap1;
- int bitmask;
int i;
int j;
+ array_iter it1;
FunctionCallInfoData locfcinfo;
- if (element_type != ARR_ELEMTYPE(array2))
+ if (element_type != AARR_ELEMTYPE(array2))
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("cannot compare arrays of different element types")));
@@ -3809,8 +4061,18 @@ array_contain_compare(ArrayType *array1, ArrayType *array2, Oid collation,
* worthwhile to use deconstruct_array on it. We scan array1 the hard way
* however, since we very likely won't need to look at all of it.
*/
- deconstruct_array(array2, element_type, typlen, typbyval, typalign,
- &values2, &nulls2, &nelems2);
+ if (VARATT_IS_EXPANDED_HEADER(array2))
+ {
+ /* This should be safe even if input is read-only */
+ deconstruct_expanded_array(&(array2->xpn));
+ values2 = array2->xpn.dvalues;
+ nulls2 = array2->xpn.dnulls;
+ nelems2 = array2->xpn.nelems;
+ }
+ else
+ deconstruct_array(&(array2->flt),
+ element_type, typlen, typbyval, typalign,
+ &values2, &nulls2, &nelems2);
/*
* Apply the comparison operator to each pair of array elements.
@@ -3819,10 +4081,8 @@ array_contain_compare(ArrayType *array1, ArrayType *array2, Oid collation,
collation, NULL, NULL);
/* Loop over source data */
- nelems1 = ArrayGetNItems(ARR_NDIM(array1), ARR_DIMS(array1));
- ptr1 = ARR_DATA_PTR(array1);
- bitmap1 = ARR_NULLBITMAP(array1);
- bitmask = 1;
+ nelems1 = ArrayGetNItems(AARR_NDIM(array1), AARR_DIMS(array1));
+ array_iter_setup(&it1, array1);
for (i = 0; i < nelems1; i++)
{
@@ -3830,27 +4090,7 @@ array_contain_compare(ArrayType *array1, ArrayType *array2, Oid collation,
bool isnull1;
/* Get element, checking for NULL */
- if (bitmap1 && (*bitmap1 & bitmask) == 0)
- {
- isnull1 = true;
- elt1 = (Datum) 0;
- }
- else
- {
- isnull1 = false;
- elt1 = fetch_att(ptr1, typbyval, typlen);
- ptr1 = att_addlength_pointer(ptr1, typlen, ptr1);
- ptr1 = (char *) att_align_nominal(ptr1, typalign);
- }
-
- /* advance bitmap pointer if any */
- bitmask <<= 1;
- if (bitmask == 0x100)
- {
- if (bitmap1)
- bitmap1++;
- bitmask = 1;
- }
+ elt1 = array_iter_next(&it1, &isnull1, i, typlen, typbyval, typalign);
/*
* We assume that the comparison operator is strict, so a NULL can't
@@ -3909,17 +4149,14 @@ array_contain_compare(ArrayType *array1, ArrayType *array2, Oid collation,
}
}
- pfree(values2);
- pfree(nulls2);
-
return result;
}
Datum
arrayoverlap(PG_FUNCTION_ARGS)
{
- ArrayType *array1 = PG_GETARG_ARRAYTYPE_P(0);
- ArrayType *array2 = PG_GETARG_ARRAYTYPE_P(1);
+ AnyArrayType *array1 = PG_GETARG_ANY_ARRAY(0);
+ AnyArrayType *array2 = PG_GETARG_ANY_ARRAY(1);
Oid collation = PG_GET_COLLATION();
bool result;
@@ -3927,8 +4164,8 @@ arrayoverlap(PG_FUNCTION_ARGS)
&fcinfo->flinfo->fn_extra);
/* Avoid leaking memory when handed toasted input. */
- PG_FREE_IF_COPY(array1, 0);
- PG_FREE_IF_COPY(array2, 1);
+ AARR_FREE_IF_COPY(array1, 0);
+ AARR_FREE_IF_COPY(array2, 1);
PG_RETURN_BOOL(result);
}
@@ -3936,8 +4173,8 @@ arrayoverlap(PG_FUNCTION_ARGS)
Datum
arraycontains(PG_FUNCTION_ARGS)
{
- ArrayType *array1 = PG_GETARG_ARRAYTYPE_P(0);
- ArrayType *array2 = PG_GETARG_ARRAYTYPE_P(1);
+ AnyArrayType *array1 = PG_GETARG_ANY_ARRAY(0);
+ AnyArrayType *array2 = PG_GETARG_ANY_ARRAY(1);
Oid collation = PG_GET_COLLATION();
bool result;
@@ -3945,8 +4182,8 @@ arraycontains(PG_FUNCTION_ARGS)
&fcinfo->flinfo->fn_extra);
/* Avoid leaking memory when handed toasted input. */
- PG_FREE_IF_COPY(array1, 0);
- PG_FREE_IF_COPY(array2, 1);
+ AARR_FREE_IF_COPY(array1, 0);
+ AARR_FREE_IF_COPY(array2, 1);
PG_RETURN_BOOL(result);
}
@@ -3954,8 +4191,8 @@ arraycontains(PG_FUNCTION_ARGS)
Datum
arraycontained(PG_FUNCTION_ARGS)
{
- ArrayType *array1 = PG_GETARG_ARRAYTYPE_P(0);
- ArrayType *array2 = PG_GETARG_ARRAYTYPE_P(1);
+ AnyArrayType *array1 = PG_GETARG_ANY_ARRAY(0);
+ AnyArrayType *array2 = PG_GETARG_ANY_ARRAY(1);
Oid collation = PG_GET_COLLATION();
bool result;
@@ -3963,8 +4200,8 @@ arraycontained(PG_FUNCTION_ARGS)
&fcinfo->flinfo->fn_extra);
/* Avoid leaking memory when handed toasted input. */
- PG_FREE_IF_COPY(array1, 0);
- PG_FREE_IF_COPY(array2, 1);
+ AARR_FREE_IF_COPY(array1, 0);
+ AARR_FREE_IF_COPY(array2, 1);
PG_RETURN_BOOL(result);
}
@@ -4702,7 +4939,8 @@ initArrayResult(Oid element_type, MemoryContext rcontext, bool subcontext)
MemoryContextAlloc(arr_context, sizeof(ArrayBuildState));
astate->mcontext = arr_context;
astate->private_cxt = subcontext;
- astate->alen = (subcontext ? 64 : 8); /* arbitrary starting array size */
+ astate->alen = (subcontext ? 64 : 8); /* arbitrary starting array
+ * size */
astate->dvalues = (Datum *)
MemoryContextAlloc(arr_context, astate->alen * sizeof(Datum));
astate->dnulls = (bool *)
@@ -4878,10 +5116,11 @@ initArrayResultArr(Oid array_type, Oid element_type, MemoryContext rcontext,
bool subcontext)
{
ArrayBuildStateArr *astate;
- MemoryContext arr_context = rcontext; /* by default use the parent ctx */
+ MemoryContext arr_context = rcontext; /* by default use the parent
+ * ctx */
/* Lookup element type, unless element_type already provided */
- if (! OidIsValid(element_type))
+ if (!OidIsValid(element_type))
{
element_type = get_element_type(array_type);
@@ -5259,31 +5498,19 @@ makeArrayResultAny(ArrayBuildStateAny *astate,
Datum
array_larger(PG_FUNCTION_ARGS)
{
- ArrayType *v1,
- *v2,
- *result;
-
- v1 = PG_GETARG_ARRAYTYPE_P(0);
- v2 = PG_GETARG_ARRAYTYPE_P(1);
-
- result = ((array_cmp(fcinfo) > 0) ? v1 : v2);
-
- PG_RETURN_ARRAYTYPE_P(result);
+ if (array_cmp(fcinfo) > 0)
+ PG_RETURN_DATUM(PG_GETARG_DATUM(0));
+ else
+ PG_RETURN_DATUM(PG_GETARG_DATUM(1));
}
Datum
array_smaller(PG_FUNCTION_ARGS)
{
- ArrayType *v1,
- *v2,
- *result;
-
- v1 = PG_GETARG_ARRAYTYPE_P(0);
- v2 = PG_GETARG_ARRAYTYPE_P(1);
-
- result = ((array_cmp(fcinfo) < 0) ? v1 : v2);
-
- PG_RETURN_ARRAYTYPE_P(result);
+ if (array_cmp(fcinfo) < 0)
+ PG_RETURN_DATUM(PG_GETARG_DATUM(0));
+ else
+ PG_RETURN_DATUM(PG_GETARG_DATUM(1));
}
@@ -5308,7 +5535,7 @@ generate_subscripts(PG_FUNCTION_ARGS)
/* stuff done only on the first call of the function */
if (SRF_IS_FIRSTCALL())
{
- ArrayType *v = PG_GETARG_ARRAYTYPE_P(0);
+ AnyArrayType *v = PG_GETARG_ANY_ARRAY(0);
int reqdim = PG_GETARG_INT32(1);
int *lb,
*dimv;
@@ -5317,11 +5544,11 @@ generate_subscripts(PG_FUNCTION_ARGS)
funcctx = SRF_FIRSTCALL_INIT();
/* Sanity check: does it look like an array at all? */
- if (ARR_NDIM(v) <= 0 || ARR_NDIM(v) > MAXDIM)
+ if (AARR_NDIM(v) <= 0 || AARR_NDIM(v) > MAXDIM)
SRF_RETURN_DONE(funcctx);
/* Sanity check: was the requested dim valid */
- if (reqdim <= 0 || reqdim > ARR_NDIM(v))
+ if (reqdim <= 0 || reqdim > AARR_NDIM(v))
SRF_RETURN_DONE(funcctx);
/*
@@ -5330,8 +5557,8 @@ generate_subscripts(PG_FUNCTION_ARGS)
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
fctx = (generate_subscripts_fctx *) palloc(sizeof(generate_subscripts_fctx));
- lb = ARR_LBOUND(v);
- dimv = ARR_DIMS(v);
+ lb = AARR_LBOUND(v);
+ dimv = AARR_DIMS(v);
fctx->lower = lb[reqdim - 1];
fctx->upper = dimv[reqdim - 1] + lb[reqdim - 1] - 1;
@@ -5650,11 +5877,9 @@ array_unnest(PG_FUNCTION_ARGS)
{
typedef struct
{
- ArrayType *arr;
+ array_iter iter;
int nextelem;
int numelems;
- char *elemdataptr; /* this moves with nextelem */
- bits8 *arraynullsptr; /* this does not */
int16 elmlen;
bool elmbyval;
char elmalign;
@@ -5667,7 +5892,7 @@ array_unnest(PG_FUNCTION_ARGS)
/* stuff done only on the first call of the function */
if (SRF_IS_FIRSTCALL())
{
- ArrayType *arr;
+ AnyArrayType *arr;
/* create a function context for cross-call persistence */
funcctx = SRF_FIRSTCALL_INIT();
@@ -5684,23 +5909,28 @@ array_unnest(PG_FUNCTION_ARGS)
* and not before. (If no detoast happens, we assume the originally
* passed array will stick around till then.)
*/
- arr = PG_GETARG_ARRAYTYPE_P(0);
+ arr = PG_GETARG_ANY_ARRAY(0);
/* allocate memory for user context */
fctx = (array_unnest_fctx *) palloc(sizeof(array_unnest_fctx));
/* initialize state */
- fctx->arr = arr;
+ array_iter_setup(&fctx->iter, arr);
fctx->nextelem = 0;
- fctx->numelems = ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr));
-
- fctx->elemdataptr = ARR_DATA_PTR(arr);
- fctx->arraynullsptr = ARR_NULLBITMAP(arr);
+ fctx->numelems = ArrayGetNItems(AARR_NDIM(arr), AARR_DIMS(arr));
- get_typlenbyvalalign(ARR_ELEMTYPE(arr),
- &fctx->elmlen,
- &fctx->elmbyval,
- &fctx->elmalign);
+ if (VARATT_IS_EXPANDED_HEADER(arr))
+ {
+ /* we can just grab the type data from expanded array */
+ fctx->elmlen = arr->xpn.typlen;
+ fctx->elmbyval = arr->xpn.typbyval;
+ fctx->elmalign = arr->xpn.typalign;
+ }
+ else
+ get_typlenbyvalalign(AARR_ELEMTYPE(arr),
+ &fctx->elmlen,
+ &fctx->elmbyval,
+ &fctx->elmalign);
funcctx->user_fctx = fctx;
MemoryContextSwitchTo(oldcontext);
@@ -5715,32 +5945,8 @@ array_unnest(PG_FUNCTION_ARGS)
int offset = fctx->nextelem++;
Datum elem;
- /*
- * Check for NULL array element
- */
- if (array_get_isnull(fctx->arraynullsptr, offset))
- {
- fcinfo->isnull = true;
- elem = (Datum) 0;
- /* elemdataptr does not move */
- }
- else
- {
- /*
- * OK, get the element
- */
- char *ptr = fctx->elemdataptr;
-
- fcinfo->isnull = false;
- elem = ArrayCast(ptr, fctx->elmbyval, fctx->elmlen);
-
- /*
- * Advance elemdataptr over it
- */
- ptr = att_addlength_pointer(ptr, fctx->elmlen, ptr);
- ptr = (char *) att_align_nominal(ptr, fctx->elmalign);
- fctx->elemdataptr = ptr;
- }
+ elem = array_iter_next(&fctx->iter, &fcinfo->isnull, offset,
+ fctx->elmlen, fctx->elmbyval, fctx->elmalign);
SRF_RETURN_NEXT(funcctx, elem);
}
@@ -5992,7 +6198,8 @@ array_replace_internal(ArrayType *array,
result->ndim = ndim;
result->dataoffset = dataoffset;
result->elemtype = element_type;
- memcpy(ARR_DIMS(result), ARR_DIMS(array), 2 * ndim * sizeof(int));
+ memcpy(ARR_DIMS(result), ARR_DIMS(array), ndim * sizeof(int));
+ memcpy(ARR_LBOUND(result), ARR_LBOUND(array), ndim * sizeof(int));
if (remove)
{