diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index 654ee80b27..86b0d9fba7 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -34,6 +34,11 @@
 #include "utils/lsyscache.h"
 #include "utils/syscache.h"
 
+typedef enum
+{
+	FUNCLOOKUP_NOSUCHFUNC,
+	FUNCLOOKUP_AMBIGUOUS
+} FuncLookupError;
 
 static void unify_hypothetical_args(ParseState *pstate,
 						List *fargs, int numAggregatedArgs,
@@ -41,6 +46,9 @@ static void unify_hypothetical_args(ParseState *pstate,
 static Oid	FuncNameAsType(List *funcname);
 static Node *ParseComplexProjection(ParseState *pstate, const char *funcname,
 					   Node *first_arg, int location);
+static Oid LookupFuncNameInternal(List *funcname, int nargs,
+					   const Oid *argtypes,
+					   bool noError, FuncLookupError *lookupError);
 
 
 /*
@@ -2022,20 +2030,19 @@ func_signature_string(List *funcname, int nargs,
 }
 
 /*
- * LookupFuncName
- *
- * Given a possibly-qualified function name and optionally a set of argument
- * types, look up the function.  Pass nargs == -1 to indicate that no argument
- * types are specified.
+ * LookupFuncNameInternal
+ *		Lookup a function Oid from its name and arguments.
  *
- * If the function name is not schema-qualified, it is sought in the current
- * namespace search path.
+ * In an error situation, e.g. can't find the function then we return
+ * InvalidOid and set *lookupError to indicate what went wrong.
  *
- * If the function is not found, we return InvalidOid if noError is true,
- * else raise an error.
+ * Possible Errors:
+ *	FUNCLOOKUP_NOSUCHFUNC -- When we can't find a function of this name.
+ *	FUNCLOOKUP_AMBIGUOUS -- When nargs == -1 and more than one func matches.
  */
-Oid
-LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError)
+static Oid
+LookupFuncNameInternal(List *funcname, int nargs, const Oid *argtypes,
+					   bool noError, FuncLookupError *lookupError)
 {
 	FuncCandidateList clist;
 
@@ -2051,25 +2058,20 @@ LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError)
 	{
 		if (clist)
 		{
+			/* If there is another match then it's an ambiguous error */
 			if (clist->next)
 			{
-				if (!noError)
-					ereport(ERROR,
-							(errcode(ERRCODE_AMBIGUOUS_FUNCTION),
-							 errmsg("function name \"%s\" is not unique",
-									NameListToString(funcname)),
-							 errhint("Specify the argument list to select the function unambiguously.")));
+				*lookupError = FUNCLOOKUP_AMBIGUOUS;
+				return InvalidOid;
 			}
+			/* Otherwise return the match */
 			else
 				return clist->oid;
 		}
 		else
 		{
-			if (!noError)
-				ereport(ERROR,
-						(errcode(ERRCODE_UNDEFINED_FUNCTION),
-						 errmsg("could not find a function named \"%s\"",
-								NameListToString(funcname))));
+			*lookupError = FUNCLOOKUP_NOSUCHFUNC;
+			return InvalidOid;
 		}
 	}
 
@@ -2080,16 +2082,75 @@ LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError)
 		clist = clist->next;
 	}
 
-	if (!noError)
-		ereport(ERROR,
-				(errcode(ERRCODE_UNDEFINED_FUNCTION),
-				 errmsg("function %s does not exist",
-						func_signature_string(funcname, nargs,
-											  NIL, argtypes))));
-
+	*lookupError = FUNCLOOKUP_NOSUCHFUNC;
 	return InvalidOid;
 }
 
