diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c
index a2160fa0251b0615c460a08071753bf39c4530e3..ad348bf6a5630d3bfbd6192d3d3faa476fed1bb5 100644
--- a/src/backend/catalog/pg_aggregate.c
+++ b/src/backend/catalog/pg_aggregate.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.58 2003/06/25 21:30:25 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.59 2003/07/01 19:10:52 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -29,6 +29,10 @@
 #include "utils/syscache.h"
 
 
+static Oid	lookup_agg_function(List *fnName, int nargs, Oid *input_types,
+								Oid *rettype);
+
+
 /*
  * AggregateCreate
  */
@@ -48,9 +52,10 @@ AggregateCreate(const char *aggName,
 	Form_pg_proc proc;
 	Oid			transfn;
 	Oid			finalfn = InvalidOid;	/* can be omitted */
+	Oid			rettype;
 	Oid			finaltype;
 	Oid			fnArgs[FUNC_MAX_ARGS];
-	int			nargs;
+	int			nargs_transfn;
 	Oid			procOid;
 	TupleDesc	tupDesc;
 	int			i;
@@ -64,28 +69,49 @@ AggregateCreate(const char *aggName,
 	if (!aggtransfnName)
 		elog(ERROR, "aggregate must have a transition function");
 
+	/*
+	 * If transtype is polymorphic, basetype must be polymorphic also;
+	 * else we will have no way to deduce the actual transtype.
+	 */
+	if ((aggTransType == ANYARRAYOID || aggTransType == ANYELEMENTOID) &&
+		!(aggBaseType == ANYARRAYOID || aggBaseType == ANYELEMENTOID))
+		elog(ERROR, "an aggregate using ANYARRAY or ANYELEMENT as trans type "
+			 "must also have one of them as its base type");
+
 	/* handle transfn */
 	MemSet(fnArgs, 0, FUNC_MAX_ARGS * sizeof(Oid));
 	fnArgs[0] = aggTransType;
 	if (aggBaseType == ANYOID)
-		nargs = 1;
+		nargs_transfn = 1;
 	else
 	{
 		fnArgs[1] = aggBaseType;
-		nargs = 2;
+		nargs_transfn = 2;
 	}
-	transfn = LookupFuncName(aggtransfnName, nargs, fnArgs);
-	if (!OidIsValid(transfn))
-		func_error("AggregateCreate", aggtransfnName, nargs, fnArgs, NULL);
+	transfn = lookup_agg_function(aggtransfnName, nargs_transfn, fnArgs,
+								  &rettype);
+
+	/*
+	 * Return type of transfn (possibly after refinement by
+	 * enforce_generic_type_consistency, if transtype isn't polymorphic)
+	 * must exactly match declared transtype.
+	 *
+	 * In the non-polymorphic-transtype case, it might be okay to allow
+	 * a rettype that's binary-coercible to transtype, but I'm not quite
+	 * convinced that it's either safe or useful.  When transtype is
+	 * polymorphic we *must* demand exact equality.
+	 */
+	if (rettype != aggTransType)
+		elog(ERROR, "return type of transition function %s is not %s",
+		 NameListToString(aggtransfnName), format_type_be(aggTransType));
+
 	tup = SearchSysCache(PROCOID,
 						 ObjectIdGetDatum(transfn),
 						 0, 0, 0);
 	if (!HeapTupleIsValid(tup))
-		func_error("AggregateCreate", aggtransfnName, nargs, fnArgs, NULL);
+		func_error("AggregateCreate", aggtransfnName,
+				   nargs_transfn, fnArgs, NULL);
 	proc = (Form_pg_proc) GETSTRUCT(tup);
-	if (proc->prorettype != aggTransType)
-		elog(ERROR, "return type of transition function %s is not %s",
-		 NameListToString(aggtransfnName), format_type_be(aggTransType));
 
 	/*
 	 * If the transfn is strict and the initval is NULL, make sure input
@@ -105,17 +131,8 @@ AggregateCreate(const char *aggName,
 	{
 		MemSet(fnArgs, 0, FUNC_MAX_ARGS * sizeof(Oid));
 		fnArgs[0] = aggTransType;
-		finalfn = LookupFuncName(aggfinalfnName, 1, fnArgs);
-		if (!OidIsValid(finalfn))
-			func_error("AggregateCreate", aggfinalfnName, 1, fnArgs, NULL);
-		tup = SearchSysCache(PROCOID,
-							 ObjectIdGetDatum(finalfn),
-							 0, 0, 0);
-		if (!HeapTupleIsValid(tup))
-			func_error("AggregateCreate", aggfinalfnName, 1, fnArgs, NULL);
-		proc = (Form_pg_proc) GETSTRUCT(tup);
-		finaltype = proc->prorettype;
-		ReleaseSysCache(tup);
+		finalfn = lookup_agg_function(aggfinalfnName, 1, fnArgs,
+									  &finaltype);
 	}
 	else
 	{
@@ -126,6 +143,19 @@ AggregateCreate(const char *aggName,
 	}
 	Assert(OidIsValid(finaltype));
 
+	/*
+	 * If finaltype (i.e. aggregate return type) is polymorphic,
+	 * basetype must be polymorphic also, else parser will fail to deduce
+	 * result type.  (Note: given the previous test on transtype and basetype,
+	 * this cannot happen, unless someone has snuck a finalfn definition
+	 * into the catalogs that itself violates the rule against polymorphic
+	 * result with no polymorphic input.)
+	 */
+	if ((finaltype == ANYARRAYOID || finaltype == ANYELEMENTOID) &&
+		!(aggBaseType == ANYARRAYOID || aggBaseType == ANYELEMENTOID))
+		elog(ERROR, "an aggregate returning ANYARRAY or ANYELEMENT "
+			 "must also have one of them as its base type");
+
 	/*
 	 * Everything looks okay.  Try to create the pg_proc entry for the
 	 * aggregate.  (This could fail if there's already a conflicting
@@ -207,3 +237,71 @@ AggregateCreate(const char *aggName,
 		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 	}
 }
+
+/*
+ * lookup_agg_function -- common code for finding both transfn and finalfn
+ */
+static Oid
+lookup_agg_function(List *fnName,
+					int nargs,
+					Oid *input_types,
+					Oid *rettype)
+{
+	Oid			fnOid;
+	bool		retset;
+	Oid		   *true_oid_array;
+	FuncDetailCode fdresult;
+
+	/*
+	 * func_get_detail looks up the function in the catalogs, does
+	 * disambiguation for polymorphic functions, handles inheritance, and
+	 * returns the funcid and type and set or singleton status of the
+	 * function's return value.  it also returns the true argument types
+	 * to the function.
+	 */
+	fdresult = func_get_detail(fnName, NIL, nargs, input_types,
+							   &fnOid, rettype, &retset,
+							   &true_oid_array);
+
+	/* only valid case is a normal function not returning a set */
+	if (fdresult != FUNCDETAIL_NORMAL ||
+		!OidIsValid(fnOid) ||
+		retset)
+		func_error("AggregateCreate", fnName, nargs, input_types, NULL);
+
+	/*
+	 * If the given type(s) are all polymorphic, there's nothing we
+	 * can check.  Otherwise, enforce consistency, and possibly refine
+	 * the result type.
+	 */
+	if ((input_types[0] == ANYARRAYOID || input_types[0] == ANYELEMENTOID) &&
+		(nargs == 1 ||
+		 (input_types[1] == ANYARRAYOID || input_types[1] == ANYELEMENTOID)))
+	{
+		/* nothing to check here */
+	}
+	else
+	{
+		*rettype = enforce_generic_type_consistency(input_types,
+													true_oid_array,
+													nargs,
+													*rettype);
+	}
+
+	/*
+	 * func_get_detail will find functions requiring run-time argument type
+	 * coercion, but nodeAgg.c isn't prepared to deal with that
+	 */
+	if (true_oid_array[0] != ANYARRAYOID &&
+		true_oid_array[0] != ANYELEMENTOID &&
+		!IsBinaryCoercible(input_types[0], true_oid_array[0]))
+		func_error("AggregateCreate", fnName, nargs, input_types, NULL);
+
+	if (nargs == 2 &&
+		true_oid_array[1] != ANYARRAYOID &&
+		true_oid_array[1] != ANYELEMENTOID &&
+		!IsBinaryCoercible(input_types[1], true_oid_array[1]))
+		func_error("AggregateCreate", fnName, nargs, input_types, NULL);
+
+	return fnOid;
+}
diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c
index 1ea31a6a5a0fd2322fee7ae88d326f5990376112..860d490bd30c7938aff067fa79307b86cb821266 100644
--- a/src/backend/commands/aggregatecmds.c
+++ b/src/backend/commands/aggregatecmds.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/aggregatecmds.c,v 1.8 2003/06/27 14:45:27 petere Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/aggregatecmds.c,v 1.9 2003/07/01 19:10:52 tgl Exp $
  *
  * DESCRIPTION
  *	  The "DefineFoo" routines take the parse tree and pick out the
@@ -120,7 +120,9 @@ DefineAggregate(List *names, List *parameters)
 		baseTypeId = typenameTypeId(baseType);
 
 	transTypeId = typenameTypeId(transType);
-	if (get_typtype(transTypeId) == 'p')
+	if (get_typtype(transTypeId) == 'p' &&
+		transTypeId != ANYARRAYOID &&
+		transTypeId != ANYELEMENTOID)
 		elog(ERROR, "Aggregate transition datatype cannot be %s",
 			 format_type_be(transTypeId));
 
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index 04d656f05a93b1f034ac73a252a05bec146c5047..b54d528eeaf37d54a564e335f896567e7edb8db4 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -45,7 +45,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.109 2003/06/25 21:30:28 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.110 2003/07/01 19:10:52 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -59,6 +59,7 @@
 #include "executor/nodeAgg.h"
 #include "miscadmin.h"
 #include "optimizer/clauses.h"
+#include "parser/parse_agg.h"
 #include "parser/parse_coerce.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_oper.h"
@@ -1182,11 +1183,15 @@ ExecInitAgg(Agg *node, EState *estate)
 		AggrefExprState *aggrefstate = (AggrefExprState *) lfirst(alist);
 		Aggref	   *aggref = (Aggref *) aggrefstate->xprstate.expr;
 		AggStatePerAgg peraggstate;
+		Oid			inputType;
 		HeapTuple	aggTuple;
 		Form_pg_aggregate aggform;
+		Oid			aggtranstype;
 		AclResult	aclresult;
 		Oid			transfn_oid,
 					finalfn_oid;
+		Expr	   *transfnexpr,
+				   *finalfnexpr;
 		Datum		textInitVal;
 		int			i;
 
@@ -1217,6 +1222,13 @@ ExecInitAgg(Agg *node, EState *estate)
 		peraggstate->aggrefstate = aggrefstate;
 		peraggstate->aggref = aggref;
 
+		/*
+		 * Get actual datatype of the input.  We need this because it may
+		 * be different from the agg's declared input type, when the agg
+		 * accepts ANY (eg, COUNT(*)) or ANYARRAY or ANYELEMENT.
+		 */
+		inputType = exprType((Node *) aggref->target);
+
 		aggTuple = SearchSysCache(AGGFNOID,
 								  ObjectIdGetDatum(aggref->aggfnoid),
 								  0, 0, 0);
@@ -1231,10 +1243,47 @@ ExecInitAgg(Agg *node, EState *estate)
 		if (aclresult != ACLCHECK_OK)
 			aclcheck_error(aclresult, get_func_name(aggref->aggfnoid));
 
+		peraggstate->transfn_oid = transfn_oid = aggform->aggtransfn;
+		peraggstate->finalfn_oid = finalfn_oid = aggform->aggfinalfn;
+
+		/* resolve actual type of transition state, if polymorphic */
+		aggtranstype = aggform->aggtranstype;
+		if (aggtranstype == ANYARRAYOID || aggtranstype == ANYELEMENTOID)
+		{
+			/* have to fetch the agg's declared input type... */
+			Oid			agg_arg_types[FUNC_MAX_ARGS];
+			int			agg_nargs;
+
+			(void) get_func_signature(aggref->aggfnoid,
+									  agg_arg_types, &agg_nargs);
+			Assert(agg_nargs == 1);
+			aggtranstype = resolve_generic_type(aggtranstype,
+												inputType,
+												agg_arg_types[0]);
+		}
+
+		/* build expression trees using actual argument & result types */
+		build_aggregate_fnexprs(inputType,
+								aggtranstype,
+								aggref->aggtype,
+								transfn_oid,
+								finalfn_oid,
+								&transfnexpr,
+								&finalfnexpr);
+
+		fmgr_info(transfn_oid, &peraggstate->transfn);
+		peraggstate->transfn.fn_expr = (Node *) transfnexpr;
+
+		if (OidIsValid(finalfn_oid))
+		{
+			fmgr_info(finalfn_oid, &peraggstate->finalfn);
+			peraggstate->finalfn.fn_expr = (Node *) finalfnexpr;
+		}
+
 		get_typlenbyval(aggref->aggtype,
 						&peraggstate->resulttypeLen,
 						&peraggstate->resulttypeByVal);
-		get_typlenbyval(aggform->aggtranstype,
+		get_typlenbyval(aggtranstype,
 						&peraggstate->transtypeLen,
 						&peraggstate->transtypeByVal);
 
@@ -1250,14 +1299,7 @@ ExecInitAgg(Agg *node, EState *estate)
 			peraggstate->initValue = (Datum) 0;
 		else
 			peraggstate->initValue = GetAggInitVal(textInitVal,
-												   aggform->aggtranstype);
-
-		peraggstate->transfn_oid = transfn_oid = aggform->aggtransfn;
-		peraggstate->finalfn_oid = finalfn_oid = aggform->aggfinalfn;
-
-		fmgr_info(transfn_oid, &peraggstate->transfn);
-		if (OidIsValid(finalfn_oid))
-			fmgr_info(finalfn_oid, &peraggstate->finalfn);
+												   aggtranstype);
 
 		/*
 		 * If the transfn is strict and the initval is NULL, make sure
@@ -1268,26 +1310,13 @@ ExecInitAgg(Agg *node, EState *estate)
 		 */
 		if (peraggstate->transfn.fn_strict && peraggstate->initValueIsNull)
 		{
-			/*
-			 * Note: use the type from the input expression here, not from
-			 * pg_proc.proargtypes, because the latter might be 0.
-			 * (Consider COUNT(*).)
-			 */
-			Oid			inputType = exprType((Node *) aggref->target);
-
-			if (!IsBinaryCoercible(inputType, aggform->aggtranstype))
+			if (!IsBinaryCoercible(inputType, aggtranstype))
 				elog(ERROR, "Aggregate %u needs to have compatible input type and transition type",
 					 aggref->aggfnoid);
 		}
 
 		if (aggref->aggdistinct)
 		{
-			/*
-			 * Note: use the type from the input expression here, not from
-			 * pg_proc.proargtypes, because the latter might be a pseudotype.
-			 * (Consider COUNT(*).)
-			 */
-			Oid			inputType = exprType((Node *) aggref->target);
 			Oid			eq_function;
 
 			/* We don't implement DISTINCT aggs in the HASHED case */
diff --git a/src/backend/nodes/makefuncs.c b/src/backend/nodes/makefuncs.c
index 4683d36bfbcdf4a16b078c01601dd0f5aa59ea10..38bd4ac6f6ed1e8c38fae8589ce900707c41d6d8 100644
--- a/src/backend/nodes/makefuncs.c
+++ b/src/backend/nodes/makefuncs.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/makefuncs.c,v 1.39 2003/05/06 00:20:32 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/makefuncs.c,v 1.40 2003/07/01 19:10:52 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -251,3 +251,24 @@ makeTypeName(char *typnam)
 	n->typmod = -1;
 	return n;
 }
+
+/*
+ * makeFuncExpr -
+ *	build an expression tree representing a function call.
+ *
+ * The argument expressions must have been transformed already.
+ */
+FuncExpr *
+makeFuncExpr(Oid funcid, Oid rettype, List *args, CoercionForm fformat)
+{
+	FuncExpr   *funcexpr;
+
+	funcexpr = makeNode(FuncExpr);
+	funcexpr->funcid = funcid;
+	funcexpr->funcresulttype = rettype;
+	funcexpr->funcretset = false;		/* only allowed case here */
+	funcexpr->funcformat = fformat;
+	funcexpr->args = args;
+
+	return funcexpr;
+}
diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c
index 49d952bf8afc92d1eb66ff66f0a94e986a349200..306a64735b9e6f28d0b5c760a188d4e15dc0e257 100644
--- a/src/backend/parser/parse_agg.c
+++ b/src/backend/parser/parse_agg.c
@@ -8,18 +8,21 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.53 2003/06/06 15:04:02 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.54 2003/07/01 19:10:52 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
+#include "nodes/makefuncs.h"
+#include "nodes/params.h"
 #include "optimizer/clauses.h"
 #include "optimizer/tlist.h"
 #include "optimizer/var.h"
 #include "parser/parse_agg.h"
 #include "parser/parsetree.h"
 #include "rewrite/rewriteManip.h"
+#include "utils/lsyscache.h"
 
 
 typedef struct
@@ -312,3 +315,91 @@ check_ungrouped_columns_walker(Node *node,
 	return expression_tree_walker(node, check_ungrouped_columns_walker,
 								  (void *) context);
 }
+
+/*
+ * Create expression trees for the transition and final functions
+ * of an aggregate.  These are needed so that polymorphic functions
+ * can be used within an aggregate --- without the expression trees,
+ * such functions would not know the datatypes they are supposed to use.
+ * (The trees will never actually be executed, however, so we can skimp
+ * a bit on correctness.)
+ *
+ * agg_input_type, agg_state_type, agg_result_type identify the input,
+ * transition, and result types of the aggregate.  These should all be
+ * resolved to actual types (ie, none should ever be ANYARRAY or ANYELEMENT).
+ *
+ * transfn_oid and finalfn_oid identify the funcs to be called; the latter
+ * may be InvalidOid.
+ *
+ * Pointers to the constructed trees are returned into *transfnexpr and
+ * *finalfnexpr.  The latter is set to NULL if there's no finalfn.
+ */
+void
+build_aggregate_fnexprs(Oid agg_input_type,
+						Oid agg_state_type,
+						Oid agg_result_type,
+						Oid transfn_oid,
+						Oid finalfn_oid,
+						Expr **transfnexpr,
+						Expr **finalfnexpr)
+{
+	Oid			transfn_arg_types[FUNC_MAX_ARGS];
+	int			transfn_nargs;
+	Param	   *arg0;
+	Param	   *arg1;
+	List	   *args;
+
+	/* get the transition function signature (only need nargs) */
+	(void) get_func_signature(transfn_oid, transfn_arg_types, &transfn_nargs);
+
+	/*
+	 * Build arg list to use in the transfn FuncExpr node. We really
+	 * only care that transfn can discover the actual argument types
+	 * at runtime using get_fn_expr_argtype(), so it's okay to use
+	 * Param nodes that don't correspond to any real Param.
+	 */
+	arg0 = makeNode(Param);
+	arg0->paramkind = PARAM_EXEC;
+	arg0->paramid = -1;
+	arg0->paramtype = agg_state_type;
+
+	if (transfn_nargs == 2)
+	{
+		arg1 = makeNode(Param);
+		arg1->paramkind = PARAM_EXEC;
+		arg1->paramid = -1;
+		arg1->paramtype = agg_input_type;
+
+		args = makeList2(arg0, arg1);
+	}
+	else
+	{
+		args = makeList1(arg0);
+	}
+
+   *transfnexpr = (Expr *) makeFuncExpr(transfn_oid,
+										agg_state_type,
+										args,
+										COERCE_DONTCARE);
+
+   /* see if we have a final function */
+   if (!OidIsValid(finalfn_oid))
+   {
+	   *finalfnexpr = NULL;
+	   return;
+   }
+
+   /*
+	* Build expr tree for final function
+	*/
+	arg0 = makeNode(Param);
+	arg0->paramkind = PARAM_EXEC;
+	arg0->paramid = -1;
+	arg0->paramtype = agg_state_type;
+	args = makeList1(arg0);
+
+   *finalfnexpr = (Expr *) makeFuncExpr(finalfn_oid,
+										agg_result_type,
+										args,
+										COERCE_DONTCARE);
+}
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index eba6f5a13334d907606dae7b6ac74e8b4536eb6e..977780fecc857adc8ca6a9a40bf1a2637b10fe11 100644
--- a/src/backend/parser/parse_coerce.c
+++ b/src/backend/parser/parse_coerce.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.101 2003/06/27 00:33:25 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.102 2003/07/01 19:10:53 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -32,8 +32,6 @@
 static Node *coerce_type_typmod(Node *node,
 								Oid targetTypeId, int32 targetTypMod,
 								CoercionForm cformat, bool isExplicit);
-static Node *build_func_call(Oid funcid, Oid rettype, List *args,
-							 CoercionForm fformat);
 
 
 /*
@@ -275,8 +273,9 @@ coerce_type(ParseState *pstate, Node *node,
 			 */
 			Oid			baseTypeId = getBaseType(targetTypeId);
 
-			result = build_func_call(funcId, baseTypeId, makeList1(node),
-									 cformat);
+			result = (Node *) makeFuncExpr(funcId, baseTypeId,
+										   makeList1(node),
+										   cformat);
 
 			/*
 			 * If domain, coerce to the domain type and relabel with
@@ -534,7 +533,7 @@ coerce_type_typmod(Node *node, Oid targetTypeId, int32 targetTypMod,
 			args = lappend(args, cons);
 		}
 
-		node = build_func_call(funcId, targetTypeId, args, cformat);
+		node = (Node *) makeFuncExpr(funcId, targetTypeId, args, cformat);
 	}
 
 	return node;
@@ -935,6 +934,76 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
 	return rettype;
 }
 
+/*
+ * resolve_generic_type()
+ *		Deduce an individual actual datatype on the assumption that
+ *		the rules for ANYARRAY/ANYELEMENT are being followed.
+ *
+ * declared_type is the declared datatype we want to resolve.
+ * context_actual_type is the actual input datatype to some argument
+ * that has declared datatype context_declared_type.
+ *
+ * If declared_type isn't polymorphic, we just return it.  Otherwise,
+ * context_declared_type must be polymorphic, and we deduce the correct
+ * return type based on the relationship of the two polymorphic types.
+ */
+Oid
+resolve_generic_type(Oid declared_type,
+					 Oid context_actual_type,
+					 Oid context_declared_type)
+{
+	if (declared_type == ANYARRAYOID)
+	{
+		if (context_declared_type == ANYARRAYOID)
+		{
+			/* Use actual type, but it must be an array */
+			Oid		array_typelem = get_element_type(context_actual_type);
+
+			if (!OidIsValid(array_typelem))
+				elog(ERROR, "Argument declared ANYARRAY is not an array: %s",
+					 format_type_be(context_actual_type));
+			return context_actual_type;
+		}
+		else if (context_declared_type == ANYELEMENTOID)
+		{
+			/* Use the array type corresponding to actual type */
+			Oid		array_typeid = get_array_type(context_actual_type);
+
+			if (!OidIsValid(array_typeid))
+				elog(ERROR, "Cannot find array type for datatype %s",
+					 format_type_be(context_actual_type));
+			return array_typeid;
+		}
+	}
+	else if (declared_type == ANYELEMENTOID)
+	{
+		if (context_declared_type == ANYARRAYOID)
+		{
+			/* Use the element type corresponding to actual type */
+			Oid		array_typelem = get_element_type(context_actual_type);
+
+			if (!OidIsValid(array_typelem))
+				elog(ERROR, "Argument declared ANYARRAY is not an array: %s",
+					 format_type_be(context_actual_type));
+			return array_typelem;
+		}
+		else if (context_declared_type == ANYELEMENTOID)
+		{
+			/* Use the actual type; it doesn't matter if array or not */
+			return context_actual_type;
+		}
+	}
+	else
+	{
+		/* declared_type isn't polymorphic, so return it as-is */
+		return declared_type;
+	}
+	/* If we get here, declared_type is polymorphic and context isn't */
+	/* NB: this is a calling-code logic error, not a user error */
+	elog(ERROR, "Cannot determine ANYARRAY/ANYELEMENT type because context isn't polymorphic");
+	return InvalidOid;			/* keep compiler quiet */
+}
+
 
 /* TypeCategory()
  *		Assign a category to the specified type OID.
@@ -1417,23 +1486,3 @@ find_typmod_coercion_function(Oid typeId, int *nargs)
 
 	return funcid;
 }
-
-/*
- * Build an expression tree representing a function call.
- *
- * The argument expressions must have been transformed already.
- */
-static Node *
-build_func_call(Oid funcid, Oid rettype, List *args, CoercionForm fformat)
-{
-	FuncExpr   *funcexpr;
-
-	funcexpr = makeNode(FuncExpr);
-	funcexpr->funcid = funcid;
-	funcexpr->funcresulttype = rettype;
-	funcexpr->funcretset = false;		/* only possible case here */
-	funcexpr->funcformat = fformat;
-	funcexpr->args = args;
-
-	return (Node *) funcexpr;
-}
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c
index 6da53870c47a8a3c676c1295b620d99b40768da2..879d2ba57a719ad094600fd9028b93ea7b0f97e9 100644
--- a/src/backend/utils/cache/lsyscache.c
+++ b/src/backend/utils/cache/lsyscache.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.100 2003/06/27 00:33:25 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.101 2003/07/01 19:10:53 tgl Exp $
  *
  * NOTES
  *	  Eventually, the index information should go through here, too.
@@ -718,6 +718,36 @@ get_func_rettype(Oid funcid)
 	return result;
 }
 
+/*
+ * get_func_signature
+ *		Given procedure id, return the function's argument and result types.
+ *		(The return value is the result type.)
+ *
+ * argtypes must point to a vector of size FUNC_MAX_ARGS.
+ */
+Oid
+get_func_signature(Oid funcid, Oid *argtypes, int *nargs)
+{
+	HeapTuple		tp;
+	Form_pg_proc	procstruct;
+	Oid			result;
+
+	tp = SearchSysCache(PROCOID,
+						ObjectIdGetDatum(funcid),
+						0, 0, 0);
+	if (!HeapTupleIsValid(tp))
+		elog(ERROR, "Function OID %u does not exist", funcid);
+
+	procstruct = (Form_pg_proc) GETSTRUCT(tp);
+
+	result = procstruct->prorettype;
+	memcpy(argtypes, procstruct->proargtypes, FUNC_MAX_ARGS * sizeof(Oid));
+	*nargs = (int) procstruct->pronargs;
+
+	ReleaseSysCache(tp);
+	return result;
+}
+
 /*
  * get_func_retset
  *		Given procedure id, return the function's proretset flag.
diff --git a/src/include/nodes/makefuncs.h b/src/include/nodes/makefuncs.h
index a66e9fc09be9948c099ccc1223b3130ba29ac8d5..f1b45e897bb93c9bcff56302d15ac89944939777 100644
--- a/src/include/nodes/makefuncs.h
+++ b/src/include/nodes/makefuncs.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: makefuncs.h,v 1.44 2003/02/10 04:44:46 tgl Exp $
+ * $Id: makefuncs.h,v 1.45 2003/07/01 19:10:53 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -56,4 +56,7 @@ extern RangeVar *makeRangeVar(char *schemaname, char *relname);
 
 extern TypeName *makeTypeName(char *typnam);
 
+extern FuncExpr *makeFuncExpr(Oid funcid, Oid rettype,
+							  List *args, CoercionForm fformat);
+
 #endif   /* MAKEFUNC_H */
diff --git a/src/include/parser/parse_agg.h b/src/include/parser/parse_agg.h
index bc1e601cc22cdfb63a1802326fe05a9ba7e8ae67..79f226fb89f44062ac9d2f925d1a357d066fb999 100644
--- a/src/include/parser/parse_agg.h
+++ b/src/include/parser/parse_agg.h
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parse_agg.h,v 1.26 2003/06/06 15:04:03 tgl Exp $
+ * $Id: parse_agg.h,v 1.27 2003/07/01 19:10:53 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,4 +19,12 @@ extern void transformAggregateCall(ParseState *pstate, Aggref *agg);
 
 extern void parseCheckAggregates(ParseState *pstate, Query *qry);
 
+extern void build_aggregate_fnexprs(Oid agg_input_type,
+									Oid agg_state_type,
+									Oid agg_result_type,
+									Oid transfn_oid,
+									Oid finalfn_oid,
+									Expr **transfnexpr,
+									Expr **finalfnexpr);
+
 #endif   /* PARSE_AGG_H */
diff --git a/src/include/parser/parse_coerce.h b/src/include/parser/parse_coerce.h
index de2ea95db8547f1d35724aa7ce9f69cffee6d829..5facbc7d7d4fa43a8866718cd494f4eb8b0aa9ae 100644
--- a/src/include/parser/parse_coerce.h
+++ b/src/include/parser/parse_coerce.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parse_coerce.h,v 1.51 2003/04/29 22:13:11 tgl Exp $
+ * $Id: parse_coerce.h,v 1.52 2003/07/01 19:10:53 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -67,6 +67,9 @@ extern Oid enforce_generic_type_consistency(Oid *actual_arg_types,
 											Oid *declared_arg_types,
 											int nargs,
 											Oid rettype);
+extern Oid resolve_generic_type(Oid declared_type,
+								Oid context_actual_type,
+								Oid context_declared_type);
 
 extern bool find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId,
 								  CoercionContext ccontext,
diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h
index 4d8749befc6464ca2fd462c16d97a50e39c0da05..1f8bcb06d1e2a29d6eea4fb27f519a24e8e739ed 100644
--- a/src/include/utils/lsyscache.h
+++ b/src/include/utils/lsyscache.h
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: lsyscache.h,v 1.75 2003/06/27 00:33:26 tgl Exp $
+ * $Id: lsyscache.h,v 1.76 2003/07/01 19:10:53 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -50,6 +50,7 @@ extern RegProcedure get_oprrest(Oid opno);
 extern RegProcedure get_oprjoin(Oid opno);
 extern char *get_func_name(Oid funcid);
 extern Oid	get_func_rettype(Oid funcid);
+extern Oid	get_func_signature(Oid funcid, Oid *argtypes, int *nargs);
 extern bool get_func_retset(Oid funcid);
 extern bool func_strict(Oid funcid);
 extern char func_volatile(Oid funcid);
diff --git a/src/test/regress/expected/polymorphism.out b/src/test/regress/expected/polymorphism.out
new file mode 100644
index 0000000000000000000000000000000000000000..63dfdb694f1ff13fc61f0b3154782b65f8f0e134
--- /dev/null
+++ b/src/test/regress/expected/polymorphism.out
@@ -0,0 +1,514 @@
+-- Currently this tests polymorphic aggregates and indirectly does some
+-- testing of polymorphic SQL functions.  It ought to be extended.
+-- Legend:
+-----------
+-- A = type is ANY
+-- P = type is polymorphic
+-- N = type is non-polymorphic
+-- B = aggregate base type
+-- S = aggregate state type
+-- R = aggregate return type
+-- 1 = arg1 of a function
+-- 2 = arg2 of a function
+-- ag = aggregate
+-- tf = trans (state) function
+-- ff = final function
+-- rt = return type of a function
+-- -> = implies
+-- => = allowed
+-- !> = not allowed
+-- E  = exists
+-- NE = not-exists
+-- 
+-- Possible states:
+-- ----------------
+-- B = (A || P || N)
+--   when (B = A) -> (tf2 = NE)
+-- S = (P || N)
+-- ff = (E || NE)
+-- tf1 = (P || N)
+-- tf2 = (NE || P || N)
+-- R = (P || N)
+-- create functions for use as tf and ff with the needed combinations of
+-- argument polymorphism, but within the constraints of valid aggregate
+-- functions, i.e. tf arg1 and tf return type must match
+-- polymorphic single arg transfn
+CREATE FUNCTION stfp(anyarray) returns anyarray as
+'select $1' language 'sql';
+-- non-polymorphic single arg transfn
+CREATE FUNCTION stfnp(int[]) returns int[] as
+'select $1' language 'sql';
+-- dual polymorphic transfn
+CREATE FUNCTION tfp(anyarray,anyelement) returns anyarray as
+'select $1 || $2' language 'sql';
+-- dual non-polymorphic transfn
+CREATE FUNCTION tfnp(int[],int) returns int[] as
+'select $1 || $2' language 'sql';
+-- arg1 only polymorphic transfn
+CREATE FUNCTION tf1p(anyarray,int) returns anyarray as
+'select $1' language 'sql';
+-- arg2 only polymorphic transfn
+CREATE FUNCTION tf2p(int[],anyelement) returns int[] as
+'select $1' language 'sql';
+-- finalfn polymorphic
+CREATE FUNCTION ffp(anyarray) returns anyarray as
+'select $1' language 'sql';
+-- finalfn non-polymorphic
+CREATE FUNCTION ffnp(int[]) returns int[] as
+'select $1' language 'sql';
+-- Try to cover all the possible states:
+-- 
+-- Note: in Cases 1 & 2, we are trying to return P. Therefore, if the transfn
+-- is stfnp, tfnp, or tf2p, we must use ffp as finalfn, because stfnp, tfnp,
+-- and tf2p do not return P. Conversely, in Cases 3 & 4, we are trying to
+-- return N. Therefore, if the transfn is stfp, tfp, or tf1p, we must use ffnp
+-- as finalfn, because stfp, tfp, and tf1p do not return N.
+--
+--     Case1 (R = P) && (B = A)
+--     ------------------------
+--     S    tf1
+--     -------
+--     N    N
+-- should CREATE
+CREATE AGGREGATE myaggp01a(BASETYPE = "ANY", SFUNC = stfnp, STYPE = int4[],
+  FINALFUNC = ffp, INITCOND = '{}');
+--     P    N
+-- should ERROR: stfnp(anyarray) not matched by stfnp(int[])
+CREATE AGGREGATE myaggp02a(BASETYPE = "ANY", SFUNC = stfnp, STYPE = anyarray,
+  FINALFUNC = ffp, INITCOND = '{}');
+ERROR:  an aggregate using ANYARRAY or ANYELEMENT as trans type must also have one of them as its base type
+--     N    P
+-- should CREATE
+CREATE AGGREGATE myaggp03a(BASETYPE = "ANY", SFUNC = stfp, STYPE = int4[],
+  FINALFUNC = ffp, INITCOND = '{}');
+CREATE AGGREGATE myaggp03b(BASETYPE = "ANY", SFUNC = stfp, STYPE = int4[],
+  INITCOND = '{}');
+--     P    P
+-- should ERROR: we have no way to resolve S
+CREATE AGGREGATE myaggp04a(BASETYPE = "ANY", SFUNC = stfp, STYPE = anyarray,
+  FINALFUNC = ffp, INITCOND = '{}');
+ERROR:  an aggregate using ANYARRAY or ANYELEMENT as trans type must also have one of them as its base type
+CREATE AGGREGATE myaggp04b(BASETYPE = "ANY", SFUNC = stfp, STYPE = anyarray,
+  INITCOND = '{}');
+ERROR:  an aggregate using ANYARRAY or ANYELEMENT as trans type must also have one of them as its base type
+--    Case2 (R = P) && ((B = P) || (B = N))
+--    -------------------------------------
+--    S    tf1      B    tf2
+--    -----------------------
+--    N    N        N    N
+-- should CREATE
+CREATE AGGREGATE myaggp05a(BASETYPE = int, SFUNC = tfnp, STYPE = int[],
+  FINALFUNC = ffp, INITCOND = '{}');
+--    N    N        N    P
+-- should CREATE
+CREATE AGGREGATE myaggp06a(BASETYPE = int, SFUNC = tf2p, STYPE = int[],
+  FINALFUNC = ffp, INITCOND = '{}');
+--    N    N        P    N
+-- should ERROR: tfnp(int[], anyelement) not matched by tfnp(int[], int)
+CREATE AGGREGATE myaggp07a(BASETYPE = anyelement, SFUNC = tfnp, STYPE = int[],
+  FINALFUNC = ffp, INITCOND = '{}');
+ERROR:  AggregateCreate: function tfnp(integer[], anyelement) does not exist
+--    N    N        P    P
+-- should CREATE
+CREATE AGGREGATE myaggp08a(BASETYPE = anyelement, SFUNC = tf2p, STYPE = int[],
+  FINALFUNC = ffp, INITCOND = '{}');
+--    N    P        N    N
+-- should CREATE
+CREATE AGGREGATE myaggp09a(BASETYPE = int, SFUNC = tf1p, STYPE = int[],
+  FINALFUNC = ffp, INITCOND = '{}');
+CREATE AGGREGATE myaggp09b(BASETYPE = int, SFUNC = tf1p, STYPE = int[],
+  INITCOND = '{}');
+--    N    P        N    P
+-- should CREATE
+CREATE AGGREGATE myaggp10a(BASETYPE = int, SFUNC = tfp, STYPE = int[],
+  FINALFUNC = ffp, INITCOND = '{}');
+CREATE AGGREGATE myaggp10b(BASETYPE = int, SFUNC = tfp, STYPE = int[],
+  INITCOND = '{}');
+--    N    P        P    N
+-- should ERROR: tf1p(int[],anyelement) not matched by tf1p(anyarray,int)
+CREATE AGGREGATE myaggp11a(BASETYPE = anyelement, SFUNC = tf1p, STYPE = int[],
+  FINALFUNC = ffp, INITCOND = '{}');
+ERROR:  AggregateCreate: function tf1p(integer[], anyelement) does not exist
+CREATE AGGREGATE myaggp11b(BASETYPE = anyelement, SFUNC = tf1p, STYPE = int[],
+  INITCOND = '{}');
+ERROR:  AggregateCreate: function tf1p(integer[], anyelement) does not exist
+--    N    P        P    P
+-- should ERROR: tfp(int[],anyelement) not matched by tfp(anyarray,anyelement)
+CREATE AGGREGATE myaggp12a(BASETYPE = anyelement, SFUNC = tfp, STYPE = int[],
+  FINALFUNC = ffp, INITCOND = '{}');
+ERROR:  AggregateCreate: function tfp(integer[], anyelement) does not exist
+CREATE AGGREGATE myaggp12b(BASETYPE = anyelement, SFUNC = tfp, STYPE = int[],
+  INITCOND = '{}');
+ERROR:  AggregateCreate: function tfp(integer[], anyelement) does not exist
+--    P    N        N    N
+-- should ERROR: tfnp(anyarray, int) not matched by tfnp(int[],int)
+CREATE AGGREGATE myaggp13a(BASETYPE = int, SFUNC = tfnp, STYPE = anyarray,
+  FINALFUNC = ffp, INITCOND = '{}');
+ERROR:  an aggregate using ANYARRAY or ANYELEMENT as trans type must also have one of them as its base type
+--    P    N        N    P
+-- should ERROR: tf2p(anyarray, int) not matched by tf2p(int[],anyelement)
+CREATE AGGREGATE myaggp14a(BASETYPE = int, SFUNC = tf2p, STYPE = anyarray,
+  FINALFUNC = ffp, INITCOND = '{}');
+ERROR:  an aggregate using ANYARRAY or ANYELEMENT as trans type must also have one of them as its base type
+--    P    N        P    N
+-- should ERROR: tfnp(anyarray, anyelement) not matched by tfnp(int[],int)
+CREATE AGGREGATE myaggp15a(BASETYPE = anyelement, SFUNC = tfnp,
+  STYPE = anyarray, FINALFUNC = ffp, INITCOND = '{}');
+ERROR:  AggregateCreate: function tfnp(anyarray, anyelement) does not exist
+--    P    N        P    P
+-- should ERROR: tf2p(anyarray, anyelement) not matched by tf2p(int[],anyelement)
+CREATE AGGREGATE myaggp16a(BASETYPE = anyelement, SFUNC = tf2p,
+  STYPE = anyarray, FINALFUNC = ffp, INITCOND = '{}');
+ERROR:  AggregateCreate: function tf2p(anyarray, anyelement) does not exist
+--    P    P        N    N
+-- should ERROR: we have no way to resolve S
+CREATE AGGREGATE myaggp17a(BASETYPE = int, SFUNC = tf1p, STYPE = anyarray,
+  FINALFUNC = ffp, INITCOND = '{}');
+ERROR:  an aggregate using ANYARRAY or ANYELEMENT as trans type must also have one of them as its base type
+CREATE AGGREGATE myaggp17b(BASETYPE = int, SFUNC = tf1p, STYPE = anyarray,
+  INITCOND = '{}');
+ERROR:  an aggregate using ANYARRAY or ANYELEMENT as trans type must also have one of them as its base type
+--    P    P        N    P
+-- should ERROR: tfp(anyarray, int) not matched by tfp(anyarray, anyelement)
+CREATE AGGREGATE myaggp18a(BASETYPE = int, SFUNC = tfp, STYPE = anyarray,
+  FINALFUNC = ffp, INITCOND = '{}');
+ERROR:  an aggregate using ANYARRAY or ANYELEMENT as trans type must also have one of them as its base type
+CREATE AGGREGATE myaggp18b(BASETYPE = int, SFUNC = tfp, STYPE = anyarray,
+  INITCOND = '{}');
+ERROR:  an aggregate using ANYARRAY or ANYELEMENT as trans type must also have one of them as its base type
+--    P    P        P    N
+-- should ERROR: tf1p(anyarray, anyelement) not matched by tf1p(anyarray, int)
+CREATE AGGREGATE myaggp19a(BASETYPE = anyelement, SFUNC = tf1p,
+  STYPE = anyarray, FINALFUNC = ffp, INITCOND = '{}');
+ERROR:  AggregateCreate: function tf1p(anyarray, anyelement) does not exist
+CREATE AGGREGATE myaggp19b(BASETYPE = anyelement, SFUNC = tf1p,
+  STYPE = anyarray, INITCOND = '{}');
+ERROR:  AggregateCreate: function tf1p(anyarray, anyelement) does not exist
+--    P    P        P    P
+-- should CREATE
+CREATE AGGREGATE myaggp20a(BASETYPE = anyelement, SFUNC = tfp,
+  STYPE = anyarray, FINALFUNC = ffp, INITCOND = '{}');
+CREATE AGGREGATE myaggp20b(BASETYPE = anyelement, SFUNC = tfp,
+  STYPE = anyarray, INITCOND = '{}');
+--     Case3 (R = N) && (B = A)
+--     ------------------------
+--     S    tf1
+--     -------
+--     N    N
+-- should CREATE
+CREATE AGGREGATE myaggn01a(BASETYPE = "ANY", SFUNC = stfnp, STYPE = int4[],
+  FINALFUNC = ffnp, INITCOND = '{}');
+CREATE AGGREGATE myaggn01b(BASETYPE = "ANY", SFUNC = stfnp, STYPE = int4[],
+  INITCOND = '{}');
+--     P    N
+-- should ERROR: stfnp(anyarray) not matched by stfnp(int[])
+CREATE AGGREGATE myaggn02a(BASETYPE = "ANY", SFUNC = stfnp, STYPE = anyarray,
+  FINALFUNC = ffnp, INITCOND = '{}');
+ERROR:  an aggregate using ANYARRAY or ANYELEMENT as trans type must also have one of them as its base type
+CREATE AGGREGATE myaggn02b(BASETYPE = "ANY", SFUNC = stfnp, STYPE = anyarray,
+  INITCOND = '{}');
+ERROR:  an aggregate using ANYARRAY or ANYELEMENT as trans type must also have one of them as its base type
+--     N    P
+-- should CREATE
+CREATE AGGREGATE myaggn03a(BASETYPE = "ANY", SFUNC = stfp, STYPE = int4[],
+  FINALFUNC = ffnp, INITCOND = '{}');
+--     P    P
+-- should ERROR: ffnp(anyarray) not matched by ffnp(int[])
+CREATE AGGREGATE myaggn04a(BASETYPE = "ANY", SFUNC = stfp, STYPE = anyarray,
+  FINALFUNC = ffnp, INITCOND = '{}');
+ERROR:  an aggregate using ANYARRAY or ANYELEMENT as trans type must also have one of them as its base type
+--    Case4 (R = N) && ((B = P) || (B = N))
+--    -------------------------------------
+--    S    tf1      B    tf2
+--    -----------------------
+--    N    N        N    N
+-- should CREATE
+CREATE AGGREGATE myaggn05a(BASETYPE = int, SFUNC = tfnp, STYPE = int[],
+  FINALFUNC = ffnp, INITCOND = '{}');
+CREATE AGGREGATE myaggn05b(BASETYPE = int, SFUNC = tfnp, STYPE = int[],
+  INITCOND = '{}');
+--    N    N        N    P
+-- should CREATE
+CREATE AGGREGATE myaggn06a(BASETYPE = int, SFUNC = tf2p, STYPE = int[],
+  FINALFUNC = ffnp, INITCOND = '{}');
+CREATE AGGREGATE myaggn06b(BASETYPE = int, SFUNC = tf2p, STYPE = int[],
+  INITCOND = '{}');
+--    N    N        P    N
+-- should ERROR: tfnp(int[], anyelement) not matched by tfnp(int[], int)
+CREATE AGGREGATE myaggn07a(BASETYPE = anyelement, SFUNC = tfnp, STYPE = int[],
+  FINALFUNC = ffnp, INITCOND = '{}');
+ERROR:  AggregateCreate: function tfnp(integer[], anyelement) does not exist
+CREATE AGGREGATE myaggn07b(BASETYPE = anyelement, SFUNC = tfnp, STYPE = int[],
+  INITCOND = '{}');
+ERROR:  AggregateCreate: function tfnp(integer[], anyelement) does not exist
+--    N    N        P    P
+-- should CREATE
+CREATE AGGREGATE myaggn08a(BASETYPE = anyelement, SFUNC = tf2p, STYPE = int[],
+  FINALFUNC = ffnp, INITCOND = '{}');
+CREATE AGGREGATE myaggn08b(BASETYPE = anyelement, SFUNC = tf2p, STYPE = int[],
+  INITCOND = '{}');
+--    N    P        N    N
+-- should CREATE
+CREATE AGGREGATE myaggn09a(BASETYPE = int, SFUNC = tf1p, STYPE = int[],
+  FINALFUNC = ffnp, INITCOND = '{}');
+--    N    P        N    P
+-- should CREATE
+CREATE AGGREGATE myaggn10a(BASETYPE = int, SFUNC = tfp, STYPE = int[],
+  FINALFUNC = ffnp, INITCOND = '{}');
+--    N    P        P    N
+-- should ERROR: tf1p(int[],anyelement) not matched by tf1p(anyarray,int)
+CREATE AGGREGATE myaggn11a(BASETYPE = anyelement, SFUNC = tf1p, STYPE = int[],
+  FINALFUNC = ffnp, INITCOND = '{}');
+ERROR:  AggregateCreate: function tf1p(integer[], anyelement) does not exist
+--    N    P        P    P
+-- should ERROR: tfp(int[],anyelement) not matched by tfp(anyarray,anyelement)
+CREATE AGGREGATE myaggn12a(BASETYPE = anyelement, SFUNC = tfp, STYPE = int[],
+  FINALFUNC = ffnp, INITCOND = '{}');
+ERROR:  AggregateCreate: function tfp(integer[], anyelement) does not exist
+--    P    N        N    N
+-- should ERROR: tfnp(anyarray, int) not matched by tfnp(int[],int)
+CREATE AGGREGATE myaggn13a(BASETYPE = int, SFUNC = tfnp, STYPE = anyarray,
+  FINALFUNC = ffnp, INITCOND = '{}');
+ERROR:  an aggregate using ANYARRAY or ANYELEMENT as trans type must also have one of them as its base type
+CREATE AGGREGATE myaggn13b(BASETYPE = int, SFUNC = tfnp, STYPE = anyarray,
+  INITCOND = '{}');
+ERROR:  an aggregate using ANYARRAY or ANYELEMENT as trans type must also have one of them as its base type
+--    P    N        N    P
+-- should ERROR: tf2p(anyarray, int) not matched by tf2p(int[],anyelement)
+CREATE AGGREGATE myaggn14a(BASETYPE = int, SFUNC = tf2p, STYPE = anyarray,
+  FINALFUNC = ffnp, INITCOND = '{}');
+ERROR:  an aggregate using ANYARRAY or ANYELEMENT as trans type must also have one of them as its base type
+CREATE AGGREGATE myaggn14b(BASETYPE = int, SFUNC = tf2p, STYPE = anyarray,
+  INITCOND = '{}');
+ERROR:  an aggregate using ANYARRAY or ANYELEMENT as trans type must also have one of them as its base type
+--    P    N        P    N
+-- should ERROR: tfnp(anyarray, anyelement) not matched by tfnp(int[],int)
+CREATE AGGREGATE myaggn15a(BASETYPE = anyelement, SFUNC = tfnp,
+  STYPE = anyarray, FINALFUNC = ffnp, INITCOND = '{}');
+ERROR:  AggregateCreate: function tfnp(anyarray, anyelement) does not exist
+CREATE AGGREGATE myaggn15b(BASETYPE = anyelement, SFUNC = tfnp,
+  STYPE = anyarray, INITCOND = '{}');
+ERROR:  AggregateCreate: function tfnp(anyarray, anyelement) does not exist
+--    P    N        P    P
+-- should ERROR: tf2p(anyarray, anyelement) not matched by tf2p(int[],anyelement)
+CREATE AGGREGATE myaggn16a(BASETYPE = anyelement, SFUNC = tf2p,
+  STYPE = anyarray, FINALFUNC = ffnp, INITCOND = '{}');
+ERROR:  AggregateCreate: function tf2p(anyarray, anyelement) does not exist
+CREATE AGGREGATE myaggn16b(BASETYPE = anyelement, SFUNC = tf2p,
+  STYPE = anyarray, INITCOND = '{}');
+ERROR:  AggregateCreate: function tf2p(anyarray, anyelement) does not exist
+--    P    P        N    N
+-- should ERROR: ffnp(anyarray) not matched by ffnp(int[])
+CREATE AGGREGATE myaggn17a(BASETYPE = int, SFUNC = tf1p, STYPE = anyarray,
+  FINALFUNC = ffnp, INITCOND = '{}');
+ERROR:  an aggregate using ANYARRAY or ANYELEMENT as trans type must also have one of them as its base type
+--    P    P        N    P
+-- should ERROR: tfp(anyarray, int) not matched by tfp(anyarray, anyelement)
+CREATE AGGREGATE myaggn18a(BASETYPE = int, SFUNC = tfp, STYPE = anyarray,
+  FINALFUNC = ffnp, INITCOND = '{}');
+ERROR:  an aggregate using ANYARRAY or ANYELEMENT as trans type must also have one of them as its base type
+--    P    P        P    N
+-- should ERROR: tf1p(anyarray, anyelement) not matched by tf1p(anyarray, int)
+CREATE AGGREGATE myaggn19a(BASETYPE = anyelement, SFUNC = tf1p,
+  STYPE = anyarray, FINALFUNC = ffnp, INITCOND = '{}');
+ERROR:  AggregateCreate: function tf1p(anyarray, anyelement) does not exist
+--    P    P        P    P
+-- should ERROR: ffnp(anyarray) not matched by ffnp(int[])
+CREATE AGGREGATE myaggn20a(BASETYPE = anyelement, SFUNC = tfp,
+  STYPE = anyarray, FINALFUNC = ffnp, INITCOND = '{}');
+ERROR:  AggregateCreate: function ffnp(anyarray) does not exist
+-- create test data for polymorphic aggregates
+create temp table t(f1 int, f2 int[], f3 text);
+insert into t values(1,array[1],'a');
+insert into t values(1,array[11],'b');
+insert into t values(1,array[111],'c');
+insert into t values(2,array[2],'a');
+insert into t values(2,array[22],'b');
+insert into t values(2,array[222],'c');
+insert into t values(3,array[3],'a');
+insert into t values(3,array[3],'b');
+-- test the successfully created polymorphic aggregates
+select f3, myaggp01a(*) from t group by f3;
+ f3 | myaggp01a 
+----+-----------
+ b  | {}
+ a  | {}
+ c  | {}
+(3 rows)
+
+select f3, myaggp03a(*) from t group by f3;
+ f3 | myaggp03a 
+----+-----------
+ b  | {}
+ a  | {}
+ c  | {}
+(3 rows)
+
+select f3, myaggp03b(*) from t group by f3;
+ f3 | myaggp03b 
+----+-----------
+ b  | {}
+ a  | {}
+ c  | {}
+(3 rows)
+
+select f3, myaggp05a(f1) from t group by f3;
+ f3 | myaggp05a 
+----+-----------
+ b  | {1,2,3}
+ a  | {1,2,3}
+ c  | {1,2}
+(3 rows)
+
+select f3, myaggp06a(f1) from t group by f3;
+ f3 | myaggp06a 
+----+-----------
+ b  | {}
+ a  | {}
+ c  | {}
+(3 rows)
+
+select f3, myaggp08a(f1) from t group by f3;
+ f3 | myaggp08a 
+----+-----------
+ b  | {}
+ a  | {}
+ c  | {}
+(3 rows)
+
+select f3, myaggp09a(f1) from t group by f3;
+ f3 | myaggp09a 
+----+-----------
+ b  | {}
+ a  | {}
+ c  | {}
+(3 rows)
+
+select f3, myaggp09b(f1) from t group by f3;
+ f3 | myaggp09b 
+----+-----------
+ b  | {}
+ a  | {}
+ c  | {}
+(3 rows)
+
+select f3, myaggp10a(f1) from t group by f3;
+ f3 | myaggp10a 
+----+-----------
+ b  | {1,2,3}
+ a  | {1,2,3}
+ c  | {1,2}
+(3 rows)
+
+select f3, myaggp10b(f1) from t group by f3;
+ f3 | myaggp10b 
+----+-----------
+ b  | {1,2,3}
+ a  | {1,2,3}
+ c  | {1,2}
+(3 rows)
+
+select f3, myaggp20a(f1) from t group by f3;
+ f3 | myaggp20a 
+----+-----------
+ b  | {1,2,3}
+ a  | {1,2,3}
+ c  | {1,2}
+(3 rows)
+
+select f3, myaggp20b(f1) from t group by f3;
+ f3 | myaggp20b 
+----+-----------
+ b  | {1,2,3}
+ a  | {1,2,3}
+ c  | {1,2}
+(3 rows)
+
+select f3, myaggn01a(*) from t group by f3;
+ f3 | myaggn01a 
+----+-----------
+ b  | {}
+ a  | {}
+ c  | {}
+(3 rows)
+
+select f3, myaggn01b(*) from t group by f3;
+ f3 | myaggn01b 
+----+-----------
+ b  | {}
+ a  | {}
+ c  | {}
+(3 rows)
+
+select f3, myaggn03a(*) from t group by f3;
+ f3 | myaggn03a 
+----+-----------
+ b  | {}
+ a  | {}
+ c  | {}
+(3 rows)
+
+select f3, myaggn05a(f1) from t group by f3;
+ f3 | myaggn05a 
+----+-----------
+ b  | {1,2,3}
+ a  | {1,2,3}
+ c  | {1,2}
+(3 rows)
+
+select f3, myaggn05b(f1) from t group by f3;
+ f3 | myaggn05b 
+----+-----------
+ b  | {1,2,3}
+ a  | {1,2,3}
+ c  | {1,2}
+(3 rows)
+
+select f3, myaggn06a(f1) from t group by f3;
+ f3 | myaggn06a 
+----+-----------
+ b  | {}
+ a  | {}
+ c  | {}
+(3 rows)
+
+select f3, myaggn06b(f1) from t group by f3;
+ f3 | myaggn06b 
+----+-----------
+ b  | {}
+ a  | {}
+ c  | {}
+(3 rows)
+
+select f3, myaggn08a(f1) from t group by f3;
+ f3 | myaggn08a 
+----+-----------
+ b  | {}
+ a  | {}
+ c  | {}
+(3 rows)
+
+select f3, myaggn08b(f1) from t group by f3;
+ f3 | myaggn08b 
+----+-----------
+ b  | {}
+ a  | {}
+ c  | {}
+(3 rows)
+
+select f3, myaggn09a(f1) from t group by f3;
+ f3 | myaggn09a 
+----+-----------
+ b  | {}
+ a  | {}
+ c  | {}
+(3 rows)
+
+select f3, myaggn10a(f1) from t group by f3;
+ f3 | myaggn10a 
+----+-----------
+ b  | {1,2,3}
+ a  | {1,2,3}
+ c  | {1,2}
+(3 rows)
+
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index e8e8d1e67bd0a0a4128f4b15ec659e700616d5b8..913c4cba0cd85be8465ae9a8c99574f1523d9496 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -74,4 +74,4 @@ test: select_views portals_p2 rules foreign_key cluster
 # The sixth group of parallel test
 # ----------
 # "plpgsql" cannot run concurrently with "rules"
-test: limit plpgsql copy2 temp domain rangefuncs prepare without_oid conversion truncate alter_table sequence
+test: limit plpgsql copy2 temp domain rangefuncs prepare without_oid conversion truncate alter_table sequence polymorphism
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
index ff2a0d16625f5a1cd063f04df20b52eb373edfe4..d3ae9f5ddb2c01a9152c1ca8ec253c49dbcac142 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -1,4 +1,4 @@
-# $Header: /cvsroot/pgsql/src/test/regress/serial_schedule,v 1.19 2003/03/20 07:02:11 momjian Exp $
+# $Header: /cvsroot/pgsql/src/test/regress/serial_schedule,v 1.20 2003/07/01 19:10:53 tgl Exp $
 # This should probably be in an order similar to parallel_schedule.
 test: boolean
 test: char
@@ -91,3 +91,4 @@ test: conversion
 test: truncate
 test: alter_table
 test: sequence
+test: polymorphism
diff --git a/src/test/regress/sql/polymorphism.sql b/src/test/regress/sql/polymorphism.sql
new file mode 100644
index 0000000000000000000000000000000000000000..5175f9f93d1c1f7a99c8b637f5a593dce41209b5
--- /dev/null
+++ b/src/test/regress/sql/polymorphism.sql
@@ -0,0 +1,367 @@
+-- Currently this tests polymorphic aggregates and indirectly does some
+-- testing of polymorphic SQL functions.  It ought to be extended.
+
+
+-- Legend:
+-----------
+-- A = type is ANY
+-- P = type is polymorphic
+-- N = type is non-polymorphic
+-- B = aggregate base type
+-- S = aggregate state type
+-- R = aggregate return type
+-- 1 = arg1 of a function
+-- 2 = arg2 of a function
+-- ag = aggregate
+-- tf = trans (state) function
+-- ff = final function
+-- rt = return type of a function
+-- -> = implies
+-- => = allowed
+-- !> = not allowed
+-- E  = exists
+-- NE = not-exists
+-- 
+-- Possible states:
+-- ----------------
+-- B = (A || P || N)
+--   when (B = A) -> (tf2 = NE)
+-- S = (P || N)
+-- ff = (E || NE)
+-- tf1 = (P || N)
+-- tf2 = (NE || P || N)
+-- R = (P || N)
+
+-- create functions for use as tf and ff with the needed combinations of
+-- argument polymorphism, but within the constraints of valid aggregate
+-- functions, i.e. tf arg1 and tf return type must match
+
+-- polymorphic single arg transfn
+CREATE FUNCTION stfp(anyarray) returns anyarray as
+'select $1' language 'sql';
+-- non-polymorphic single arg transfn
+CREATE FUNCTION stfnp(int[]) returns int[] as
+'select $1' language 'sql';
+
+-- dual polymorphic transfn
+CREATE FUNCTION tfp(anyarray,anyelement) returns anyarray as
+'select $1 || $2' language 'sql';
+-- dual non-polymorphic transfn
+CREATE FUNCTION tfnp(int[],int) returns int[] as
+'select $1 || $2' language 'sql';
+
+-- arg1 only polymorphic transfn
+CREATE FUNCTION tf1p(anyarray,int) returns anyarray as
+'select $1' language 'sql';
+-- arg2 only polymorphic transfn
+CREATE FUNCTION tf2p(int[],anyelement) returns int[] as
+'select $1' language 'sql';
+
+-- finalfn polymorphic
+CREATE FUNCTION ffp(anyarray) returns anyarray as
+'select $1' language 'sql';
+-- finalfn non-polymorphic
+CREATE FUNCTION ffnp(int[]) returns int[] as
+'select $1' language 'sql';
+
+-- Try to cover all the possible states:
+-- 
+-- Note: in Cases 1 & 2, we are trying to return P. Therefore, if the transfn
+-- is stfnp, tfnp, or tf2p, we must use ffp as finalfn, because stfnp, tfnp,
+-- and tf2p do not return P. Conversely, in Cases 3 & 4, we are trying to
+-- return N. Therefore, if the transfn is stfp, tfp, or tf1p, we must use ffnp
+-- as finalfn, because stfp, tfp, and tf1p do not return N.
+--
+--     Case1 (R = P) && (B = A)
+--     ------------------------
+--     S    tf1
+--     -------
+--     N    N
+-- should CREATE
+CREATE AGGREGATE myaggp01a(BASETYPE = "ANY", SFUNC = stfnp, STYPE = int4[],
+  FINALFUNC = ffp, INITCOND = '{}');
+
+--     P    N
+-- should ERROR: stfnp(anyarray) not matched by stfnp(int[])
+CREATE AGGREGATE myaggp02a(BASETYPE = "ANY", SFUNC = stfnp, STYPE = anyarray,
+  FINALFUNC = ffp, INITCOND = '{}');
+
+--     N    P
+-- should CREATE
+CREATE AGGREGATE myaggp03a(BASETYPE = "ANY", SFUNC = stfp, STYPE = int4[],
+  FINALFUNC = ffp, INITCOND = '{}');
+CREATE AGGREGATE myaggp03b(BASETYPE = "ANY", SFUNC = stfp, STYPE = int4[],
+  INITCOND = '{}');
+
+--     P    P
+-- should ERROR: we have no way to resolve S
+CREATE AGGREGATE myaggp04a(BASETYPE = "ANY", SFUNC = stfp, STYPE = anyarray,
+  FINALFUNC = ffp, INITCOND = '{}');
+CREATE AGGREGATE myaggp04b(BASETYPE = "ANY", SFUNC = stfp, STYPE = anyarray,
+  INITCOND = '{}');
+
+
+--    Case2 (R = P) && ((B = P) || (B = N))
+--    -------------------------------------
+--    S    tf1      B    tf2
+--    -----------------------
+--    N    N        N    N
+-- should CREATE
+CREATE AGGREGATE myaggp05a(BASETYPE = int, SFUNC = tfnp, STYPE = int[],
+  FINALFUNC = ffp, INITCOND = '{}');
+
+--    N    N        N    P
+-- should CREATE
+CREATE AGGREGATE myaggp06a(BASETYPE = int, SFUNC = tf2p, STYPE = int[],
+  FINALFUNC = ffp, INITCOND = '{}');
+
+--    N    N        P    N
+-- should ERROR: tfnp(int[], anyelement) not matched by tfnp(int[], int)
+CREATE AGGREGATE myaggp07a(BASETYPE = anyelement, SFUNC = tfnp, STYPE = int[],
+  FINALFUNC = ffp, INITCOND = '{}');
+
+--    N    N        P    P
+-- should CREATE
+CREATE AGGREGATE myaggp08a(BASETYPE = anyelement, SFUNC = tf2p, STYPE = int[],
+  FINALFUNC = ffp, INITCOND = '{}');
+
+--    N    P        N    N
+-- should CREATE
+CREATE AGGREGATE myaggp09a(BASETYPE = int, SFUNC = tf1p, STYPE = int[],
+  FINALFUNC = ffp, INITCOND = '{}');
+CREATE AGGREGATE myaggp09b(BASETYPE = int, SFUNC = tf1p, STYPE = int[],
+  INITCOND = '{}');
+
+--    N    P        N    P
+-- should CREATE
+CREATE AGGREGATE myaggp10a(BASETYPE = int, SFUNC = tfp, STYPE = int[],
+  FINALFUNC = ffp, INITCOND = '{}');
+CREATE AGGREGATE myaggp10b(BASETYPE = int, SFUNC = tfp, STYPE = int[],
+  INITCOND = '{}');
+
+--    N    P        P    N
+-- should ERROR: tf1p(int[],anyelement) not matched by tf1p(anyarray,int)
+CREATE AGGREGATE myaggp11a(BASETYPE = anyelement, SFUNC = tf1p, STYPE = int[],
+  FINALFUNC = ffp, INITCOND = '{}');
+CREATE AGGREGATE myaggp11b(BASETYPE = anyelement, SFUNC = tf1p, STYPE = int[],
+  INITCOND = '{}');
+
+--    N    P        P    P
+-- should ERROR: tfp(int[],anyelement) not matched by tfp(anyarray,anyelement)
+CREATE AGGREGATE myaggp12a(BASETYPE = anyelement, SFUNC = tfp, STYPE = int[],
+  FINALFUNC = ffp, INITCOND = '{}');
+CREATE AGGREGATE myaggp12b(BASETYPE = anyelement, SFUNC = tfp, STYPE = int[],
+  INITCOND = '{}');
+
+--    P    N        N    N
+-- should ERROR: tfnp(anyarray, int) not matched by tfnp(int[],int)
+CREATE AGGREGATE myaggp13a(BASETYPE = int, SFUNC = tfnp, STYPE = anyarray,
+  FINALFUNC = ffp, INITCOND = '{}');
+
+--    P    N        N    P
+-- should ERROR: tf2p(anyarray, int) not matched by tf2p(int[],anyelement)
+CREATE AGGREGATE myaggp14a(BASETYPE = int, SFUNC = tf2p, STYPE = anyarray,
+  FINALFUNC = ffp, INITCOND = '{}');
+
+--    P    N        P    N
+-- should ERROR: tfnp(anyarray, anyelement) not matched by tfnp(int[],int)
+CREATE AGGREGATE myaggp15a(BASETYPE = anyelement, SFUNC = tfnp,
+  STYPE = anyarray, FINALFUNC = ffp, INITCOND = '{}');
+
+--    P    N        P    P
+-- should ERROR: tf2p(anyarray, anyelement) not matched by tf2p(int[],anyelement)
+CREATE AGGREGATE myaggp16a(BASETYPE = anyelement, SFUNC = tf2p,
+  STYPE = anyarray, FINALFUNC = ffp, INITCOND = '{}');
+
+--    P    P        N    N
+-- should ERROR: we have no way to resolve S
+CREATE AGGREGATE myaggp17a(BASETYPE = int, SFUNC = tf1p, STYPE = anyarray,
+  FINALFUNC = ffp, INITCOND = '{}');
+CREATE AGGREGATE myaggp17b(BASETYPE = int, SFUNC = tf1p, STYPE = anyarray,
+  INITCOND = '{}');
+
+--    P    P        N    P
+-- should ERROR: tfp(anyarray, int) not matched by tfp(anyarray, anyelement)
+CREATE AGGREGATE myaggp18a(BASETYPE = int, SFUNC = tfp, STYPE = anyarray,
+  FINALFUNC = ffp, INITCOND = '{}');
+CREATE AGGREGATE myaggp18b(BASETYPE = int, SFUNC = tfp, STYPE = anyarray,
+  INITCOND = '{}');
+
+--    P    P        P    N
+-- should ERROR: tf1p(anyarray, anyelement) not matched by tf1p(anyarray, int)
+CREATE AGGREGATE myaggp19a(BASETYPE = anyelement, SFUNC = tf1p,
+  STYPE = anyarray, FINALFUNC = ffp, INITCOND = '{}');
+CREATE AGGREGATE myaggp19b(BASETYPE = anyelement, SFUNC = tf1p,
+  STYPE = anyarray, INITCOND = '{}');
+
+--    P    P        P    P
+-- should CREATE
+CREATE AGGREGATE myaggp20a(BASETYPE = anyelement, SFUNC = tfp,
+  STYPE = anyarray, FINALFUNC = ffp, INITCOND = '{}');
+CREATE AGGREGATE myaggp20b(BASETYPE = anyelement, SFUNC = tfp,
+  STYPE = anyarray, INITCOND = '{}');
+
+--     Case3 (R = N) && (B = A)
+--     ------------------------
+--     S    tf1
+--     -------
+--     N    N
+-- should CREATE
+CREATE AGGREGATE myaggn01a(BASETYPE = "ANY", SFUNC = stfnp, STYPE = int4[],
+  FINALFUNC = ffnp, INITCOND = '{}');
+CREATE AGGREGATE myaggn01b(BASETYPE = "ANY", SFUNC = stfnp, STYPE = int4[],
+  INITCOND = '{}');
+
+--     P    N
+-- should ERROR: stfnp(anyarray) not matched by stfnp(int[])
+CREATE AGGREGATE myaggn02a(BASETYPE = "ANY", SFUNC = stfnp, STYPE = anyarray,
+  FINALFUNC = ffnp, INITCOND = '{}');
+CREATE AGGREGATE myaggn02b(BASETYPE = "ANY", SFUNC = stfnp, STYPE = anyarray,
+  INITCOND = '{}');
+
+--     N    P
+-- should CREATE
+CREATE AGGREGATE myaggn03a(BASETYPE = "ANY", SFUNC = stfp, STYPE = int4[],
+  FINALFUNC = ffnp, INITCOND = '{}');
+
+--     P    P
+-- should ERROR: ffnp(anyarray) not matched by ffnp(int[])
+CREATE AGGREGATE myaggn04a(BASETYPE = "ANY", SFUNC = stfp, STYPE = anyarray,
+  FINALFUNC = ffnp, INITCOND = '{}');
+
+
+--    Case4 (R = N) && ((B = P) || (B = N))
+--    -------------------------------------
+--    S    tf1      B    tf2
+--    -----------------------
+--    N    N        N    N
+-- should CREATE
+CREATE AGGREGATE myaggn05a(BASETYPE = int, SFUNC = tfnp, STYPE = int[],
+  FINALFUNC = ffnp, INITCOND = '{}');
+CREATE AGGREGATE myaggn05b(BASETYPE = int, SFUNC = tfnp, STYPE = int[],
+  INITCOND = '{}');
+
+--    N    N        N    P
+-- should CREATE
+CREATE AGGREGATE myaggn06a(BASETYPE = int, SFUNC = tf2p, STYPE = int[],
+  FINALFUNC = ffnp, INITCOND = '{}');
+CREATE AGGREGATE myaggn06b(BASETYPE = int, SFUNC = tf2p, STYPE = int[],
+  INITCOND = '{}');
+
+--    N    N        P    N
+-- should ERROR: tfnp(int[], anyelement) not matched by tfnp(int[], int)
+CREATE AGGREGATE myaggn07a(BASETYPE = anyelement, SFUNC = tfnp, STYPE = int[],
+  FINALFUNC = ffnp, INITCOND = '{}');
+CREATE AGGREGATE myaggn07b(BASETYPE = anyelement, SFUNC = tfnp, STYPE = int[],
+  INITCOND = '{}');
+
+--    N    N        P    P
+-- should CREATE
+CREATE AGGREGATE myaggn08a(BASETYPE = anyelement, SFUNC = tf2p, STYPE = int[],
+  FINALFUNC = ffnp, INITCOND = '{}');
+CREATE AGGREGATE myaggn08b(BASETYPE = anyelement, SFUNC = tf2p, STYPE = int[],
+  INITCOND = '{}');
+
+--    N    P        N    N
+-- should CREATE
+CREATE AGGREGATE myaggn09a(BASETYPE = int, SFUNC = tf1p, STYPE = int[],
+  FINALFUNC = ffnp, INITCOND = '{}');
+
+--    N    P        N    P
+-- should CREATE
+CREATE AGGREGATE myaggn10a(BASETYPE = int, SFUNC = tfp, STYPE = int[],
+  FINALFUNC = ffnp, INITCOND = '{}');
+
+--    N    P        P    N
+-- should ERROR: tf1p(int[],anyelement) not matched by tf1p(anyarray,int)
+CREATE AGGREGATE myaggn11a(BASETYPE = anyelement, SFUNC = tf1p, STYPE = int[],
+  FINALFUNC = ffnp, INITCOND = '{}');
+
+--    N    P        P    P
+-- should ERROR: tfp(int[],anyelement) not matched by tfp(anyarray,anyelement)
+CREATE AGGREGATE myaggn12a(BASETYPE = anyelement, SFUNC = tfp, STYPE = int[],
+  FINALFUNC = ffnp, INITCOND = '{}');
+
+--    P    N        N    N
+-- should ERROR: tfnp(anyarray, int) not matched by tfnp(int[],int)
+CREATE AGGREGATE myaggn13a(BASETYPE = int, SFUNC = tfnp, STYPE = anyarray,
+  FINALFUNC = ffnp, INITCOND = '{}');
+CREATE AGGREGATE myaggn13b(BASETYPE = int, SFUNC = tfnp, STYPE = anyarray,
+  INITCOND = '{}');
+
+--    P    N        N    P
+-- should ERROR: tf2p(anyarray, int) not matched by tf2p(int[],anyelement)
+CREATE AGGREGATE myaggn14a(BASETYPE = int, SFUNC = tf2p, STYPE = anyarray,
+  FINALFUNC = ffnp, INITCOND = '{}');
+CREATE AGGREGATE myaggn14b(BASETYPE = int, SFUNC = tf2p, STYPE = anyarray,
+  INITCOND = '{}');
+
+--    P    N        P    N
+-- should ERROR: tfnp(anyarray, anyelement) not matched by tfnp(int[],int)
+CREATE AGGREGATE myaggn15a(BASETYPE = anyelement, SFUNC = tfnp,
+  STYPE = anyarray, FINALFUNC = ffnp, INITCOND = '{}');
+CREATE AGGREGATE myaggn15b(BASETYPE = anyelement, SFUNC = tfnp,
+  STYPE = anyarray, INITCOND = '{}');
+
+--    P    N        P    P
+-- should ERROR: tf2p(anyarray, anyelement) not matched by tf2p(int[],anyelement)
+CREATE AGGREGATE myaggn16a(BASETYPE = anyelement, SFUNC = tf2p,
+  STYPE = anyarray, FINALFUNC = ffnp, INITCOND = '{}');
+CREATE AGGREGATE myaggn16b(BASETYPE = anyelement, SFUNC = tf2p,
+  STYPE = anyarray, INITCOND = '{}');
+
+--    P    P        N    N
+-- should ERROR: ffnp(anyarray) not matched by ffnp(int[])
+CREATE AGGREGATE myaggn17a(BASETYPE = int, SFUNC = tf1p, STYPE = anyarray,
+  FINALFUNC = ffnp, INITCOND = '{}');
+
+--    P    P        N    P
+-- should ERROR: tfp(anyarray, int) not matched by tfp(anyarray, anyelement)
+CREATE AGGREGATE myaggn18a(BASETYPE = int, SFUNC = tfp, STYPE = anyarray,
+  FINALFUNC = ffnp, INITCOND = '{}');
+
+--    P    P        P    N
+-- should ERROR: tf1p(anyarray, anyelement) not matched by tf1p(anyarray, int)
+CREATE AGGREGATE myaggn19a(BASETYPE = anyelement, SFUNC = tf1p,
+  STYPE = anyarray, FINALFUNC = ffnp, INITCOND = '{}');
+
+--    P    P        P    P
+-- should ERROR: ffnp(anyarray) not matched by ffnp(int[])
+CREATE AGGREGATE myaggn20a(BASETYPE = anyelement, SFUNC = tfp,
+  STYPE = anyarray, FINALFUNC = ffnp, INITCOND = '{}');
+
+-- create test data for polymorphic aggregates
+create temp table t(f1 int, f2 int[], f3 text);
+insert into t values(1,array[1],'a');
+insert into t values(1,array[11],'b');
+insert into t values(1,array[111],'c');
+insert into t values(2,array[2],'a');
+insert into t values(2,array[22],'b');
+insert into t values(2,array[222],'c');
+insert into t values(3,array[3],'a');
+insert into t values(3,array[3],'b');
+
+-- test the successfully created polymorphic aggregates
+select f3, myaggp01a(*) from t group by f3;
+select f3, myaggp03a(*) from t group by f3;
+select f3, myaggp03b(*) from t group by f3;
+select f3, myaggp05a(f1) from t group by f3;
+select f3, myaggp06a(f1) from t group by f3;
+select f3, myaggp08a(f1) from t group by f3;
+select f3, myaggp09a(f1) from t group by f3;
+select f3, myaggp09b(f1) from t group by f3;
+select f3, myaggp10a(f1) from t group by f3;
+select f3, myaggp10b(f1) from t group by f3;
+select f3, myaggp20a(f1) from t group by f3;
+select f3, myaggp20b(f1) from t group by f3;
+select f3, myaggn01a(*) from t group by f3;
+select f3, myaggn01b(*) from t group by f3;
+select f3, myaggn03a(*) from t group by f3;
+select f3, myaggn05a(f1) from t group by f3;
+select f3, myaggn05b(f1) from t group by f3;
+select f3, myaggn06a(f1) from t group by f3;
+select f3, myaggn06b(f1) from t group by f3;
+select f3, myaggn08a(f1) from t group by f3;
+select f3, myaggn08b(f1) from t group by f3;
+select f3, myaggn09a(f1) from t group by f3;
+select f3, myaggn10a(f1) from t group by f3;