diff --git a/src/backend/commands/amcmds.c b/src/backend/commands/amcmds.c
index c84507b5d0..9f2bad2afd 100644
--- a/src/backend/commands/amcmds.c
+++ b/src/backend/commands/amcmds.c
@@ -254,7 +254,7 @@ lookup_index_am_handler_func(List *handler_name, char amtype)
errmsg("handler function is not specified")));
/* handlers have one argument of type internal */
- handlerOid = LookupFuncName(handler_name, 1, funcargtypes, false);
+ handlerOid = LookupFuncName(handler_name, 1, funcargtypes, false, false);
/* check that handler has the correct return type */
switch (amtype)
diff --git a/src/backend/commands/conversioncmds.c b/src/backend/commands/conversioncmds.c
index 5afe86712f..122573464f 100644
--- a/src/backend/commands/conversioncmds.c
+++ b/src/backend/commands/conversioncmds.c
@@ -77,7 +77,7 @@ CreateConversionCommand(CreateConversionStmt *stmt)
* a qualified name.
*/
funcoid = LookupFuncName(func_name, sizeof(funcargs) / sizeof(Oid),
- funcargs, false);
+ funcargs, false, false);
/* Check it returns VOID, else it's probably the wrong function */
if (get_func_rettype(funcoid) != VOIDOID)
diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c
index adb77d8f69..91c1ea08c5 100644
--- a/src/backend/commands/event_trigger.c
+++ b/src/backend/commands/event_trigger.c
@@ -238,7 +238,7 @@ CreateEventTrigger(CreateEventTrigStmt *stmt)
stmt->trigname)));
/* Find and validate the trigger function. */
- funcoid = LookupFuncName(stmt->funcname, 0, fargtypes, false);
+ funcoid = LookupFuncName(stmt->funcname, 0, fargtypes, false, false);
funcrettype = get_func_rettype(funcoid);
if (funcrettype != EVTTRIGGEROID)
ereport(ERROR,
diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c
index 413ce3fcb6..02ed460847 100644
--- a/src/backend/commands/foreigncmds.c
+++ b/src/backend/commands/foreigncmds.c
@@ -484,7 +484,8 @@ lookup_fdw_handler_func(DefElem *handler)
return InvalidOid;
/* handlers have no arguments */
- handlerOid = LookupFuncName((List *) handler->arg, 0, funcargtypes, false);
+ handlerOid = LookupFuncName((List *) handler->arg, 0, funcargtypes, false,
+ false);
/* check that handler has correct return type */
if (get_func_rettype(handlerOid) != FDW_HANDLEROID)
@@ -511,7 +512,8 @@ lookup_fdw_validator_func(DefElem *validator)
funcargtypes[0] = TEXTARRAYOID;
funcargtypes[1] = OIDOID;
- return LookupFuncName((List *) validator->arg, 2, funcargtypes, false);
+ return LookupFuncName((List *) validator->arg, 2, funcargtypes, false,
+ false);
/* validator's return value is ignored, so we don't check the type */
}
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index 4f62e48d98..b7f9b46d4d 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -658,7 +658,7 @@ interpret_func_support(DefElem *defel)
*/
argList[0] = INTERNALOID;
- procOid = LookupFuncName(procName, 1, argList, true);
+ procOid = LookupFuncName(procName, 1, argList, false, true);
if (!OidIsValid(procOid))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_FUNCTION),
diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c
index 7b98e4b910..86a37e18e3 100644
--- a/src/backend/commands/operatorcmds.c
+++ b/src/backend/commands/operatorcmds.c
@@ -208,7 +208,7 @@ DefineOperator(List *names, List *parameters)
typeId[1] = typeId2;
nargs = 2;
}
- functionOid = LookupFuncName(functionName, nargs, typeId, false);
+ functionOid = LookupFuncName(functionName, nargs, typeId, false, false);
/*
* We require EXECUTE rights for the function. This isn't strictly
@@ -271,7 +271,7 @@ ValidateRestrictionEstimator(List *restrictionName)
typeId[2] = INTERNALOID; /* args list */
typeId[3] = INT4OID; /* varRelid */
- restrictionOid = LookupFuncName(restrictionName, 4, typeId, false);
+ restrictionOid = LookupFuncName(restrictionName, 4, typeId, false, false);
/* estimators must return float8 */
if (get_func_rettype(restrictionOid) != FLOAT8OID)
@@ -312,12 +312,12 @@ ValidateJoinEstimator(List *joinName)
* arguments, but we still allow the old 4-argument form. Try the
* preferred form first.
*/
- joinOid = LookupFuncName(joinName, 5, typeId, true);
+ joinOid = LookupFuncName(joinName, 5, typeId, true, false);
if (!OidIsValid(joinOid))
- joinOid = LookupFuncName(joinName, 4, typeId, true);
+ joinOid = LookupFuncName(joinName, 4, typeId, true, false);
/* If not found, reference the 5-argument signature in error msg */
if (!OidIsValid(joinOid))
- joinOid = LookupFuncName(joinName, 5, typeId, false);
+ joinOid = LookupFuncName(joinName, 5, typeId, false, false);
/* estimators must return float8 */
if (get_func_rettype(joinOid) != FLOAT8OID)
diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c
index 59c4e8dfd0..f0d0bc374d 100644
--- a/src/backend/commands/proclang.c
+++ b/src/backend/commands/proclang.c
@@ -106,7 +106,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
* return type.
*/
funcname = SystemFuncName(pltemplate->tmplhandler);
- handlerOid = LookupFuncName(funcname, 0, funcargtypes, true);
+ handlerOid = LookupFuncName(funcname, 0, funcargtypes, true, false);
if (OidIsValid(handlerOid))
{
funcrettype = get_func_rettype(handlerOid);
@@ -155,7 +155,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
{
funcname = SystemFuncName(pltemplate->tmplinline);
funcargtypes[0] = INTERNALOID;
- inlineOid = LookupFuncName(funcname, 1, funcargtypes, true);
+ inlineOid = LookupFuncName(funcname, 1, funcargtypes, true,
+ false);
if (!OidIsValid(inlineOid))
{
tmpAddr = ProcedureCreate(pltemplate->tmplinline,
@@ -198,7 +199,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
{
funcname = SystemFuncName(pltemplate->tmplvalidator);
funcargtypes[0] = OIDOID;
- valOid = LookupFuncName(funcname, 1, funcargtypes, true);
+ valOid = LookupFuncName(funcname, 1, funcargtypes, true, false);
if (!OidIsValid(valOid))
{
tmpAddr = ProcedureCreate(pltemplate->tmplvalidator,
@@ -264,7 +265,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
* Lookup the PL handler function and check that it is of the expected
* return type
*/
- handlerOid = LookupFuncName(stmt->plhandler, 0, funcargtypes, false);
+ handlerOid = LookupFuncName(stmt->plhandler, 0, funcargtypes, false,
+ false);
funcrettype = get_func_rettype(handlerOid);
if (funcrettype != LANGUAGE_HANDLEROID)
{
@@ -293,7 +295,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
if (stmt->plinline)
{
funcargtypes[0] = INTERNALOID;
- inlineOid = LookupFuncName(stmt->plinline, 1, funcargtypes, false);
+ inlineOid = LookupFuncName(stmt->plinline, 1, funcargtypes, false,
+ false);
/* return value is ignored, so we don't check the type */
}
else
@@ -303,7 +306,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
if (stmt->plvalidator)
{
funcargtypes[0] = OIDOID;
- valOid = LookupFuncName(stmt->plvalidator, 1, funcargtypes, false);
+ valOid = LookupFuncName(stmt->plvalidator, 1, funcargtypes, false,
+ false);
/* return value is ignored, so we don't check the type */
}
else
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 0b245a613e..d6fcac7bdb 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -667,7 +667,7 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
* Find and validate the trigger function.
*/
if (!OidIsValid(funcoid))
- funcoid = LookupFuncName(stmt->funcname, 0, fargtypes, false);
+ funcoid = LookupFuncName(stmt->funcname, 0, fargtypes, false, false);
if (!isInternal)
{
aclresult = pg_proc_aclcheck(funcoid, GetUserId(), ACL_EXECUTE);
diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c
index 8e5eec22b5..7c1c7deb50 100644
--- a/src/backend/commands/tsearchcmds.c
+++ b/src/backend/commands/tsearchcmds.c
@@ -108,7 +108,7 @@ get_ts_parser_func(DefElem *defel, int attnum)
nargs = 0; /* keep compiler quiet */
}
- procOid = LookupFuncName(funcName, nargs, typeId, false);
+ procOid = LookupFuncName(funcName, nargs, typeId, false, false);
if (get_func_rettype(procOid) != retTypeId)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
@@ -679,7 +679,7 @@ get_ts_template_func(DefElem *defel, int attnum)
nargs = 0; /* keep compiler quiet */
}
- procOid = LookupFuncName(funcName, nargs, typeId, false);
+ procOid = LookupFuncName(funcName, nargs, typeId, false, false);
if (get_func_rettype(procOid) != retTypeId)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 448926db12..46a1270470 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -1700,28 +1700,28 @@ findTypeInputFunction(List *procname, Oid typeOid)
*/
argList[0] = CSTRINGOID;
- procOid = LookupFuncName(procname, 1, argList, true);
+ procOid = LookupFuncName(procname, 1, argList, true, false);
if (OidIsValid(procOid))
return procOid;
argList[1] = OIDOID;
argList[2] = INT4OID;
- procOid = LookupFuncName(procname, 3, argList, true);
+ procOid = LookupFuncName(procname, 3, argList, true, false);
if (OidIsValid(procOid))
return procOid;
/* No luck, try it with OPAQUE */
argList[0] = OPAQUEOID;
- procOid = LookupFuncName(procname, 1, argList, true);
+ procOid = LookupFuncName(procname, 1, argList, true, false);
if (!OidIsValid(procOid))
{
argList[1] = OIDOID;
argList[2] = INT4OID;
- procOid = LookupFuncName(procname, 3, argList, true);
+ procOid = LookupFuncName(procname, 3, argList, true, false);
}
if (OidIsValid(procOid))
@@ -1766,14 +1766,14 @@ findTypeOutputFunction(List *procname, Oid typeOid)
*/
argList[0] = typeOid;
- procOid = LookupFuncName(procname, 1, argList, true);
+ procOid = LookupFuncName(procname, 1, argList, true, false);
if (OidIsValid(procOid))
return procOid;
/* No luck, try it with OPAQUE */
argList[0] = OPAQUEOID;
- procOid = LookupFuncName(procname, 1, argList, true);
+ procOid = LookupFuncName(procname, 1, argList, true, false);
if (OidIsValid(procOid))
{
@@ -1815,14 +1815,14 @@ findTypeReceiveFunction(List *procname, Oid typeOid)
*/
argList[0] = INTERNALOID;
- procOid = LookupFuncName(procname, 1, argList, true);
+ procOid = LookupFuncName(procname, 1, argList, true, false);
if (OidIsValid(procOid))
return procOid;
argList[1] = OIDOID;
argList[2] = INT4OID;
- procOid = LookupFuncName(procname, 3, argList, true);
+ procOid = LookupFuncName(procname, 3, argList, true, false);
if (OidIsValid(procOid))
return procOid;
@@ -1845,7 +1845,7 @@ findTypeSendFunction(List *procname, Oid typeOid)
*/
argList[0] = typeOid;
- procOid = LookupFuncName(procname, 1, argList, true);
+ procOid = LookupFuncName(procname, 1, argList, true, false);
if (OidIsValid(procOid))
return procOid;
@@ -1868,7 +1868,7 @@ findTypeTypmodinFunction(List *procname)
*/
argList[0] = CSTRINGARRAYOID;
- procOid = LookupFuncName(procname, 1, argList, true);
+ procOid = LookupFuncName(procname, 1, argList, true, false);
if (!OidIsValid(procOid))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_FUNCTION),
@@ -1895,7 +1895,7 @@ findTypeTypmodoutFunction(List *procname)
*/
argList[0] = INT4OID;
- procOid = LookupFuncName(procname, 1, argList, true);
+ procOid = LookupFuncName(procname, 1, argList, true, false);
if (!OidIsValid(procOid))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_FUNCTION),
@@ -1922,7 +1922,7 @@ findTypeAnalyzeFunction(List *procname, Oid typeOid)
*/
argList[0] = INTERNALOID;
- procOid = LookupFuncName(procname, 1, argList, true);
+ procOid = LookupFuncName(procname, 1, argList, true, false);
if (!OidIsValid(procOid))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_FUNCTION),
@@ -1998,7 +1998,7 @@ findRangeCanonicalFunction(List *procname, Oid typeOid)
*/
argList[0] = typeOid;
- procOid = LookupFuncName(procname, 1, argList, true);
+ procOid = LookupFuncName(procname, 1, argList, true, false);
if (!OidIsValid(procOid))
ereport(ERROR,
@@ -2040,7 +2040,7 @@ findRangeSubtypeDiffFunction(List *procname, Oid subtype)
argList[0] = subtype;
argList[1] = subtype;
- procOid = LookupFuncName(procname, 2, argList, true);
+ procOid = LookupFuncName(procname, 2, argList, true, false);
if (!OidIsValid(procOid))
ereport(ERROR,
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index c6ce1011e2..e5cc88b245 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -933,7 +933,7 @@ transformRangeTableSample(ParseState *pstate, RangeTableSample *rts)
*/
funcargtypes[0] = INTERNALOID;
- handlerOid = LookupFuncName(rts->method, 1, funcargtypes, true);
+ handlerOid = LookupFuncName(rts->method, 1, funcargtypes, true, false);
/* we want error to complain about no-such-method, not no-such-function */
if (!OidIsValid(handlerOid))
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index 5222231b51..c2c7a9cacb 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -2032,17 +2032,21 @@ func_signature_string(List *funcname, int nargs,
* namespace search path.
*
* If the function is not found, we return InvalidOid if noError is true,
- * else raise an error.
+ * else raise an error. missing_ok is similar to noError except we still
+ * raise an error for an ambigious function, regardless of what missing_ok is
+ * set to.
*/
Oid
-LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError)
+LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError,
+ bool missing_ok)
{
FuncCandidateList clist;
/* Passing NULL for argtypes is no longer allowed */
Assert(argtypes);
- clist = FuncnameGetCandidates(funcname, nargs, NIL, false, false, noError);
+ clist = FuncnameGetCandidates(funcname, nargs, NIL, false, false,
+ noError || missing_ok);
/*
* If no arguments were specified, the name must yield a unique candidate.
@@ -2065,7 +2069,7 @@ LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError)
}
else
{
- if (!noError)
+ if (!noError && !missing_ok)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_FUNCTION),
errmsg("could not find a function named \"%s\"",
@@ -2080,7 +2084,7 @@ LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError)
clist = clist->next;
}
- if (!noError)
+ if (!noError && !missing_ok)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_FUNCTION),
errmsg("function %s does not exist",
@@ -2135,10 +2139,11 @@ 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.
+ * LookupFuncName's missing_ok parameter and let it make any error
+ * messages. Otherwise, we make our own errors for the aggregate and
+ * procedure cases.
*/
- oid = LookupFuncName(func->objname, func->args_unspecified ? -1 : argcount, argoids,
+ oid = LookupFuncName(func->objname, func->args_unspecified ? -1 : argcount, argoids, false,
(objtype == OBJECT_FUNCTION || objtype == OBJECT_ROUTINE) ? noError : true);
if (objtype == OBJECT_FUNCTION)
diff --git a/src/include/parser/parse_func.h b/src/include/parser/parse_func.h
index ff1477e64f..4e8f7af0f3 100644
--- a/src/include/parser/parse_func.h
+++ b/src/include/parser/parse_func.h
@@ -63,7 +63,7 @@ extern const char *func_signature_string(List *funcname, int nargs,
List *argnames, const Oid *argtypes);
extern Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes,
- bool noError);
+ bool noError, bool missing_ok);
extern Oid LookupFuncWithArgs(ObjectType objtype, ObjectWithArgs *func,
bool noError);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index bfbf62305c..05a4b2af16 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -616,7 +616,7 @@ call_pltcl_start_proc(Oid prolang, bool pltrusted)
/* Parse possibly-qualified identifier and look up the function */
namelist = stringToQualifiedNameList(start_proc);
- procOid = LookupFuncName(namelist, 0, fargtypes, false);
+ procOid = LookupFuncName(namelist, 0, fargtypes, false, false);
/* Current user must have permission to call function */
aclresult = pg_proc_aclcheck(procOid, GetUserId(), ACL_EXECUTE);
diff --git a/src/test/regress/expected/drop_if_exists.out b/src/test/regress/expected/drop_if_exists.out
index b80c5ed2d8..dd4e6c0f6d 100644
--- a/src/test/regress/expected/drop_if_exists.out
+++ b/src/test/regress/expected/drop_if_exists.out
@@ -138,6 +138,16 @@ 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);
-- 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..ad4ef76460 100644
--- a/src/test/regress/sql/drop_if_exists.sql
+++ b/src/test/regress/sql/drop_if_exists.sql
@@ -153,6 +153,16 @@ 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);
+
-- aggregate
DROP AGGREGATE test_aggregate_exists(*);
DROP AGGREGATE IF EXISTS test_aggregate_exists(*);