+/*
+ * LookupFuncName
+ *
+ * Given a possibly-qualified function name and optionally a set of argument
+ * types, look up the function.  Pass nargs == -1 to indicate that no argument
+ * types are specified.
+ *
+ * If the function name is not schema-qualified, it is sought in the current
+ * namespace search path.
+ *
+ * If the function is not found, we return InvalidOid if noError is true,
+ * else raise an error.
+ *
+ * If nargs == -1 and multiple functions are found matching this function name
+ * then we raise an ambiguous function error regardless of what noError is set
+ * to.
+ */
+Oid
+LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError)
+{
+	FuncLookupError lookupError;
+	Oid		funcoid;
+
+	funcoid = LookupFuncNameInternal(funcname, nargs, argtypes, noError,
+									 &lookupError);
+
+	if (OidIsValid(funcoid))
+		return funcoid;
+
+	switch (lookupError)
+	{
+		case FUNCLOOKUP_AMBIGUOUS:
+			/*
+			 * Raise an error regardless of if noError is set if there are
+			 * multiple matching functions.
+			 */
+			ereport(ERROR,
+				(errcode(ERRCODE_AMBIGUOUS_FUNCTION),
+					errmsg("function name \"%s\" is not unique",
+						NameListToString(funcname)),
+					errhint("Specify the argument list to select the function unambiguously.")));
+			break;
+
+		case FUNCLOOKUP_NOSUCHFUNC:
+			/* Let the caller deal with it when noError is true */
+			if (noError)
+				return InvalidOid;
+
+			if (nargs == -1)
+				ereport(ERROR,
+						(errcode(ERRCODE_UNDEFINED_FUNCTION),
+						errmsg("could not find a function named \"%s\"",
+							   NameListToString(funcname))));
+			else
+				ereport(ERROR,
+						(errcode(ERRCODE_UNDEFINED_FUNCTION),
+						errmsg("function %s does not exist",
+							   func_signature_string(funcname, nargs,
+													 NIL, argtypes))));
+			break;
+	}
+
+	return InvalidOid;		/* Keep compiler quiet */
+}
+
 /*
  * LookupFuncWithArgs
  *
@@ -2104,8 +2165,10 @@ LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError)
 Oid
 LookupFuncWithArgs(ObjectType objtype, ObjectWithArgs *func, bool noError)
 {
+	FuncLookupError lookupError;
 	Oid			argoids[FUNC_MAX_ARGS];
 	int			argcount;
+	int			nargs;
 	int			i;
 	ListCell   *args_item;
 	Oid			oid;
@@ -2117,12 +2180,22 @@ LookupFuncWithArgs(ObjectType objtype, ObjectWithArgs *func, bool noError)
 
 	argcount = list_length(func->objargs);
 	if (argcount > FUNC_MAX_ARGS)
-		ereport(ERROR,
+	{
+		if (objtype == OBJECT_PROCEDURE)
+			ereport(ERROR,
+					(errcode(ERRCODE_TOO_MANY_ARGUMENTS),
+					 errmsg_plural("procedure cannot have more than %d argument",
+								   "procedure cannot have more than %d arguments",
+								   FUNC_MAX_ARGS,
+								   FUNC_MAX_ARGS)));
+		else
+			ereport(ERROR,
 				(errcode(ERRCODE_TOO_MANY_ARGUMENTS),
 				 errmsg_plural("functions cannot have more than %d argument",
 							   "functions cannot have more than %d arguments",
 							   FUNC_MAX_ARGS,
 							   FUNC_MAX_ARGS)));
+	}
 
 	i = 0;
 	foreach(args_item, func->objargs)
@@ -2133,97 +2206,156 @@ LookupFuncWithArgs(ObjectType objtype, ObjectWithArgs *func, bool noError)
 	}
 
 	/*
-	 * When looking for a function or routine, we pass noError through to
-	 * LookupFuncName and let it make any error messages.  Otherwise, we make
-	 * our own errors for the aggregate and procedure cases.
+	 * Set nargs for the LookupFuncName call. It expects -1 to mean no args
+	 * were specified.
 	 */
