diff options
Diffstat (limited to 'src/backend/utils/adt/arrayfuncs.c')
-rw-r--r-- | src/backend/utils/adt/arrayfuncs.c | 482 |
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"))); |