summaryrefslogtreecommitdiff
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.c482
1 files changed, 441 insertions, 41 deletions
diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c
index 533b77c1cd..3e43e951e1 100644
--- a/src/backend/utils/adt/arrayfuncs.c
+++ b/src/backend/utils/adt/arrayfuncs.c
@@ -3,12 +3,12 @@
* arrayfuncs.c
* Support functions for arrays.
*
- * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.164 2010/02/26 02:01:07 momjian Exp $
+ * src/backend/utils/adt/arrayfuncs.c
*
*-------------------------------------------------------------------------
*/
@@ -50,6 +50,31 @@ typedef enum
ARRAY_LEVEL_DELIMITED
} ArrayParseState;
+/* Working state for array_iterate() */
+typedef struct ArrayIteratorData
+{
+ /* basic info about the array, set up during array_create_iterator() */
+ ArrayType *arr; /* array we're iterating through */
+ bits8 *nullbitmap; /* its null bitmap, if any */
+ int nitems; /* total number of elements in array */
+ int16 typlen; /* element type's length */
+ bool typbyval; /* element type's byval property */
+ char typalign; /* element type's align property */
+
+ /* information about the requested slice size */
+ int slice_ndim; /* slice dimension, or 0 if not slicing */
+ int slice_len; /* number of elements per slice */
+ int *slice_dims; /* slice dims array */
+ int *slice_lbound; /* slice lbound array */
+ Datum *slice_values; /* workspace of length slice_len */
+ bool *slice_nulls; /* workspace of length slice_len */
+
+ /* current position information, updated on each iteration */
+ char *data_ptr; /* our current position in the array */
+ int current_item; /* the item # we're at in the array */
+} ArrayIteratorData;
+
+static bool array_isspace(char ch);
static int ArrayCount(const char *str, int *dim, char typdelim);
static void ReadArrayStr(char *arrayStr, const char *origStr,
int nitems, int ndim, int *dim,
@@ -192,7 +217,7 @@ array_in(PG_FUNCTION_ARGS)
* Note: we currently allow whitespace between, but not within,
* dimension items.
*/
- while (isspace((unsigned char) *p))
+ while (array_isspace(*p))
p++;
if (*p != '[')
break; /* no more dimension items */
@@ -201,7 +226,7 @@ array_in(PG_FUNCTION_ARGS)
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
- ndim, MAXDIM)));
+ ndim + 1, MAXDIM)));
for (q = p; isdigit((unsigned char) *q) || (*q == '-') || (*q == '+'); q++);
if (q == p) /* no digits? */
@@ -265,7 +290,7 @@ array_in(PG_FUNCTION_ARGS)
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("missing assignment operator")));
p += strlen(ASSGN);
- while (isspace((unsigned char) *p))
+ while (array_isspace(*p))
p++;
/*
@@ -351,6 +376,27 @@ array_in(PG_FUNCTION_ARGS)
}
/*
+ * array_isspace() --- a non-locale-dependent isspace()
+ *
+ * We used to use isspace() for parsing array values, but that has
+ * undesirable results: an array value might be silently interpreted
+ * differently depending on the locale setting. Now we just hard-wire
+ * the traditional ASCII definition of isspace().
+ */
+static bool
+array_isspace(char ch)
+{
+ if (ch == ' ' ||
+ ch == '\t' ||
+ ch == '\n' ||
+ ch == '\r' ||
+ ch == '\v' ||
+ ch == '\f')
+ return true;
+ return false;
+}
+
+/*
* ArrayCount
* Determines the dimensions for an array string.
*
@@ -459,7 +505,7 @@ ArrayCount(const char *str, int *dim, char typdelim)
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
- nest_level, MAXDIM)));
+ nest_level + 1, MAXDIM)));
temp[nest_level] = 0;
nest_level++;
if (ndim < nest_level)
@@ -534,7 +580,7 @@ ArrayCount(const char *str, int *dim, char typdelim)
itemdone = true;
nelems[nest_level - 1]++;
}
- else if (!isspace((unsigned char) *ptr))
+ else if (!array_isspace(*ptr))
{
/*
* Other non-space characters must be after a
@@ -563,7 +609,7 @@ ArrayCount(const char *str, int *dim, char typdelim)
/* only whitespace is allowed after the closing brace */
while (*ptr)
{
- if (!isspace((unsigned char) *ptr++))
+ if (!array_isspace(*ptr++))
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("malformed array literal: \"%s\"", str)));
@@ -756,7 +802,7 @@ ReadArrayStr(char *arrayStr,
indx[ndim - 1]++;
srcptr++;
}
- else if (isspace((unsigned char) *srcptr))
+ else if (array_isspace(*srcptr))
{
/*
* If leading space, drop it immediately. Else, copy
@@ -1044,7 +1090,7 @@ array_out(PG_FUNCTION_ARGS)
overall_length += 1;
}
else if (ch == '{' || ch == '}' || ch == typdelim ||
- isspace((unsigned char) ch))
+ array_isspace(ch))
needquote = true;
}
}
@@ -1213,17 +1259,22 @@ array_recv(PG_FUNCTION_ARGS)
for (i = 0; i < ndim; i++)
{
- int ub;
-
dim[i] = pq_getmsgint(buf, 4);
lBound[i] = pq_getmsgint(buf, 4);
- ub = lBound[i] + dim[i] - 1;
- /* overflow? */
- if (lBound[i] > ub)
- ereport(ERROR,
- (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
- errmsg("integer out of range")));
+ /*
+ * Check overflow of upper bound. (ArrayNItems() below checks that
+ * dim[i] >= 0)
+ */
+ if (dim[i] != 0)
+ {
+ int ub = lBound[i] + dim[i] - 1;
+
+ if (lBound[i] > ub)
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("integer out of range")));
+ }
}
/* This checks for overflow of array dimensions */
@@ -1288,7 +1339,7 @@ array_recv(PG_FUNCTION_ARGS)
dataoffset = 0; /* marker for no null bitmap */
nbytes += ARR_OVERHEAD_NONULLS(ndim);
}
- retval = (ArrayType *) palloc(nbytes);
+ retval = (ArrayType *) palloc0(nbytes);
SET_VARSIZE(retval, nbytes);
retval->ndim = ndim;
retval->dataoffset = dataoffset;
@@ -1926,7 +1977,7 @@ array_get_slice(ArrayType *array,
bytes += ARR_OVERHEAD_NONULLS(ndim);
}
- newarray = (ArrayType *) palloc(bytes);
+ newarray = (ArrayType *) palloc0(bytes);
SET_VARSIZE(newarray, bytes);
newarray->ndim = ndim;
newarray->dataoffset = dataoffset;
@@ -2179,7 +2230,7 @@ array_set(ArrayType *array,
/*
* OK, create the new array and fill in header/dimensions
*/
- newarray = (ArrayType *) palloc(newsize);
+ newarray = (ArrayType *) palloc0(newsize);
SET_VARSIZE(newarray, newsize);
newarray->ndim = ndim;
newarray->dataoffset = newhasnulls ? overheadlen : 0;
@@ -2474,6 +2525,7 @@ array_set_slice(ArrayType *array,
{
/*
* here we must allow for possibility of slice larger than orig array
+ * and/or not adjacent to orig array subscripts
*/
int oldlb = ARR_LBOUND(array)[0];
int oldub = oldlb + ARR_DIMS(array)[0] - 1;
@@ -2482,10 +2534,12 @@ array_set_slice(ArrayType *array,
char *oldarraydata = ARR_DATA_PTR(array);
bits8 *oldarraybitmap = ARR_NULLBITMAP(array);
+ /* count/size of old array entries that will go before the slice */
itemsbefore = Min(slicelb, oldub + 1) - oldlb;
lenbefore = array_nelems_size(oldarraydata, 0, oldarraybitmap,
itemsbefore,
elmlen, elmbyval, elmalign);
+ /* count/size of old array entries that will be replaced by slice */
if (slicelb > sliceub)
{
nolditems = 0;
@@ -2499,13 +2553,14 @@ array_set_slice(ArrayType *array,
nolditems,
elmlen, elmbyval, elmalign);
}
- itemsafter = oldub - sliceub;
+ /* count/size of old array entries that will go after the slice */
+ itemsafter = oldub + 1 - Max(sliceub + 1, oldlb);
lenafter = olddatasize - lenbefore - olditemsize;
}
newsize = overheadlen + olddatasize - olditemsize + newitemsize;
- newarray = (ArrayType *) palloc(newsize);
+ newarray = (ArrayType *) palloc0(newsize);
SET_VARSIZE(newarray, newsize);
newarray->ndim = ndim;
newarray->dataoffset = newhasnulls ? overheadlen : 0;
@@ -2764,7 +2819,7 @@ array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType,
dataoffset = 0; /* marker for no null bitmap */
nbytes += ARR_OVERHEAD_NONULLS(ndim);
}
- result = (ArrayType *) palloc(nbytes);
+ result = (ArrayType *) palloc0(nbytes);
SET_VARSIZE(result, nbytes);
result->ndim = ndim;
result->dataoffset = dataoffset;
@@ -2900,7 +2955,7 @@ construct_md_array(Datum *elems,
dataoffset = 0; /* marker for no null bitmap */
nbytes += ARR_OVERHEAD_NONULLS(ndims);
}
- result = (ArrayType *) palloc(nbytes);
+ result = (ArrayType *) palloc0(nbytes);
SET_VARSIZE(result, nbytes);
result->ndim = ndims;
result->dataoffset = dataoffset;
@@ -2924,7 +2979,7 @@ construct_empty_array(Oid elmtype)
{
ArrayType *result;
- result = (ArrayType *) palloc(sizeof(ArrayType));
+ result = (ArrayType *) palloc0(sizeof(ArrayType));
SET_VARSIZE(result, sizeof(ArrayType));
result->ndim = 0;
result->dataoffset = 0;
@@ -2972,7 +3027,7 @@ deconstruct_array(ArrayType *array,
nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
*elemsp = elems = (Datum *) palloc(nelems * sizeof(Datum));
if (nullsp)
- *nullsp = nulls = (bool *) palloc(nelems * sizeof(bool));
+ *nullsp = nulls = (bool *) palloc0(nelems * sizeof(bool));
else
nulls = NULL;
*nelemsp = nelems;
@@ -2997,8 +3052,6 @@ deconstruct_array(ArrayType *array,
else
{
elems[i] = fetch_att(p, elmbyval, elmlen);
- if (nulls)
- nulls[i] = false;
p = att_addlength_pointer(p, elmlen, p);
p = (char *) att_align_nominal(p, elmalign);
}
@@ -3016,6 +3069,49 @@ deconstruct_array(ArrayType *array,
}
}
+/*
+ * array_contains_nulls --- detect whether an array has any null elements
+ *
+ * This gives an accurate answer, whereas testing ARR_HASNULL only tells
+ * if the array *might* contain a null.
+ */
+bool
+array_contains_nulls(ArrayType *array)
+{
+ int nelems;
+ bits8 *bitmap;
+ int bitmask;
+
+ /* Easy answer if there's no null bitmap */
+ if (!ARR_HASNULL(array))
+ return false;
+
+ nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
+
+ bitmap = ARR_NULLBITMAP(array);
+
+ /* check whole bytes of the bitmap byte-at-a-time */
+ while (nelems >= 8)
+ {
+ if (*bitmap != 0xFF)
+ return true;
+ bitmap++;
+ nelems -= 8;
+ }
+
+ /* check last partial byte */
+ bitmask = 1;
+ while (nelems > 0)
+ {
+ if ((*bitmap & bitmask) == 0)
+ return true;
+ bitmask <<= 1;
+ nelems--;
+ }
+
+ return false;
+}
+
/*
* array_eq :
@@ -3031,6 +3127,7 @@ array_eq(PG_FUNCTION_ARGS)
{
ArrayType *array1 = PG_GETARG_ARRAYTYPE_P(0);
ArrayType *array2 = PG_GETARG_ARRAYTYPE_P(1);
+ Oid collation = PG_GET_COLLATION();
int ndims1 = ARR_NDIM(array1);
int ndims2 = ARR_NDIM(array2);
int *dims1 = ARR_DIMS(array1);
@@ -3088,7 +3185,7 @@ array_eq(PG_FUNCTION_ARGS)
* apply the operator to each pair of array elements.
*/
InitFunctionCallInfoData(locfcinfo, &typentry->eq_opr_finfo, 2,
- NULL, NULL);
+ collation, NULL, NULL);
/* Loop over source data */
nitems = ArrayGetNItems(ndims1, dims1);
@@ -3236,6 +3333,7 @@ array_cmp(FunctionCallInfo fcinfo)
{
ArrayType *array1 = PG_GETARG_ARRAYTYPE_P(0);
ArrayType *array2 = PG_GETARG_ARRAYTYPE_P(1);
+ Oid collation = PG_GET_COLLATION();
int ndims1 = ARR_NDIM(array1);
int ndims2 = ARR_NDIM(array2);
int *dims1 = ARR_DIMS(array1);
@@ -3289,7 +3387,7 @@ array_cmp(FunctionCallInfo fcinfo)
* apply the operator to each pair of array elements.
*/
InitFunctionCallInfoData(locfcinfo, &typentry->cmp_proc_finfo, 2,
- NULL, NULL);
+ collation, NULL, NULL);
/* Loop over source data */
min_nitems = Min(nitems1, nitems2);
@@ -3423,6 +3521,123 @@ array_cmp(FunctionCallInfo fcinfo)
/*-----------------------------------------------------------------------------
+ * array hashing
+ * Hash the elements and combine the results.
+ *----------------------------------------------------------------------------
+ */
+
+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);
+ uint32 result = 1;
+ int nitems;
+ TypeCacheEntry *typentry;
+ int typlen;
+ bool typbyval;
+ char typalign;
+ char *ptr;
+ bits8 *bitmap;
+ int bitmask;
+ int i;
+ FunctionCallInfoData locfcinfo;
+
+ /*
+ * We arrange to look up the hash function only once per series of calls,
+ * assuming the element type doesn't change underneath us. The typcache
+ * is used so that we have no memory leakage when being used as an index
+ * support function.
+ */
+ typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
+ if (typentry == NULL ||
+ typentry->type_id != element_type)
+ {
+ typentry = lookup_type_cache(element_type,
+ TYPECACHE_HASH_PROC_FINFO);
+ if (!OidIsValid(typentry->hash_proc_finfo.fn_oid))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("could not identify a hash function for type %s",
+ format_type_be(element_type))));
+ fcinfo->flinfo->fn_extra = (void *) typentry;
+ }
+ typlen = typentry->typlen;
+ typbyval = typentry->typbyval;
+ typalign = typentry->typalign;
+
+ /*
+ * apply the hash function to each array element.
+ */
+ InitFunctionCallInfoData(locfcinfo, &typentry->hash_proc_finfo, 1,
+ InvalidOid, NULL, NULL);
+
+ /* Loop over source data */
+ nitems = ArrayGetNItems(ndims, dims);
+ ptr = ARR_DATA_PTR(array);
+ bitmap = ARR_NULLBITMAP(array);
+ bitmask = 1;
+
+ for (i = 0; i < nitems; i++)
+ {
+ uint32 elthash;
+
+ /* Get element, checking for NULL */
+ if (bitmap && (*bitmap & bitmask) == 0)
+ {
+ /* 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;
+ locfcinfo.isnull = false;
+ 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.
+ *
+ * The result is a sum in which each element's hash value is
+ * multiplied by a different power of 31. This is modulo 2^32
+ * arithmetic, and the powers of 31 modulo 2^32 form a cyclic group of
+ * order 2^27. So for arrays of up to 2^27 elements, each element's
+ * hash value is multiplied by a different (odd) number, resulting in
+ * a good mixing of all the elements' hash values.
+ */
+ result = (result << 5) - result + elthash;
+ }
+
+ /* Avoid leaking memory when handed toasted input. */
+ PG_FREE_IF_COPY(array, 0);
+
+ PG_RETURN_UINT32(result);
+}
+
+
+/*-----------------------------------------------------------------------------
* array overlap/containment comparisons
* These use the same methods of comparing array elements as array_eq.
* We consider only the elements of the arrays, ignoring dimensionality.
@@ -3437,8 +3652,8 @@ array_cmp(FunctionCallInfo fcinfo)
* When matchall is false, return true if any members of array1 are in array2.
*/
static bool
-array_contain_compare(ArrayType *array1, ArrayType *array2, bool matchall,
- void **fn_extra)
+array_contain_compare(ArrayType *array1, ArrayType *array2, Oid collation,
+ bool matchall, void **fn_extra)
{
bool result = matchall;
Oid element_type = ARR_ELEMTYPE(array1);
@@ -3497,7 +3712,7 @@ array_contain_compare(ArrayType *array1, ArrayType *array2, bool matchall,
* Apply the comparison operator to each pair of array elements.
*/
InitFunctionCallInfoData(locfcinfo, &typentry->eq_opr_finfo, 2,
- NULL, NULL);
+ collation, NULL, NULL);
/* Loop over source data */
nelems1 = ArrayGetNItems(ARR_NDIM(array1), ARR_DIMS(array1));
@@ -3601,9 +3816,10 @@ arrayoverlap(PG_FUNCTION_ARGS)
{
ArrayType *array1 = PG_GETARG_ARRAYTYPE_P(0);
ArrayType *array2 = PG_GETARG_ARRAYTYPE_P(1);
+ Oid collation = PG_GET_COLLATION();
bool result;
- result = array_contain_compare(array1, array2, false,
+ result = array_contain_compare(array1, array2, collation, false,
&fcinfo->flinfo->fn_extra);
/* Avoid leaking memory when handed toasted input. */
@@ -3618,9 +3834,10 @@ arraycontains(PG_FUNCTION_ARGS)
{
ArrayType *array1 = PG_GETARG_ARRAYTYPE_P(0);
ArrayType *array2 = PG_GETARG_ARRAYTYPE_P(1);
+ Oid collation = PG_GET_COLLATION();
bool result;
- result = array_contain_compare(array2, array1, true,
+ result = array_contain_compare(array2, array1, collation, true,
&fcinfo->flinfo->fn_extra);
/* Avoid leaking memory when handed toasted input. */
@@ -3635,9 +3852,10 @@ arraycontained(PG_FUNCTION_ARGS)
{
ArrayType *array1 = PG_GETARG_ARRAYTYPE_P(0);
ArrayType *array2 = PG_GETARG_ARRAYTYPE_P(1);
+ Oid collation = PG_GET_COLLATION();
bool result;
- result = array_contain_compare(array1, array2, true,
+ result = array_contain_compare(array1, array2, collation, true,
&fcinfo->flinfo->fn_extra);
/* Avoid leaking memory when handed toasted input. */
@@ -3648,6 +3866,188 @@ arraycontained(PG_FUNCTION_ARGS)
}
+/*-----------------------------------------------------------------------------
+ * Array iteration functions
+ * These functions are used to iterate efficiently through arrays
+ *-----------------------------------------------------------------------------
+ */
+
+/*
+ * array_create_iterator --- set up to iterate through an array
+ *
+ * If slice_ndim is zero, we will iterate element-by-element; the returned
+ * datums are of the array's element type.
+ *
+ * If slice_ndim is 1..ARR_NDIM(arr), we will iterate by slices: the
+ * returned datums are of the same array type as 'arr', but of size
+ * equal to the rightmost N dimensions of 'arr'.
+ *
+ * The passed-in array must remain valid for the lifetime of the iterator.
+ */
+ArrayIterator
+array_create_iterator(ArrayType *arr, int slice_ndim)
+{
+ ArrayIterator iterator = palloc0(sizeof(ArrayIteratorData));
+
+ /*
+ * Sanity-check inputs --- caller should have got this right already
+ */
+ Assert(PointerIsValid(arr));
+ if (slice_ndim < 0 || slice_ndim > ARR_NDIM(arr))
+ elog(ERROR, "invalid arguments to array_create_iterator");
+
+ /*
+ * Remember basic info about the array and its element type
+ */
+ iterator->arr = arr;
+ iterator->nullbitmap = ARR_NULLBITMAP(arr);
+ iterator->nitems = ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr));
+ get_typlenbyvalalign(ARR_ELEMTYPE(arr),
+ &iterator->typlen,
+ &iterator->typbyval,
+ &iterator->typalign);
+
+ /*
+ * Remember the slicing parameters.
+ */
+ iterator->slice_ndim = slice_ndim;
+
+ if (slice_ndim > 0)
+ {
+ /*
+ * Get pointers into the array's dims and lbound arrays to represent
+ * the dims/lbound arrays of a slice. These are the same as the
+ * rightmost N dimensions of the array.
+ */
+ iterator->slice_dims = ARR_DIMS(arr) + ARR_NDIM(arr) - slice_ndim;
+ iterator->slice_lbound = ARR_LBOUND(arr) + ARR_NDIM(arr) - slice_ndim;
+
+ /*
+ * Compute number of elements in a slice.
+ */
+ iterator->slice_len = ArrayGetNItems(slice_ndim,
+ iterator->slice_dims);
+
+ /*
+ * Create workspace for building sub-arrays.
+ */
+ iterator->slice_values = (Datum *)
+ palloc(iterator->slice_len * sizeof(Datum));
+ iterator->slice_nulls = (bool *)
+ palloc(iterator->slice_len * sizeof(bool));
+ }
+
+ /*
+ * Initialize our data pointer and linear element number. These will
+ * advance through the array during array_iterate().
+ */
+ iterator->data_ptr = ARR_DATA_PTR(arr);
+ iterator->current_item = 0;
+
+ return iterator;
+}
+
+/*
+ * Iterate through the array referenced by 'iterator'.
+ *
+ * As long as there is another element (or slice), return it into
+ * *value / *isnull, and return true. Return false when no more data.
+ */
+bool
+array_iterate(ArrayIterator iterator, Datum *value, bool *isnull)
+{
+ /* Done if we have reached the end of the array */
+ if (iterator->current_item >= iterator->nitems)
+ return false;
+
+ if (iterator->slice_ndim == 0)
+ {
+ /*
+ * Scalar case: return one element.
+ */
+ if (array_get_isnull(iterator->nullbitmap, iterator->current_item++))
+ {
+ *isnull = true;
+ *value = (Datum) 0;
+ }
+ else
+ {
+ /* non-NULL, so fetch the individual Datum to return */
+ char *p = iterator->data_ptr;
+
+ *isnull = false;
+ *value = fetch_att(p, iterator->typbyval, iterator->typlen);
+
+ /* Move our data pointer forward to the next element */
+ p = att_addlength_pointer(p, iterator->typlen, p);
+ p = (char *) att_align_nominal(p, iterator->typalign);
+ iterator->data_ptr = p;
+ }
+ }
+ else
+ {
+ /*
+ * Slice case: build and return an array of the requested size.
+ */
+ ArrayType *result;
+ Datum *values = iterator->slice_values;
+ bool *nulls = iterator->slice_nulls;
+ char *p = iterator->data_ptr;
+ int i;
+
+ for (i = 0; i < iterator->slice_len; i++)
+ {
+ if (array_get_isnull(iterator->nullbitmap,
+ iterator->current_item++))
+ {
+ nulls[i] = true;
+ values[i] = (Datum) 0;
+ }
+ else
+ {
+ nulls[i] = false;
+ values[i] = fetch_att(p, iterator->typbyval, iterator->typlen);
+
+ /* Move our data pointer forward to the next element */
+ p = att_addlength_pointer(p, iterator->typlen, p);
+ p = (char *) att_align_nominal(p, iterator->typalign);
+ }
+ }
+
+ iterator->data_ptr = p;
+
+ result = construct_md_array(values,
+ nulls,
+ iterator->slice_ndim,
+ iterator->slice_dims,
+ iterator->slice_lbound,
+ ARR_ELEMTYPE(iterator->arr),
+ iterator->typlen,
+ iterator->typbyval,
+ iterator->typalign);
+
+ *isnull = false;
+ *value = PointerGetDatum(result);
+ }
+
+ return true;
+}
+
+/*
+ * Release an ArrayIterator data structure
+ */
+void
+array_free_iterator(ArrayIterator iterator)
+{
+ if (iterator->slice_ndim > 0)
+ {
+ pfree(iterator->slice_values);
+ pfree(iterator->slice_nulls);
+ }
+ pfree(iterator);
+}
+
+
/***************************************************************************/
/******************| Support Routines |*****************/
/***************************************************************************/
@@ -4411,7 +4811,7 @@ array_fill_with_lower_bounds(PG_FUNCTION_ARGS)
if (PG_ARGISNULL(1) || PG_ARGISNULL(2))
ereport(ERROR,
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
- errmsg("dimension array or low bound array cannot be NULL")));
+ errmsg("dimension array or low bound array cannot be null")));
dims = PG_GETARG_ARRAYTYPE_P(1);
lbs = PG_GETARG_ARRAYTYPE_P(2);
@@ -4451,7 +4851,7 @@ array_fill(PG_FUNCTION_ARGS)
if (PG_ARGISNULL(1))
ereport(ERROR,
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
- errmsg("dimension array or low bound array cannot be NULL")));
+ errmsg("dimension array or low bound array cannot be null")));
dims = PG_GETARG_ARRAYTYPE_P(1);
@@ -4522,7 +4922,7 @@ array_fill_internal(ArrayType *dims, ArrayType *lbs,
errmsg("wrong range of array subscripts"),
errdetail("Lower bound of dimension array must be one.")));
- if (ARR_HASNULL(dims))
+ if (array_contains_nulls(dims))
ereport(ERROR,
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
errmsg("dimension values cannot be null")));
@@ -4554,7 +4954,7 @@ array_fill_internal(ArrayType *dims, ArrayType *lbs,
errmsg("wrong range of array subscripts"),
errdetail("Lower bound of dimension array must be one.")));
- if (ARR_HASNULL(lbs))
+ if (array_contains_nulls(lbs))
ereport(ERROR,
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
errmsg("dimension values cannot be null")));