Change array comparison rules to consider dimensionality information,

not only the array contents, before claiming two arrays are equal.
Per recent discussion.
This commit is contained in:
Tom Lane 2005-11-19 19:44:55 +00:00
parent daea4d8eae
commit 659f681638
2 changed files with 47 additions and 10 deletions

View File

@ -1,5 +1,5 @@
<!--
$PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.294 2005/11/19 01:50:08 tgl Exp $
$PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.295 2005/11/19 19:44:54 tgl Exp $
PostgreSQL documentation
-->
@ -7403,6 +7403,19 @@ SELECT NULLIF(value, '(none)') ...
</tgroup>
</table>
<para>
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
<productname>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.)
</para>
<para>
See <xref linkend="arrays"> for more details about array operator
behavior.

View File

@ -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);