From 659f68163813906d323219913909fb9b1adaa39f Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
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 c0e364a30b8..b6f1a40b4a0 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -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.
diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c
index 3818b181904..ec7009816b8 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);
-- 
GitLab