-	oid = LookupFuncName(func->objname, func->args_unspecified ? -1 : argcount, argoids,
-						 (objtype == OBJECT_FUNCTION || objtype == OBJECT_ROUTINE) ? noError : true);
+	nargs = func->args_unspecified ? -1 : argcount;
 
-	if (objtype == OBJECT_FUNCTION)
-	{
-		/* Make sure it's a function, not a procedure */
-		if (oid && get_func_prokind(oid) == PROKIND_PROCEDURE)
-		{
-			if (noError)
-				return InvalidOid;
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("%s is not a function",
-							func_signature_string(func->objname, argcount,
-												  NIL, argoids))));
-		}
-	}
-	else if (objtype == OBJECT_PROCEDURE)
+	oid = LookupFuncNameInternal(func->objname, nargs, argoids, noError,
+								 &lookupError);
+
+	if (OidIsValid(oid))
 	{
-		if (!OidIsValid(oid))
+		/*
+		 * Even if we found the function, perform validation that the objtype
+		 * matches the prokind of the found function.  For historical reasons
+		 * we allow the objtype of FUNCTION to mean other things, but we draw
+		 * the line if the object is a procedure.  This is a new enough
+		 * feature that this historical rule does not apply.
+		 */
+		switch (objtype)
 		{
-			if (noError)
-				return InvalidOid;
-			else if (func->args_unspecified)
-				ereport(ERROR,
-						(errcode(ERRCODE_UNDEFINED_FUNCTION),
-						 errmsg("could not find a procedure named \"%s\"",
-								NameListToString(func->objname))));
-			else
-				ereport(ERROR,
-						(errcode(ERRCODE_UNDEFINED_FUNCTION),
-						 errmsg("procedure %s does not exist",
-								func_signature_string(func->objname, argcount,
-													  NIL, argoids))));
-		}
+			case OBJECT_FUNCTION:
+				/* Only complain if it's a procedure. */
+				if (get_func_prokind(oid) == PROKIND_PROCEDURE)
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+									 errmsg("%s is not a function",
+											func_signature_string(func->objname, argcount,
+																  NIL, argoids))));
+				break;
 
-		/* Make sure it's a procedure */
-		if (get_func_prokind(oid) != PROKIND_PROCEDURE)
-		{
-			if (noError)
-				return InvalidOid;
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("%s is not a procedure",
-							func_signature_string(func->objname, argcount,
-												  NIL, argoids))));
+			case OBJECT_PROCEDURE:
+				/* Reject found object is not a procedure */
+				if (get_func_prokind(oid) != PROKIND_PROCEDURE)
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+									 errmsg("%s is not a procedure",
+											func_signature_string(func->objname, argcount,
+																  NIL, argoids))));
+				break;
+
+			case OBJECT_AGGREGATE:
+				/* Reject found object is not an aggregate */
+				if (get_func_prokind(oid) != PROKIND_AGGREGATE)
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+									 errmsg("function %s is not an aggregate",
+											func_signature_string(func->objname, argcount,
+																  NIL, argoids))));
+				break;
+
+			default:
+				/* Don't complain for routines */
+				break;
 		}
+
+		return oid;		/* All good */
 	}
