Commit 659f6816 authored by Tom Lane's avatar Tom Lane

Change array comparison rules to consider dimensionality information,

not only the array contents, before claiming two arrays are equal.
Per recent discussion.
parent daea4d8e
<!-- <!--
$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 PostgreSQL documentation
--> -->
...@@ -7403,6 +7403,19 @@ SELECT NULLIF(value, '(none)') ... ...@@ -7403,6 +7403,19 @@ SELECT NULLIF(value, '(none)') ...
</tgroup> </tgroup>
</table> </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> <para>
See <xref linkend="arrays"> for more details about array operator See <xref linkend="arrays"> for more details about array operator
behavior. behavior.
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -2965,10 +2965,9 @@ array_eq(PG_FUNCTION_ARGS)
int ndims2 = ARR_NDIM(array2); int ndims2 = ARR_NDIM(array2);
int *dims1 = ARR_DIMS(array1); int *dims1 = ARR_DIMS(array1);
int *dims2 = ARR_DIMS(array2); int *dims2 = ARR_DIMS(array2);
int nitems1 = ArrayGetNItems(ndims1, dims1);
int nitems2 = ArrayGetNItems(ndims2, dims2);
Oid element_type = ARR_ELEMTYPE(array1); Oid element_type = ARR_ELEMTYPE(array1);
bool result = true; bool result = true;
int nitems;
TypeCacheEntry *typentry; TypeCacheEntry *typentry;
int typlen; int typlen;
bool typbyval; bool typbyval;
...@@ -2986,8 +2985,9 @@ array_eq(PG_FUNCTION_ARGS) ...@@ -2986,8 +2985,9 @@ array_eq(PG_FUNCTION_ARGS)
(errcode(ERRCODE_DATATYPE_MISMATCH), (errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("cannot compare arrays of different element types"))); errmsg("cannot compare arrays of different element types")));
/* fast path if the arrays do not have the same number of elements */ /* fast path if the arrays do not have the same dimensionality */
if (nitems1 != nitems2) if (ndims1 != ndims2 ||
memcmp(dims1, dims2, 2 * ndims1 * sizeof(int)) != 0)
result = false; result = false;
else else
{ {
...@@ -3021,13 +3021,14 @@ array_eq(PG_FUNCTION_ARGS) ...@@ -3021,13 +3021,14 @@ array_eq(PG_FUNCTION_ARGS)
NULL, NULL); NULL, NULL);
/* Loop over source data */ /* Loop over source data */
nitems = ArrayGetNItems(ndims1, dims1);
ptr1 = ARR_DATA_PTR(array1); ptr1 = ARR_DATA_PTR(array1);
ptr2 = ARR_DATA_PTR(array2); ptr2 = ARR_DATA_PTR(array2);
bitmap1 = ARR_NULLBITMAP(array1); bitmap1 = ARR_NULLBITMAP(array1);
bitmap2 = ARR_NULLBITMAP(array2); bitmap2 = ARR_NULLBITMAP(array2);
bitmask = 1; /* use same bitmask for both arrays */ bitmask = 1; /* use same bitmask for both arrays */
for (i = 0; i < nitems1; i++) for (i = 0; i < nitems; i++)
{ {
Datum elt1; Datum elt1;
Datum elt2; Datum elt2;
...@@ -3221,13 +3222,13 @@ array_cmp(FunctionCallInfo fcinfo) ...@@ -3221,13 +3222,13 @@ array_cmp(FunctionCallInfo fcinfo)
NULL, NULL); NULL, NULL);
/* Loop over source data */ /* Loop over source data */
min_nitems = Min(nitems1, nitems2);
ptr1 = ARR_DATA_PTR(array1); ptr1 = ARR_DATA_PTR(array1);
ptr2 = ARR_DATA_PTR(array2); ptr2 = ARR_DATA_PTR(array2);
bitmap1 = ARR_NULLBITMAP(array1); bitmap1 = ARR_NULLBITMAP(array1);
bitmap2 = ARR_NULLBITMAP(array2); bitmap2 = ARR_NULLBITMAP(array2);
bitmask = 1; /* use same bitmask for both arrays */ bitmask = 1; /* use same bitmask for both arrays */
min_nitems = Min(nitems1, nitems2);
for (i = 0; i < min_nitems; i++) for (i = 0; i < min_nitems; i++)
{ {
Datum elt1; Datum elt1;
...@@ -3317,8 +3318,31 @@ array_cmp(FunctionCallInfo fcinfo) ...@@ -3317,8 +3318,31 @@ array_cmp(FunctionCallInfo fcinfo)
} }
} }
if ((result == 0) && (nitems1 != nitems2)) /*
* 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; 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. */ /* Avoid leaking memory when handed toasted input. */
PG_FREE_IF_COPY(array1, 0); PG_FREE_IF_COPY(array1, 0);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment