diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index 48b90e56ef1034aea86e92db9a522f4c46b0be80..4ec4c44bd402f0a30e6c73c3e1e58fdc46667d07 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.97 2003/06/15 17:59:10 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.98 2003/07/01 00:04:37 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -33,7 +33,6 @@
 #include "utils/syscache.h"
 
 
-static void checkretval(Oid rettype, char fn_typtype, List *queryTreeList);
 Datum		fmgr_internal_validator(PG_FUNCTION_ARGS);
 Datum		fmgr_c_validator(PG_FUNCTION_ARGS);
 Datum		fmgr_sql_validator(PG_FUNCTION_ARGS);
@@ -317,15 +316,20 @@ ProcedureCreate(const char *procedureName,
 }
 
 /*
- * checkretval() -- check return value of a list of sql parse trees.
+ * check_sql_fn_retval() -- check return value of a list of sql parse trees.
  *
  * The return value of a sql function is the value returned by
- * the final query in the function.  We do some ad-hoc define-time
- * type checking here to be sure that the user is returning the
- * type he claims.
+ * the final query in the function.  We do some ad-hoc type checking here
+ * to be sure that the user is returning the type he claims.
+ *
+ * This is normally applied during function definition, but in the case
+ * of a function with polymorphic arguments, we instead apply it during
+ * function execution startup.  The rettype is then the actual resolved
+ * output type of the function, rather than the declared type.  (Therefore,
+ * we should never see ANYARRAY or ANYELEMENT as rettype.)
  */
-static void
-checkretval(Oid rettype, char fn_typtype, List *queryTreeList)
+void
+check_sql_fn_retval(Oid rettype, char fn_typtype, List *queryTreeList)
 {
 	Query	   *parse;
 	int			cmd;
@@ -472,7 +476,7 @@ checkretval(Oid rettype, char fn_typtype, List *queryTreeList)
 
 		relation_close(reln, AccessShareLock);
 	}
-	else if (fn_typtype == 'p' && rettype == RECORDOID)
+	else if (rettype == RECORDOID)
 	{
 		/* Shouldn't have a typerelid */
 		Assert(typerelid == InvalidOid);
@@ -482,6 +486,14 @@ checkretval(Oid rettype, char fn_typtype, List *queryTreeList)
 		 * tuple.
 		 */
 	}
+	else if (rettype == ANYARRAYOID || rettype == ANYELEMENTOID)
+	{
+		/*
+		 * This should already have been caught ...
+		 */
+		elog(ERROR, "functions returning ANYARRAY or ANYELEMENT must " \
+			 "have at least one argument of either type");
+	}
 	else
 		elog(ERROR, "return type %s is not supported for SQL functions",
 			 format_type_be(rettype));
@@ -505,7 +517,9 @@ fmgr_internal_validator(PG_FUNCTION_ARGS)
 	Datum		tmp;
 	char	   *prosrc;
 