-	else if (objtype == OBJECT_AGGREGATE)
+
+	/* Deal with cases where the lookup failed */
+	else
 	{
-		if (!OidIsValid(oid))
+		switch (lookupError)
 		{
-			if (noError)
+			case FUNCLOOKUP_AMBIGUOUS:
+				switch (objtype)
+				{
+					case OBJECT_FUNCTION:
+						ereport(ERROR,
+							(errcode(ERRCODE_AMBIGUOUS_FUNCTION),
+								errmsg("function name \"%s\" is not unique",
+									NameListToString(func->objname)),
+								errhint("Specify the argument list to select the function unambiguously.")));
+						break;
+					case OBJECT_PROCEDURE:
+						ereport(ERROR,
+							(errcode(ERRCODE_AMBIGUOUS_FUNCTION),
+								errmsg("procedure name \"%s\" is not unique",
+									NameListToString(func->objname)),
+								errhint("Specify the argument list to select the procedure unambiguously.")));
+						break;
+					case OBJECT_AGGREGATE:
+						ereport(ERROR,
+							(errcode(ERRCODE_AMBIGUOUS_FUNCTION),
+								errmsg("aggregate name \"%s\" is not unique",
+									NameListToString(func->objname)),
+								errhint("Specify the argument list to select the aggregate unambiguously.")));
+						break;
+					default:
+						break;
+				}
 				return InvalidOid;
-			else if (func->args_unspecified)
-				ereport(ERROR,
-						(errcode(ERRCODE_UNDEFINED_FUNCTION),
-						 errmsg("could not find an aggregate named \"%s\"",
-								NameListToString(func->objname))));
-			else if (argcount == 0)
-				ereport(ERROR,
-						(errcode(ERRCODE_UNDEFINED_FUNCTION),
-						 errmsg("aggregate %s(*) does not exist",
-								NameListToString(func->objname))));
-			else
-				ereport(ERROR,
-						(errcode(ERRCODE_UNDEFINED_FUNCTION),
-						 errmsg("aggregate %s does not exist",
-								func_signature_string(func->objname, argcount,
-													  NIL, argoids))));
-		}
 
-		/* Make sure it's an aggregate */
-		if (get_func_prokind(oid) != PROKIND_AGGREGATE)
-		{
-			if (noError)
-				return InvalidOid;
-			/* we do not use the (*) notation for functions... */
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("function %s is not an aggregate",
-							func_signature_string(func->objname, argcount,
-												  NIL, argoids))));
+			case FUNCLOOKUP_NOSUCHFUNC:
+
+				/* Suppress no such func errors when noError is true */
+				if (noError)
+					break;
+
+				switch (objtype)
+				{
+					case OBJECT_PROCEDURE:
+						if (func->args_unspecified)
+							ereport(ERROR,
+									(errcode(ERRCODE_UNDEFINED_FUNCTION),
+									 errmsg("could not find a procedure named \"%s\"",
+											NameListToString(func->objname))));
+						else
+							ereport(ERROR,
+									(errcode(ERRCODE_UNDEFINED_FUNCTION),
+									 errmsg("procedure %s does not exist",
+											func_signature_string(func->objname, argcount,
+																  NIL, argoids))));
+						break;
+
+					case OBJECT_AGGREGATE:
+						if (func->args_unspecified)
+							ereport(ERROR,
+									(errcode(ERRCODE_UNDEFINED_FUNCTION),
+									 errmsg("could not find an aggregate named \"%s\"",
+											NameListToString(func->objname))));
+						else if (argcount == 0)
+							ereport(ERROR,
+									(errcode(ERRCODE_UNDEFINED_FUNCTION),
+									 errmsg("aggregate %s(*) does not exist",
+											NameListToString(func->objname))));
+						else
+							ereport(ERROR,
+									(errcode(ERRCODE_UNDEFINED_FUNCTION),
+									 errmsg("aggregate %s does not exist",
+											func_signature_string(func->objname, argcount,
+																  NIL, argoids))));
+						break;
+
+					default:
+						/* FUNCTION and ROUTINE */
+						if (func->args_unspecified)
+							ereport(ERROR,
+									(errcode(ERRCODE_UNDEFINED_FUNCTION),
+									 errmsg("could not find a function named \"%s\"",
+											NameListToString(func->objname))));
+						else
+							ereport(ERROR,
+									(errcode(ERRCODE_UNDEFINED_FUNCTION),
+									 errmsg("function %s does not exist",
+											func_signature_string(func->objname, argcount,
+																  NIL, argoids))));
+						break;
+				}
 		}
+		return InvalidOid;
 	}
