From a9d5f30be328fb83f0667b8a60df00a30d934fb2 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Sun, 14 Dec 2008 19:45:52 +0000
Subject: [PATCH] Restore enforce_generic_type_consistency's pre-8.3 behavior
 of allowing an actual argument type of ANYARRAY to match an argument declared
 ANYARRAY, so long as ANYELEMENT etc aren't used.  I had overlooked the fact
 that this is a possible case while fixing bug #3852; but it is possible
 because pg_statistic contains columns declared ANYARRAY.  Per gripe from
 Corey Horton.

---
 src/backend/parser/parse_coerce.c          | 36 +++++++++++++++++-----
 src/test/regress/expected/polymorphism.out | 11 +++++++
 src/test/regress/sql/polymorphism.sql      |  7 +++++
 3 files changed, 46 insertions(+), 8 deletions(-)

diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index 112a07beb58..1bac7ca2fce 100644
--- a/src/backend/parser/parse_coerce.c
+++ b/src/backend/parser/parse_coerce.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.171 2008/10/31 08:39:21 heikki Exp $
+ *	  $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.172 2008/12/14 19:45:52 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1424,6 +1424,15 @@ check_generic_type_consistency(Oid *actual_arg_types,
  * arg types, and we can return ANYARRAY or ANYELEMENT as the result.  (This
  * case is currently used only to check compatibility of an aggregate's
  * declaration with the underlying transfn.)
+ *
+ * A special case is that we could see ANYARRAY as an actual_arg_type even
+ * when allow_poly is false (this is possible only because pg_statistic has
+ * columns shown as anyarray in the catalogs).  We allow this to match a
+ * declared ANYARRAY argument, but only if there is no ANYELEMENT argument
+ * or result (since we can't determine a specific element type to match to
+ * ANYELEMENT).  Note this means that functions taking ANYARRAY had better
+ * behave sanely if applied to the pg_statistic columns; they can't just
+ * assume that successive inputs are of the same actual element type.
  */
 Oid
 enforce_generic_type_consistency(Oid *actual_arg_types,
@@ -1438,6 +1447,9 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
 	Oid			elem_typeid = InvalidOid;
 	Oid			array_typeid = InvalidOid;
 	Oid			array_typelem;
+	bool		have_anyelement = (rettype == ANYELEMENTOID ||
+								   rettype == ANYNONARRAYOID ||
+								   rettype == ANYENUMOID);
 	bool		have_anynonarray = (rettype == ANYNONARRAYOID);
 	bool		have_anyenum = (rettype == ANYENUMOID);
 
@@ -1454,7 +1466,7 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
 			decl_type == ANYNONARRAYOID ||
 			decl_type == ANYENUMOID)
 		{
-			have_generics = true;
+			have_generics = have_anyelement = true;
 			if (decl_type == ANYNONARRAYOID)
 				have_anynonarray = true;
 			else if (decl_type == ANYENUMOID)
@@ -1506,12 +1518,20 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
 	/* Get the element type based on the array type, if we have one */
 	if (OidIsValid(array_typeid))
 	{
-		array_typelem = get_element_type(array_typeid);
-		if (!OidIsValid(array_typelem))
-			ereport(ERROR,
-					(errcode(ERRCODE_DATATYPE_MISMATCH),
-					 errmsg("argument declared \"anyarray\" is not an array but type %s",
-							format_type_be(array_typeid))));
+		if (array_typeid == ANYARRAYOID && !have_anyelement)
+		{
+			/* Special case for ANYARRAY input: okay iff no ANYELEMENT */
+			array_typelem = InvalidOid;
+		}
+		else
+		{
+			array_typelem = get_element_type(array_typeid);
+			if (!OidIsValid(array_typelem))
+				ereport(ERROR,
+						(errcode(ERRCODE_DATATYPE_MISMATCH),
+						 errmsg("argument declared \"anyarray\" is not an array but type %s",
+								format_type_be(array_typeid))));
+		}
 
 		if (!OidIsValid(elem_typeid))
 		{
diff --git a/src/test/regress/expected/polymorphism.out b/src/test/regress/expected/polymorphism.out
index 340b7c0f973..69e0ea47463 100644
--- a/src/test/regress/expected/polymorphism.out
+++ b/src/test/regress/expected/polymorphism.out
@@ -613,6 +613,17 @@ create aggregate build_group(int8, integer) (
   SFUNC = add_group,
   STYPE = int8[]
 );
+-- check that we can apply functions taking ANYARRAY to pg_stats
+select distinct array_ndims(histogram_bounds) from pg_stats
+where histogram_bounds is not null;
+ array_ndims 
+-------------
+           1
+(1 row)
+
+-- such functions must protect themselves if varying element type isn't OK
+select max(histogram_bounds) from pg_stats;
+ERROR:  cannot compare arrays of different element types
 -- test variadic polymorphic functions
 create function myleast(variadic anyarray) returns anyelement as $$
   select min($1[i]) from generate_subscripts($1,1) g(i)
diff --git a/src/test/regress/sql/polymorphism.sql b/src/test/regress/sql/polymorphism.sql
index 56f90c597a8..6c7b1813f94 100644
--- a/src/test/regress/sql/polymorphism.sql
+++ b/src/test/regress/sql/polymorphism.sql
@@ -427,6 +427,13 @@ create aggregate build_group(int8, integer) (
   STYPE = int8[]
 );
 
+-- check that we can apply functions taking ANYARRAY to pg_stats
+select distinct array_ndims(histogram_bounds) from pg_stats
+where histogram_bounds is not null;
+
+-- such functions must protect themselves if varying element type isn't OK
+select max(histogram_bounds) from pg_stats;
+
 -- test variadic polymorphic functions
 
 create function myleast(variadic anyarray) returns anyelement as $$