-	tuple = SearchSysCache(PROCOID, funcoid, 0, 0, 0);
+	tuple = SearchSysCache(PROCOID,
+						   ObjectIdGetDatum(funcoid),
+						   0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
 		elog(ERROR, "cache lookup of function %u failed", funcoid);
 	proc = (Form_pg_proc) GETSTRUCT(tuple);
@@ -544,7 +558,9 @@ fmgr_c_validator(PG_FUNCTION_ARGS)
 	char	   *prosrc;
 	char	   *probin;
 
-	tuple = SearchSysCache(PROCOID, funcoid, 0, 0, 0);
+	tuple = SearchSysCache(PROCOID,
+						   ObjectIdGetDatum(funcoid),
+						   0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
 		elog(ERROR, "cache lookup of function %u failed", funcoid);
 	proc = (Form_pg_proc) GETSTRUCT(tuple);
@@ -585,38 +601,62 @@ fmgr_sql_validator(PG_FUNCTION_ARGS)
 	Datum		tmp;
 	char	   *prosrc;
 	char		functyptype;
+	bool		haspolyarg;
 	int			i;
 
-	tuple = SearchSysCache(PROCOID, funcoid, 0, 0, 0);
+	tuple = SearchSysCache(PROCOID,
+						   ObjectIdGetDatum(funcoid),
+						   0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
 		elog(ERROR, "cache lookup of function %u failed", funcoid);
 	proc = (Form_pg_proc) GETSTRUCT(tuple);
 
 	functyptype = get_typtype(proc->prorettype);
 
-	/* Disallow pseudotypes in arguments and result */
-	/* except that return type can be RECORD or VOID */
+	/* Disallow pseudotype result */
+	/* except for RECORD, VOID, ANYARRAY, or ANYELEMENT */
 	if (functyptype == 'p' &&
 		proc->prorettype != RECORDOID &&
-		proc->prorettype != VOIDOID)
+		proc->prorettype != VOIDOID &&
+		proc->prorettype != ANYARRAYOID &&
+		proc->prorettype != ANYELEMENTOID)
 		elog(ERROR, "SQL functions cannot return type %s",
 			 format_type_be(proc->prorettype));
 
+	/* Disallow pseudotypes in arguments */
+	/* except for ANYARRAY or ANYELEMENT */
+	haspolyarg = false;
 	for (i = 0; i < proc->pronargs; i++)
 	{
 		if (get_typtype(proc->proargtypes[i]) == 'p')
-			elog(ERROR, "SQL functions cannot have arguments of type %s",
-				 format_type_be(proc->proargtypes[i]));
+		{
+			if (proc->proargtypes[i] == ANYARRAYOID ||
+				proc->proargtypes[i] == ANYELEMENTOID)
+				haspolyarg = true;
+			else
+				elog(ERROR, "SQL functions cannot have arguments of type %s",
+					 format_type_be(proc->proargtypes[i]));
+		}
 	}
 
-	tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull);
-	if (isnull)
-		elog(ERROR, "null prosrc");
+	/*
+	 * We can't precheck the function definition if there are any polymorphic
+	 * input types, because actual datatypes of expression results will be
+	 * unresolvable.  The check will be done at runtime instead.
+	 */
+	if (!haspolyarg)
+	{
+		tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull);
+		if (isnull)
+			elog(ERROR, "null prosrc");
 
-	prosrc = DatumGetCString(DirectFunctionCall1(textout, tmp));
+		prosrc = DatumGetCString(DirectFunctionCall1(textout, tmp));
 
-	querytree_list = pg_parse_and_rewrite(prosrc, proc->proargtypes, proc->pronargs);
-	checkretval(proc->prorettype, functyptype, querytree_list);
+		querytree_list = pg_parse_and_rewrite(prosrc,
+											  proc->proargtypes,
+											  proc->pronargs);
+		check_sql_fn_retval(proc->prorettype, functyptype, querytree_list);
+	}
 
 	ReleaseSysCache(tuple);
 
diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c
index a0e0919fd0b61f01f9545e1c02f0e2d875f6553b..e0ab9e92d5010ec2474122a82a18a7c192936756 100644
--- a/src/backend/executor/functions.c
+++ b/src/backend/executor/functions.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.66 2003/06/12 17:29:26 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.67 2003/07/01 00:04:37 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -24,6 +24,7 @@
 #include "tcop/tcopprot.h"
 #include "tcop/utility.h"
 #include "utils/builtins.h"
+#include "utils/lsyscache.h"
 #include "utils/syscache.h"
 
 
@@ -76,7 +77,8 @@ typedef SQLFunctionCache *SQLFunctionCachePtr;
 
 /* non-export function prototypes */
 static execution_state *init_execution_state(char *src,
-					 Oid *argOidVect, int nargs);
+					 Oid *argOidVect, int nargs,
+					 Oid rettype, bool haspolyarg);
 static void init_sql_fcache(FmgrInfo *finfo);
 static void postquel_start(execution_state *es, SQLFunctionCachePtr fcache);
 static TupleTableSlot *postquel_getnext(execution_state *es);
@@ -90,7 +92,8 @@ static void ShutdownSQLFunction(Datum arg);
 
 
 static execution_state *