-
-	return oid;
 }
 
 /*
diff --git a/src/test/regress/expected/drop_if_exists.out b/src/test/regress/expected/drop_if_exists.out
index b80c5ed2d8..5290b1ca7d 100644
--- a/src/test/regress/expected/drop_if_exists.out
+++ b/src/test/regress/expected/drop_if_exists.out
@@ -138,6 +138,27 @@ DROP FUNCTION test_function_exists(int, text, int[]);
 ERROR:  function test_function_exists(integer, text, integer[]) does not exist
 DROP FUNCTION IF EXISTS test_function_exists(int, text, int[]);
 NOTICE:  function test_function_exists(pg_catalog.int4,text,pg_catalog.int4[]) does not exist, skipping
+-- Ensure we still receive an ambiguous function error when there are
+-- multiple matching functions.
+CREATE FUNCTION test_ambiguous_funcname(int) returns int as $$ select $1; $$ language sql;
+CREATE FUNCTION test_ambiguous_funcname(text) returns text as $$ select $1; $$ language sql;
+DROP FUNCTION IF EXISTS test_ambiguous_funcname;
+ERROR:  function name "test_ambiguous_funcname" is not unique
+HINT:  Specify the argument list to select the function unambiguously.
+-- cleanup
+DROP FUNCTION test_ambiguous_funcname(int);
+DROP FUNCTION test_ambiguous_funcname(text);
+-- Ensure we get an ambiguous function error for procedures too.
+CREATE PROCEDURE test_ambiguous_procname(int) as $$ begin end; $$ language plpgsql;
+CREATE PROCEDURE test_ambiguous_procname(text) as $$ begin end; $$ language plpgsql;
+DROP PROCEDURE IF EXISTS test_ambiguous_procname;
+ERROR:  procedure name "test_ambiguous_procname" is not unique
+HINT:  Specify the argument list to select the procedure unambiguously.
+-- cleanup
+DROP FUNCTION test_ambiguous_procname(int);
+ERROR:  test_ambiguous_procname(integer) is not a function
+DROP FUNCTION test_ambiguous_procname(text);
+ERROR:  test_ambiguous_procname(text) is not a function
 -- aggregate
 DROP AGGREGATE test_aggregate_exists(*);
 ERROR:  aggregate test_aggregate_exists(*) does not exist
diff --git a/src/test/regress/sql/drop_if_exists.sql b/src/test/regress/sql/drop_if_exists.sql
index c1d30bc4a5..138a713b9e 100644
--- a/src/test/regress/sql/drop_if_exists.sql
+++ b/src/test/regress/sql/drop_if_exists.sql
@@ -153,6 +153,25 @@ DROP FUNCTION IF EXISTS test_function_exists();
 DROP FUNCTION test_function_exists(int, text, int[]);
 DROP FUNCTION IF EXISTS test_function_exists(int, text, int[]);
 
+-- Ensure we still receive an ambiguous function error when there are
+-- multiple matching functions.
+CREATE FUNCTION test_ambiguous_funcname(int) returns int as $$ select $1; $$ language sql;
+CREATE FUNCTION test_ambiguous_funcname(text) returns text as $$ select $1; $$ language sql;
+DROP FUNCTION IF EXISTS test_ambiguous_funcname;
+
+-- cleanup
+DROP FUNCTION test_ambiguous_funcname(int);
+DROP FUNCTION test_ambiguous_funcname(text);
+
+-- Ensure we get an ambiguous function error for procedures too.
+CREATE PROCEDURE test_ambiguous_procname(int) as $$ begin end; $$ language plpgsql;
+CREATE PROCEDURE test_ambiguous_procname(text) as $$ begin end; $$ language plpgsql;
+DROP PROCEDURE IF EXISTS test_ambiguous_procname;
+
+-- cleanup
+DROP FUNCTION test_ambiguous_procname(int);
+DROP FUNCTION test_ambiguous_procname(text);
+
 -- aggregate
 DROP AGGREGATE test_aggregate_exists(*);
 DROP AGGREGATE IF EXISTS test_aggregate_exists(*);
