From 659f68163813906d323219913909fb9b1adaa39f Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sat, 19 Nov 2005 19:44:55 +0000 Subject: [PATCH] Change array comparison rules to consider dimensionality information, not only the array contents, before claiming two arrays are equal. Per recent discussion. --- doc/src/sgml/func.sgml | 15 ++++++++++- src/backend/utils/adt/arrayfuncs.c | 42 +++++++++++++++++++++++------- 2 files changed, 47 insertions(+), 10 deletions(-) diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index c0e364a30b..b6f1a40b4a 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -1,5 +1,5 @@ @@ -7403,6 +7403,19 @@ SELECT NULLIF(value, '(none)') ... + + Array comparisons compare the array contents element-by-element, + using the default btree comparison function for the element data type. + In multidimensional arrays the elements are visited in row-major order + (last subscript varies most rapidly). + If the contents of two arrays are equal but the dimensionality is + different, the first difference in the dimensionality information + determines the sort order. (This is a change from versions of + PostgreSQL prior to 8.2: older versions would claim + that two arrays with the same contents were equal, even if the + number of dimensions or subscript ranges were different.) + + See for more details about array operator behavior. diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c index 3818b18190..ec7009816b 100644 --- a/src/backend/utils/adt/arrayfuncs.c +++ b/src/backend/utils/adt/arrayfuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.124 2005/11/17 22:14:52 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.125 2005/11/19 19:44:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -2965,10 +2965,9 @@ array_eq(PG_FUNCTION_ARGS) int ndims2 = ARR_NDIM(array2); int *dims1 = ARR_DIMS(array1); int *dims2 = ARR_DIMS(array2); - int nitems1 = ArrayGetNItems(ndims1, dims1); - int nitems2 = ArrayGetNItems(ndims2, dims2); Oid element_type = ARR_ELEMTYPE(array1); bool result = true; + int nitems; TypeCacheEntry *typentry; int typlen; bool typbyval; @@ -2986,8 +2985,9 @@ array_eq(PG_FUNCTION_ARGS) (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("cannot compare arrays of different element types"))); - /* fast path if the arrays do not have the same number of elements */ - if (nitems1 != nitems2) + /* fast path if the arrays do not have the same dimensionality */ + if (ndims1 != ndims2 || + memcmp(dims1, dims2, 2 * ndims1 * sizeof(int)) != 0) result = false; else { @@ -3021,13 +3021,14 @@ array_eq(PG_FUNCTION_ARGS) NULL, NULL); /* 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 */ - for (i = 0; i < nitems1; i++) + for (i = 0; i < nitems; i++) { Datum elt1; Datum elt2; @@ -3221,13 +3222,13 @@ array_cmp(FunctionCallInfo fcinfo) NULL, NULL); /* 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 */ - min_nitems = Min(nitems1, nitems2); for (i = 0; i < min_nitems; i++) { Datum elt1; @@ -3317,8 +3318,31 @@ array_cmp(FunctionCallInfo fcinfo) } } - if ((result == 0) && (nitems1 != nitems2)) - result = (nitems1 < nitems2) ? -1 : 1; + /* + * If arrays contain same data (up to end of shorter one), apply additional + * rules to sort by dimensionality. The relative significance of the + * different bits of information is historical; mainly we just care that + * we don't say "equal" for arrays of different dimensionality. + */ + if (result == 0) + { + if (nitems1 != nitems2) + result = (nitems1 < nitems2) ? -1 : 1; + else if (ndims1 != ndims2) + result = (ndims1 < ndims2) ? -1 : 1; + else + { + /* this relies on LB array immediately following DIMS array */ + for (i = 0; i < ndims1 * 2; i++) + { + if (dims1[i] != dims2[i]) + { + result = (dims1[i] < dims2[i]) ? -1 : 1; + break; + } + } + } + } /* Avoid leaking memory when handed toasted input. */ PG_FREE_IF_COPY(array1, 0);