-init_execution_state(char *src, Oid *argOidVect, int nargs)
+init_execution_state(char *src, Oid *argOidVect, int nargs,
+					 Oid rettype, bool haspolyarg)
 {
 	execution_state *firstes;
 	execution_state *preves;
@@ -99,6 +102,13 @@ init_execution_state(char *src, Oid *argOidVect, int nargs)
 
 	queryTree_list = pg_parse_and_rewrite(src, argOidVect, nargs);
 
+	/*
+	 * If the function has any arguments declared as polymorphic types,
+	 * then it wasn't type-checked at definition time; must do so now.
+	 */
+	if (haspolyarg)
+		check_sql_fn_retval(rettype, get_typtype(rettype), queryTree_list);
+
 	firstes = NULL;
 	preves = NULL;
 
@@ -133,17 +143,21 @@ static void
 init_sql_fcache(FmgrInfo *finfo)
 {
 	Oid			foid = finfo->fn_oid;
+	Oid			rettype;
 	HeapTuple	procedureTuple;
 	HeapTuple	typeTuple;
 	Form_pg_proc procedureStruct;
 	Form_pg_type typeStruct;
 	SQLFunctionCachePtr fcache;
 	Oid		   *argOidVect;
+	bool		haspolyarg;
 	char	   *src;
 	int			nargs;
 	Datum		tmp;
 	bool		isNull;
 
+	fcache = (SQLFunctionCachePtr) palloc0(sizeof(SQLFunctionCache));
+
 	/*
 	 * get the procedure tuple corresponding to the given function Oid
 	 */
@@ -153,30 +167,37 @@ init_sql_fcache(FmgrInfo *finfo)
 	if (!HeapTupleIsValid(procedureTuple))
 		elog(ERROR, "init_sql_fcache: Cache lookup failed for procedure %u",
 			 foid);
-
 	procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple);
 
 	/*
-	 * get the return type from the procedure tuple
+	 * get the result type from the procedure tuple, and check for
+	 * polymorphic result type; if so, find out the actual result type.
 	 */
+	rettype = procedureStruct->prorettype;
+
+	if (rettype == ANYARRAYOID || rettype == ANYELEMENTOID)
+	{
+		rettype = get_fn_expr_rettype(finfo);
+		if (rettype == InvalidOid)
+			elog(ERROR, "could not determine actual result type for function declared %s",
+				 format_type_be(procedureStruct->prorettype));
+	}
+
+	/* Now look up the actual result type */
 	typeTuple = SearchSysCache(TYPEOID,
-						   ObjectIdGetDatum(procedureStruct->prorettype),
+							   ObjectIdGetDatum(rettype),
 							   0, 0, 0);
 	if (!HeapTupleIsValid(typeTuple))
 		elog(ERROR, "init_sql_fcache: Cache lookup failed for type %u",
-			 procedureStruct->prorettype);
-
+			 rettype);
 	typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
 
-	fcache = (SQLFunctionCachePtr) palloc0(sizeof(SQLFunctionCache));
-
 	/*
 	 * get the type length and by-value flag from the type tuple
 	 */
 	fcache->typlen = typeStruct->typlen;
 
-	if (typeStruct->typtype != 'c' &&
-		procedureStruct->prorettype != RECORDOID)
+	if (typeStruct->typtype != 'c' && rettype != RECORDOID)
 	{
 		/* The return type is not a composite type, so just use byval */
 		fcache->typbyval = typeStruct->typbyval;
@@ -205,17 +226,35 @@ init_sql_fcache(FmgrInfo *finfo)
 		fcache->funcSlot = NULL;
 
 	/*
-	 * Parse and plan the queries.  We need the argument info to pass
+	 * Parse and plan the queries.  We need the argument type info to pass
 	 * to the parser.
 	 */
 	nargs = procedureStruct->pronargs;
+	haspolyarg = false;
 
 	if (nargs > 0)
 	{
+		int		argnum;
+
 		argOidVect = (Oid *) palloc(nargs * sizeof(Oid));
 		memcpy(argOidVect,
 			   procedureStruct->proargtypes,
 			   nargs * sizeof(Oid));
+		/* Resolve any polymorphic argument types */
+		for (argnum = 0; argnum < nargs; argnum++)
+		{
+			Oid		argtype = argOidVect[argnum];
+
+			if (argtype == ANYARRAYOID || argtype == ANYELEMENTOID)
+			{
+				argtype = get_fn_expr_argtype(finfo, argnum);
+				if (argtype == InvalidOid)
+					elog(ERROR, "could not determine actual type of argument declared %s",
+						 format_type_be(argOidVect[argnum]));
+				argOidVect[argnum] = argtype;
+				haspolyarg = true;
+			}
+		}
 	}
 	else
 		argOidVect = (Oid *) NULL;
@@ -229,7 +268,8 @@ init_sql_fcache(FmgrInfo *finfo)
 			 foid);
 	src = DatumGetCString(DirectFunctionCall1(textout, tmp));
 
-	fcache->func_state = init_execution_state(src, argOidVect, nargs);
+	fcache->func_state = init_execution_state(src, argOidVect, nargs,
+											  rettype, haspolyarg);
 
 	pfree(src);
 
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 54f2d7bd69b2a4c0e330ac539e8e6ce80cd250f7..3da79cc4957cdaafdf05ec361183dc57dc58422e 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.142 2003/06/29 00:33:43 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.143 2003/07/01 00:04:37 tgl Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -1731,6 +1731,7 @@ inline_function(Oid funcid, Oid result_type, List *args,
 	int		   *usecounts;
 	List	   *arg;
 	int			i;
+	int			j;
 
 	/*
 	 * Forget it if the function is not SQL-language or has other
@@ -1742,12 +1743,20 @@ inline_function(Oid funcid, Oid result_type, List *args,
 		funcform->pronargs != length(args))
 		return NULL;
 
-	/* Forget it if declared return type is tuple or void */
+	/* Forget it if declared return type is not base or domain */
 	result_typtype = get_typtype(funcform->prorettype);
 	if (result_typtype != 'b' &&
 		result_typtype != 'd')
 		return NULL;
 
+	/* Forget it if any declared argument type is polymorphic */
+	for (j = 0; j < funcform->pronargs; j++)
+	{
+		if (funcform->proargtypes[j] == ANYARRAYOID ||
+			funcform->proargtypes[j] == ANYELEMENTOID)
+			return NULL;
+	}
+
 	/* Check for recursive function, and give up trying to expand if so */
 	if (oidMember(funcid, active_fns))
 		return NULL;
diff --git a/src/backend/utils/adt/array_userfuncs.c b/src/backend/utils/adt/array_userfuncs.c
index 3aa70b0d3324c87975ec9a8bc311498d148d282e..6c28b211cebb4c801169843f6c86c776fc39731a 100644
--- a/src/backend/utils/adt/array_userfuncs.c
+++ b/src/backend/utils/adt/array_userfuncs.c
@@ -6,7 +6,7 @@
  * Copyright (c) 2003, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/array_userfuncs.c,v 1.4 2003/06/27 00:33:25 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/array_userfuncs.c,v 1.5 2003/07/01 00:04:38 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -37,8 +37,8 @@ array_push(PG_FUNCTION_ARGS)
 	int16		typlen;
 	bool		typbyval;
 	char		typalign;
-	Oid			arg0_typeid = get_fn_expr_argtype(fcinfo, 0);
-	Oid			arg1_typeid = get_fn_expr_argtype(fcinfo, 1);
+	Oid			arg0_typeid = get_fn_expr_argtype(fcinfo->flinfo, 0);
+	Oid			arg1_typeid = get_fn_expr_argtype(fcinfo->flinfo, 1);
 	Oid			arg0_elemid;
 	Oid			arg1_elemid;
 	ArrayMetaState *my_extra;
diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c
index 808353a63d4299344438d083c024f28ef72db0c0..d0a876a877b1fc54bb9fa2bdb5ad8c3559012695 100644
--- a/src/backend/utils/adt/arrayfuncs.c
+++ b/src/backend/utils/adt/arrayfuncs.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.92 2003/06/27 00:33:25 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.93 2003/07/01 00:04:38 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2792,7 +2792,7 @@ array_type_coerce(PG_FUNCTION_ARGS)
 
 	if (my_extra->srctype != src_elem_type)
 	{
-		Oid			tgt_type = get_fn_expr_rettype(fcinfo);
+		Oid			tgt_type = get_fn_expr_rettype(fmgr_info);
 		Oid			tgt_elem_type;
 		Oid			funcId;
 
diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c
index 0d69ac1083e600dcf5c35b24e376ec567ac86678..04e72e53413a46f3e53d3f9223fefce542d4f194 100644
--- a/src/backend/utils/fmgr/fmgr.c
+++ b/src/backend/utils/fmgr/fmgr.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/fmgr/fmgr.c,v 1.71 2003/06/29 00:33:44 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/fmgr/fmgr.c,v 1.72 2003/07/01 00:04:38 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1616,16 +1616,19 @@ pg_detoast_datum_slice(struct varlena * datum, int32 first, int32 count)
 
 /*-------------------------------------------------------------------------
  *		Support routines for extracting info from fn_expr parse tree
+ *
+ * These are needed by polymorphic functions, which accept multiple possible
+ * input types and need help from the parser to know what they've got.
  *-------------------------------------------------------------------------
  */
 
 /*
- * Get the OID of the function return type
+ * Get the actual type OID of the function return type
  *
  * Returns InvalidOid if information is not available
  */
 Oid
-get_fn_expr_rettype(FunctionCallInfo fcinfo)
+get_fn_expr_rettype(FmgrInfo *flinfo)
 {
 	Node   *expr;
 
@@ -1633,21 +1636,21 @@ get_fn_expr_rettype(FunctionCallInfo fcinfo)
 	 * can't return anything useful if we have no FmgrInfo or if
 	 * its fn_expr node has not been initialized
 	 */
-	if (!fcinfo || !fcinfo->flinfo || !fcinfo->flinfo->fn_expr)
+	if (!flinfo || !flinfo->fn_expr)
 		return InvalidOid;
 
-	expr = fcinfo->flinfo->fn_expr;
+	expr = flinfo->fn_expr;
 
 	return exprType(expr);
 }
 
 /*
- * Get the type OID of a specific function argument (counting from 0)
+ * Get the actual type OID of a specific function argument (counting from 0)
  *
  * Returns InvalidOid if information is not available
  */
 Oid
-get_fn_expr_argtype(FunctionCallInfo fcinfo, int argnum)
+get_fn_expr_argtype(FmgrInfo *flinfo, int argnum)
 {
 	Node   *expr;
 	List   *args;
@@ -1657,10 +1660,10 @@ get_fn_expr_argtype(FunctionCallInfo fcinfo, int argnum)
 	 * can't return anything useful if we have no FmgrInfo or if
 	 * its fn_expr node has not been initialized
 	 */
-	if (!fcinfo || !fcinfo->flinfo || !fcinfo->flinfo->fn_expr)
+	if (!flinfo || !flinfo->fn_expr)
 		return InvalidOid;
 
-	expr = fcinfo->flinfo->fn_expr;
+	expr = flinfo->fn_expr;
 
 	if (IsA(expr, FuncExpr))
 		args = ((FuncExpr *) expr)->args;
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 578a6b7d42a639f02263cf3dc45096b99de9d055..b1f16c2d4214b2630297c9d8b3ae0f25802305ea 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.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: pg_proc.h,v 1.308 2003/06/27 00:33:25 tgl Exp $
+ * $Id: pg_proc.h,v 1.309 2003/07/01 00:04:38 tgl Exp $
  *
  * NOTES
  *	  The script catalog/genbki.sh reads this file and generates .bki
@@ -3438,4 +3438,7 @@ extern Oid ProcedureCreate(const char *procedureName,
 				int parameterCount,
 				const Oid *parameterTypes);
 
+extern void check_sql_fn_retval(Oid rettype, char fn_typtype,
+								List *queryTreeList);
+
 #endif   /* PG_PROC_H */
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index 51844eac38bb794a2f6badd70c00b1b7bf707ad0..1cc6ed023e45a8a0fb233f711883c7e267a211bd 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -11,7 +11,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: fmgr.h,v 1.29 2003/06/25 21:30:32 momjian Exp $
+ * $Id: fmgr.h,v 1.30 2003/07/01 00:04:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -378,8 +378,8 @@ extern Datum OidFunctionCall9(Oid functionId, Datum arg1, Datum arg2,
  */
 extern Pg_finfo_record *fetch_finfo_record(void *filehandle, char *funcname);
 extern Oid	fmgr_internal_function(const char *proname);
-extern Oid	get_fn_expr_rettype(FunctionCallInfo fcinfo);
-extern Oid	get_fn_expr_argtype(FunctionCallInfo fcinfo, int argnum);
+extern Oid	get_fn_expr_rettype(FmgrInfo *flinfo);
+extern Oid	get_fn_expr_argtype(FmgrInfo *flinfo, int argnum);
 
 /*
  * Routines in dfmgr.c