diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index 78b8367d2893..0436b12b8566 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -4609,11 +4609,13 @@ SELECT * FROM ft1 WHERE 'foo' = c8 LIMIT 1;
-- with that remote type
SELECT * FROM ft1 WHERE c8 LIKE 'foo' LIMIT 1; -- ERROR
ERROR: operator does not exist: public.user_enum ~~ unknown
-HINT: No operator matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No operator of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
CONTEXT: remote SQL command: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE ((c8 ~~ 'foo')) LIMIT 1::bigint
SELECT * FROM ft1 WHERE c8::text LIKE 'foo' LIMIT 1; -- ERROR; cast not pushed down
ERROR: operator does not exist: public.user_enum ~~ unknown
-HINT: No operator matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No operator of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
CONTEXT: remote SQL command: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE ((c8 ~~ 'foo')) LIMIT 1::bigint
ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE user_enum;
-- ===================================================================
diff --git a/doc/src/sgml/sources.sgml b/doc/src/sgml/sources.sgml
index 261f19b3534b..760f9b69d477 100644
--- a/doc/src/sgml/sources.sgml
+++ b/doc/src/sgml/sources.sgml
@@ -153,11 +153,12 @@ ereport(ERROR,
errmsg("function %s is not unique",
func_signature_string(funcname, nargs,
NIL, actual_arg_types)),
- errhint("Unable to choose a best candidate function. "
- "You might need to add explicit typecasts."));
+ errdetail("Could not choose a best candidate function."),
+ errhint("You might need to add explicit type casts."));
This illustrates the use of format codes to embed run-time values into
- a message text. Also, an optional hint
message is provided.
+ a message text. Also, optional detail
+ and hint
messages are provided.
The auxiliary function calls can be written in any order, but
conventionally errcode
and errmsg appear first.
diff --git a/doc/src/sgml/typeconv.sgml b/doc/src/sgml/typeconv.sgml
index 287487424866..1707bd884dcf 100644
--- a/doc/src/sgml/typeconv.sgml
+++ b/doc/src/sgml/typeconv.sgml
@@ -465,9 +465,9 @@ try a similar case with ~, we get:
SELECT ~ '20' AS "negation";
-ERROR: operator is not unique: ~ "unknown"
-HINT: Could not choose a best candidate operator. You might need to add
-explicit type casts.
+ERROR: operator is not unique: ~ unknown
+DETAIL: Could not choose a best candidate operator.
+HINT: You might need to add explicit type casts.
This happens because the system cannot decide which of the several
possible ~ operators should be preferred. We can help
@@ -901,8 +901,8 @@ the parser will try to convert that to text:
SELECT substr(1234, 3);
ERROR: function substr(integer, integer) does not exist
-HINT: No function matches the given name and argument types. You might need
-to add explicit type casts.
+DETAIL: No function of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
This does not work because integer does not have an implicit cast
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index 8bd4d6c3d434..ed9aeee24bcb 100644
--- a/src/backend/catalog/namespace.c
+++ b/src/backend/catalog/namespace.c
@@ -232,7 +232,7 @@ static void RemoveTempRelationsCallback(int code, Datum arg);
static void InvalidationCallback(Datum arg, int cacheid, uint32 hashvalue);
static bool MatchNamedCall(HeapTuple proctup, int nargs, List *argnames,
bool include_out_arguments, int pronargs,
- int **argnumbers);
+ int **argnumbers, int *fgc_flags);
/*
* Recomputing the namespace path can be costly when done frequently, such as
@@ -1117,15 +1117,15 @@ TypeIsVisibleExt(Oid typid, bool *is_missing)
/*
* FuncnameGetCandidates
- * Given a possibly-qualified function name and argument count,
+ * Given a possibly-qualified routine name, argument count, and arg names,
* retrieve a list of the possible matches.
*
- * If nargs is -1, we return all functions matching the given name,
+ * If nargs is -1, we return all routines matching the given name,
* regardless of argument count. (argnames must be NIL, and expand_variadic
* and expand_defaults must be false, in this case.)
*
* If argnames isn't NIL, we are considering a named- or mixed-notation call,
- * and only functions having all the listed argument names will be returned.
+ * and only routines having all the listed argument names will be returned.
* (We assume that length(argnames) <= nargs and all the passed-in names are
* distinct.) The returned structs will include an argnumbers array showing
* the actual argument index for each logical argument position.
@@ -1183,14 +1183,21 @@ TypeIsVisibleExt(Oid typid, bool *is_missing)
* The caller might end up discarding such an entry anyway, but if it selects
* such an entry it should react as though the call were ambiguous.
*
- * If missing_ok is true, an empty list (NULL) is returned if the name was
- * schema-qualified with a schema that does not exist. Likewise if no
- * candidate is found for other reasons.
+ * We return an empty list (NULL) if no suitable matches can be found.
+ * If the function name was schema-qualified with a schema that does not
+ * exist, then we return an empty list if missing_ok is true and otherwise
+ * throw an error. (missing_ok does not affect the behavior otherwise.)
+ *
+ * The output argument *fgc_flags is filled with a bitmask indicating how
+ * far we were able to match the supplied information. This is not of much
+ * interest if any candidates were found, but if not, it can help callers
+ * produce an on-point error message.
*/
FuncCandidateList
FuncnameGetCandidates(List *names, int nargs, List *argnames,
bool expand_variadic, bool expand_defaults,
- bool include_out_arguments, bool missing_ok)
+ bool include_out_arguments, bool missing_ok,
+ int *fgc_flags)
{
FuncCandidateList resultList = NULL;
bool any_special = false;
@@ -1203,15 +1210,20 @@ FuncnameGetCandidates(List *names, int nargs, List *argnames,
/* check for caller error */
Assert(nargs >= 0 || !(expand_variadic | expand_defaults));
+ /* initialize output fgc_flags to empty */
+ *fgc_flags = 0;
+
/* deconstruct the name list */
DeconstructQualifiedName(names, &schemaname, &funcname);
if (schemaname)
{
/* use exact schema given */
+ *fgc_flags |= FGC_SCHEMA_GIVEN; /* report that a schema is given */
namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
if (!OidIsValid(namespaceId))
return NULL;
+ *fgc_flags |= FGC_SCHEMA_EXISTS; /* report that the schema exists */
}
else
{
@@ -1237,6 +1249,8 @@ FuncnameGetCandidates(List *names, int nargs, List *argnames,
int *argnumbers = NULL;
FuncCandidateList newResult;
+ *fgc_flags |= FGC_NAME_EXISTS; /* the name is present in pg_proc */
+
if (OidIsValid(namespaceId))
{
/* Consider only procs in specified namespace */
@@ -1262,6 +1276,8 @@ FuncnameGetCandidates(List *names, int nargs, List *argnames,
continue; /* proc is not in search path */
}
+ *fgc_flags |= FGC_NAME_VISIBLE; /* routine is in the right schema */
+
/*
* If we are asked to match to OUT arguments, then use the
* proallargtypes array (which includes those); otherwise use
@@ -1296,16 +1312,6 @@ FuncnameGetCandidates(List *names, int nargs, List *argnames,
/*
* Call uses named or mixed notation
*
- * Named or mixed notation can match a variadic function only if
- * expand_variadic is off; otherwise there is no way to match the
- * presumed-nameless parameters expanded from the variadic array.
- */
- if (OidIsValid(procform->provariadic) && expand_variadic)
- continue;
- va_elem_type = InvalidOid;
- variadic = false;
-
- /*
* Check argument count.
*/
Assert(nargs >= 0); /* -1 not supported with argnames */
@@ -1324,11 +1330,32 @@ FuncnameGetCandidates(List *names, int nargs, List *argnames,
if (pronargs != nargs && !use_defaults)
continue;
+ /* We found a routine with a suitable number of arguments */
+ *fgc_flags |= FGC_ARGCOUNT_MATCH;
+
/* Check for argument name match, generate positional mapping */
if (!MatchNamedCall(proctup, nargs, argnames,
include_out_arguments, pronargs,
- &argnumbers))
+ &argnumbers, fgc_flags))
+ continue;
+
+ /*
+ * Named or mixed notation can match a variadic function only if
+ * expand_variadic is off; otherwise there is no way to match the
+ * presumed-nameless parameters expanded from the variadic array.
+ * However, we postpone the check until here because we want to
+ * perform argument name matching anyway (using the variadic array
+ * argument's name). This allows us to give an on-point error
+ * message if the user forgets to say VARIADIC in what would have
+ * been a valid call with it.
+ */
+ if (OidIsValid(procform->provariadic) && expand_variadic)
continue;
+ va_elem_type = InvalidOid;
+ variadic = false;
+
+ /* We found a fully-valid call using argument names */
+ *fgc_flags |= FGC_ARGNAMES_VALID;
/* Named argument matching is always "special" */
any_special = true;
@@ -1371,6 +1398,9 @@ FuncnameGetCandidates(List *names, int nargs, List *argnames,
/* Ignore if it doesn't match requested argument count */
if (nargs >= 0 && pronargs != nargs && !variadic && !use_defaults)
continue;
+
+ /* We found a routine with a suitable number of arguments */
+ *fgc_flags |= FGC_ARGCOUNT_MATCH;
}
/*
@@ -1579,11 +1609,13 @@ FuncnameGetCandidates(List *names, int nargs, List *argnames,
* the mapping from call argument positions to actual function argument
* numbers. Defaulted arguments are included in this map, at positions
* after the last supplied argument.
+ *
+ * We also add flag bits to *fgc_flags reporting on how far the match got.
*/
static bool
MatchNamedCall(HeapTuple proctup, int nargs, List *argnames,
bool include_out_arguments, int pronargs,
- int **argnumbers)
+ int **argnumbers, int *fgc_flags)
{
Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
int numposargs = nargs - list_length(argnames);
@@ -1592,6 +1624,7 @@ MatchNamedCall(HeapTuple proctup, int nargs, List *argnames,
char **p_argnames;
char *p_argmodes;
bool arggiven[FUNC_MAX_ARGS];
+ bool arg_filled_twice = false;
bool isnull;
int ap; /* call args position */
int pp; /* proargs position */
@@ -1645,9 +1678,9 @@ MatchNamedCall(HeapTuple proctup, int nargs, List *argnames,
continue;
if (p_argnames[i] && strcmp(p_argnames[i], argname) == 0)
{
- /* fail if argname matches a positional argument */
+ /* note if argname matches a positional argument */
if (arggiven[pp])
- return false;
+ arg_filled_twice = true;
arggiven[pp] = true;
(*argnumbers)[ap] = pp;
found = true;
@@ -1664,6 +1697,16 @@ MatchNamedCall(HeapTuple proctup, int nargs, List *argnames,
Assert(ap == nargs); /* processed all actual parameters */
+ /* If we get here, the function did match all the supplied argnames */
+ *fgc_flags |= FGC_ARGNAMES_MATCH;
+
+ /* ... however, some of them might have been placed wrong */
+ if (arg_filled_twice)
+ return false; /* some argname matched a positional argument */
+
+ /* If we get here, the call doesn't have invalid mixed notation */
+ *fgc_flags |= FGC_ARGNAMES_NONDUP;
+
/* Check for default arguments */
if (nargs < pronargs)
{
@@ -1682,6 +1725,9 @@ MatchNamedCall(HeapTuple proctup, int nargs, List *argnames,
Assert(ap == pronargs); /* processed all function parameters */
+ /* If we get here, the call supplies all the required arguments */
+ *fgc_flags |= FGC_ARGNAMES_ALL;
+
return true;
}
@@ -1745,11 +1791,13 @@ FunctionIsVisibleExt(Oid funcid, bool *is_missing)
char *proname = NameStr(procform->proname);
int nargs = procform->pronargs;
FuncCandidateList clist;
+ int fgc_flags;
visible = false;
clist = FuncnameGetCandidates(list_make1(makeString(proname)),
- nargs, NIL, false, false, false, false);
+ nargs, NIL, false, false, false, false,
+ &fgc_flags);
for (; clist; clist = clist->next)
{
@@ -1882,9 +1930,20 @@ OpernameGetOprid(List *names, Oid oprleft, Oid oprright)
*
* The returned items always have two args[] entries --- the first will be
* InvalidOid for a prefix oprkind. nargs is always 2, too.
+ *
+ * We return an empty list (NULL) if no suitable matches can be found. If the
+ * operator name was schema-qualified with a schema that does not exist, then
+ * we return an empty list if missing_schema_ok is true and otherwise throw an
+ * error. (missing_schema_ok does not affect the behavior otherwise.)
+ *
+ * The output argument *fgc_flags is filled with a bitmask indicating how
+ * far we were able to match the supplied information. This is not of much
+ * interest if any candidates were found, but if not, it can help callers
+ * produce an on-point error message.
*/
FuncCandidateList
-OpernameGetCandidates(List *names, char oprkind, bool missing_schema_ok)
+OpernameGetCandidates(List *names, char oprkind, bool missing_schema_ok,
+ int *fgc_flags)
{
FuncCandidateList resultList = NULL;
char *resultSpace = NULL;
@@ -1895,15 +1954,20 @@ OpernameGetCandidates(List *names, char oprkind, bool missing_schema_ok)
CatCList *catlist;
int i;
+ /* initialize output fgc_flags to empty */
+ *fgc_flags = 0;
+
/* deconstruct the name list */
DeconstructQualifiedName(names, &schemaname, &opername);
if (schemaname)
{
/* use exact schema given */
+ *fgc_flags |= FGC_SCHEMA_GIVEN; /* report that a schema is given */
namespaceId = LookupExplicitNamespace(schemaname, missing_schema_ok);
- if (missing_schema_ok && !OidIsValid(namespaceId))
+ if (!OidIsValid(namespaceId))
return NULL;
+ *fgc_flags |= FGC_SCHEMA_EXISTS; /* report that the schema exists */
}
else
{
@@ -1941,6 +2005,8 @@ OpernameGetCandidates(List *names, char oprkind, bool missing_schema_ok)
if (oprkind && operform->oprkind != oprkind)
continue;
+ *fgc_flags |= FGC_NAME_EXISTS; /* the name is present in pg_operator */
+
if (OidIsValid(namespaceId))
{
/* Consider only opers in specified namespace */
@@ -2014,6 +2080,8 @@ OpernameGetCandidates(List *names, char oprkind, bool missing_schema_ok)
}
}
+ *fgc_flags |= FGC_NAME_VISIBLE; /* operator is in the right schema */
+
/*
* Okay to add it to result list
*/
diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c
index c62e8acd4137..a1cb5719a0c6 100644
--- a/src/backend/catalog/pg_aggregate.c
+++ b/src/backend/catalog/pg_aggregate.c
@@ -836,6 +836,7 @@ lookup_agg_function(List *fnName,
Oid vatype;
Oid *true_oid_array;
FuncDetailCode fdresult;
+ int fgc_flags;
AclResult aclresult;
int i;
@@ -848,6 +849,7 @@ lookup_agg_function(List *fnName,
*/
fdresult = func_get_detail(fnName, NIL, NIL,
nargs, input_types, false, false, false,
+ &fgc_flags,
&fnOid, rettype, &retset,
&nvargs, &vatype,
&true_oid_array, NULL);
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index 583bbbf232f0..c43020a769d1 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -42,6 +42,8 @@ typedef enum
FUNCLOOKUP_AMBIGUOUS,
} FuncLookupError;
+static int func_lookup_failure_details(int fgc_flags, List *argnames,
+ bool proc_call);
static void unify_hypothetical_args(ParseState *pstate,
List *fargs, int numAggregatedArgs,
Oid *actual_arg_types, Oid *declared_arg_types);
@@ -115,6 +117,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
int nvargs;
Oid vatype;
FuncDetailCode fdresult;
+ int fgc_flags;
char aggkind = 0;
ParseCallbackState pcbstate;
@@ -266,6 +269,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
fdresult = func_get_detail(funcname, fargs, argnames, nargs,
actual_arg_types,
!func_variadic, true, proc_call,
+ &fgc_flags,
&funcid, &rettype, &retset,
&nvargs, &vatype,
&declared_arg_types, &argdefaults);
@@ -563,8 +567,8 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
errmsg("procedure %s is not unique",
func_signature_string(funcname, nargs, argnames,
actual_arg_types)),
- errhint("Could not choose a best candidate procedure. "
- "You might need to add explicit type casts."),
+ errdetail("Could not choose a best candidate procedure."),
+ errhint("You might need to add explicit type casts."),
parser_errposition(pstate, location)));
else
ereport(ERROR,
@@ -572,8 +576,8 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
errmsg("function %s is not unique",
func_signature_string(funcname, nargs, argnames,
actual_arg_types)),
- errhint("Could not choose a best candidate function. "
- "You might need to add explicit type casts."),
+ errdetail("Could not choose a best candidate function."),
+ errhint("You might need to add explicit type casts."),
parser_errposition(pstate, location)));
}
else
@@ -601,7 +605,9 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
/*
* No function, and no column either. Since we're dealing with
- * function notation, report "function does not exist".
+ * function notation, report "function/procedure does not exist".
+ * Depending on what was returned in fgc_flags, we can add some color
+ * to that with detail or hint messages.
*/
if (list_length(agg_order) > 1 && !agg_within_group)
{
@@ -611,8 +617,8 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
errmsg("function %s does not exist",
func_signature_string(funcname, nargs, argnames,
actual_arg_types)),
- errhint("No aggregate function matches the given name and argument types. "
- "Perhaps you misplaced ORDER BY; ORDER BY must appear "
+ errdetail("No aggregate function matches the given name and argument types."),
+ errhint("Perhaps you misplaced ORDER BY; ORDER BY must appear "
"after all regular arguments of the aggregate."),
parser_errposition(pstate, location)));
}
@@ -622,8 +628,8 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
errmsg("procedure %s does not exist",
func_signature_string(funcname, nargs, argnames,
actual_arg_types)),
- errhint("No procedure matches the given name and argument types. "
- "You might need to add explicit type casts."),
+ func_lookup_failure_details(fgc_flags, argnames,
+ proc_call),
parser_errposition(pstate, location)));
else
ereport(ERROR,
@@ -631,8 +637,8 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
errmsg("function %s does not exist",
func_signature_string(funcname, nargs, argnames,
actual_arg_types)),
- errhint("No function matches the given name and argument types. "
- "You might need to add explicit type casts."),
+ func_lookup_failure_details(fgc_flags, argnames,
+ proc_call),
parser_errposition(pstate, location)));
}
@@ -905,6 +911,104 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
return retval;
}
+/*
+ * Interpret the fgc_flags and issue a suitable detail or hint message.
+ *
+ * Helper function to reduce code duplication while throwing a
+ * function-not-found error.
+ */
+static int
+func_lookup_failure_details(int fgc_flags, List *argnames, bool proc_call)
+{
+ /*
+ * If not FGC_NAME_VISIBLE, we shouldn't raise the question of whether the
+ * arguments are wrong. If the function name was not schema-qualified,
+ * it's helpful to distinguish between doesn't-exist-anywhere and
+ * not-in-search-path; but if it was, there's really nothing to add to the
+ * basic "function/procedure %s does not exist" message.
+ *
+ * Note: we passed missing_ok = false to FuncnameGetCandidates, so there's
+ * no need to consider FGC_SCHEMA_EXISTS here: we'd have already thrown an
+ * error if an explicitly-given schema doesn't exist.
+ */
+ if (!(fgc_flags & FGC_NAME_VISIBLE))
+ {
+ if (fgc_flags & FGC_SCHEMA_GIVEN)
+ return 0; /* schema-qualified name */
+ else if (!(fgc_flags & FGC_NAME_EXISTS))
+ {
+ if (proc_call)
+ return errdetail("There is no procedure of that name.");
+ else
+ return errdetail("There is no function of that name.");
+ }
+ else
+ {
+ if (proc_call)
+ return errdetail("A procedure of that name exists, but it is not in the search_path.");
+ else
+ return errdetail("A function of that name exists, but it is not in the search_path.");
+ }
+ }
+
+ /*
+ * Next, complain if nothing had the right number of arguments. (This
+ * takes precedence over wrong-argnames cases because we won't even look
+ * at the argnames unless there's a workable number of arguments.)
+ */
+ if (!(fgc_flags & FGC_ARGCOUNT_MATCH))
+ {
+ if (proc_call)
+ return errdetail("No procedure of that name accepts the given number of arguments.");
+ else
+ return errdetail("No function of that name accepts the given number of arguments.");
+ }
+
+ /*
+ * If there are argnames, and we failed to match them, again we should
+ * mention that and not bring up the argument types.
+ */
+ if (argnames != NIL && !(fgc_flags & FGC_ARGNAMES_MATCH))
+ {
+ if (proc_call)
+ return errdetail("No procedure of that name accepts the given argument names.");
+ else
+ return errdetail("No function of that name accepts the given argument names.");
+ }
+
+ /*
+ * We could have matched all the given argnames and still not have had a
+ * valid call, either because of improper use of mixed notation, or
+ * because of missing arguments, or because the user misused VARIADIC. The
+ * rules about named-argument matching are finicky enough that it's worth
+ * trying to be specific about the problem. (The messages here are chosen
+ * with full knowledge of the steps that namespace.c uses while checking a
+ * potential match.)
+ */
+ if (argnames != NIL && !(fgc_flags & FGC_ARGNAMES_NONDUP))
+ return errdetail("In the closest available match, "
+ "an argument was specified both positionally and by name.");
+
+ if (argnames != NIL && !(fgc_flags & FGC_ARGNAMES_ALL))
+ return errdetail("In the closest available match, "
+ "not all required arguments were supplied.");
+
+ if (argnames != NIL && !(fgc_flags & FGC_ARGNAMES_VALID))
+ return errhint("This call would be correct if the variadic array were labeled VARIADIC and placed last.");
+
+ if (fgc_flags & FGC_VARIADIC_FAIL)
+ return errhint("The VARIADIC parameter must be placed last, even when using argument names.");
+
+ /*
+ * Otherwise, the problem must be incorrect argument types.
+ */
+ if (proc_call)
+ (void) errdetail("No procedure of that name accepts the given argument types.");
+ else
+ (void) errdetail("No function of that name accepts the given argument types.");
+ return errhint("You might need to add explicit type casts.");
+}
+
/* func_match_argtypes()
*
@@ -1372,9 +1476,14 @@ func_select_candidate(int nargs,
* 1) check for possible interpretation as a type coercion request
* 2) apply the ambiguous-function resolution rules
*
- * Return values *funcid through *true_typeids receive info about the function.
- * If argdefaults isn't NULL, *argdefaults receives a list of any default
- * argument expressions that need to be added to the given arguments.
+ * If there is no match at all, we return FUNCDETAIL_NOTFOUND, and *fgc_flags
+ * is filled with some flags that may be useful for issuing an on-point error
+ * message (see FuncnameGetCandidates).
+ *
+ * On success, return values *funcid through *true_typeids receive info about
+ * the function. If argdefaults isn't NULL, *argdefaults receives a list of
+ * any default argument expressions that need to be added to the given
+ * arguments.
*
* When processing a named- or mixed-notation call (ie, fargnames isn't NIL),
* the returned true_typeids and argdefaults are ordered according to the
@@ -1400,6 +1509,7 @@ func_get_detail(List *funcname,
bool expand_variadic,
bool expand_defaults,
bool include_out_arguments,
+ int *fgc_flags, /* return value */
Oid *funcid, /* return value */
Oid *rettype, /* return value */
bool *retset, /* return value */
@@ -1424,7 +1534,8 @@ func_get_detail(List *funcname,
/* Get list of possible candidates from namespace search */
raw_candidates = FuncnameGetCandidates(funcname, nargs, fargnames,
expand_variadic, expand_defaults,
- include_out_arguments, false);
+ include_out_arguments, false,
+ fgc_flags);
/*
* Quickly check if there is an exact match to the input datatypes (there
@@ -1594,7 +1705,10 @@ func_get_detail(List *funcname,
*/
if (fargnames != NIL && !expand_variadic && nargs > 0 &&
best_candidate->argnumbers[nargs - 1] != nargs - 1)
+ {
+ *fgc_flags |= FGC_VARIADIC_FAIL;
return FUNCDETAIL_NOTFOUND;
+ }
*funcid = best_candidate->oid;
*nvargs = best_candidate->nvargs;
@@ -2053,6 +2167,7 @@ LookupFuncNameInternal(ObjectType objtype, List *funcname,
{
Oid result = InvalidOid;
FuncCandidateList clist;
+ int fgc_flags;
/* NULL argtypes allowed for nullary functions only */
Assert(argtypes != NULL || nargs == 0);
@@ -2062,7 +2177,8 @@ LookupFuncNameInternal(ObjectType objtype, List *funcname,
/* Get list of candidate objects */
clist = FuncnameGetCandidates(funcname, nargs, NIL, false, false,
- include_out_arguments, missing_ok);
+ include_out_arguments, missing_ok,
+ &fgc_flags);
/* Scan list for a match to the arg types (if specified) and the objtype */
for (; clist != NULL; clist = clist->next)
diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c
index 0c4337563cf3..7bd7a336fd6f 100644
--- a/src/backend/parser/parse_oper.c
+++ b/src/backend/parser/parse_oper.c
@@ -72,7 +72,8 @@ static FuncDetailCode oper_select_candidate(int nargs,
Oid *operOid);
static void op_error(ParseState *pstate, List *op,
Oid arg1, Oid arg2,
- FuncDetailCode fdresult, int location);
+ FuncDetailCode fdresult, int fgc_flags, int location);
+static int oper_lookup_failure_details(int fgc_flags, bool is_unary_op);
static bool make_oper_cache_key(ParseState *pstate, OprCacheKey *key,
List *opname, Oid ltypeId, Oid rtypeId,
int location);
@@ -373,6 +374,7 @@ oper(ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId,
Oid operOid;
OprCacheKey key;
bool key_ok;
+ int fgc_flags = 0;
FuncDetailCode fdresult = FUNCDETAIL_NOTFOUND;
HeapTuple tup = NULL;
@@ -404,7 +406,7 @@ oper(ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId,
FuncCandidateList clist;
/* Get binary operators of given name */
- clist = OpernameGetCandidates(opname, 'b', false);
+ clist = OpernameGetCandidates(opname, 'b', false, &fgc_flags);
/* No operators found? Then fail... */
if (clist != NULL)
@@ -434,7 +436,8 @@ oper(ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId,
make_oper_cache_entry(&key, operOid);
}
else if (!noError)
- op_error(pstate, opname, ltypeId, rtypeId, fdresult, location);
+ op_error(pstate, opname, ltypeId, rtypeId,
+ fdresult, fgc_flags, location);
return (Operator) tup;
}
@@ -520,6 +523,7 @@ left_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
Oid operOid;
OprCacheKey key;
bool key_ok;
+ int fgc_flags = 0;
FuncDetailCode fdresult = FUNCDETAIL_NOTFOUND;
HeapTuple tup = NULL;
@@ -551,7 +555,7 @@ left_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
FuncCandidateList clist;
/* Get prefix operators of given name */
- clist = OpernameGetCandidates(op, 'l', false);
+ clist = OpernameGetCandidates(op, 'l', false, &fgc_flags);
/* No operators found? Then fail... */
if (clist != NULL)
@@ -585,7 +589,8 @@ left_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
make_oper_cache_entry(&key, operOid);
}
else if (!noError)
- op_error(pstate, op, InvalidOid, arg, fdresult, location);
+ op_error(pstate, op, InvalidOid, arg,
+ fdresult, fgc_flags, location);
return (Operator) tup;
}
@@ -621,29 +626,67 @@ op_signature_string(List *op, Oid arg1, Oid arg2)
static void
op_error(ParseState *pstate, List *op,
Oid arg1, Oid arg2,
- FuncDetailCode fdresult, int location)
+ FuncDetailCode fdresult, int fgc_flags, int location)
{
if (fdresult == FUNCDETAIL_MULTIPLE)
ereport(ERROR,
(errcode(ERRCODE_AMBIGUOUS_FUNCTION),
errmsg("operator is not unique: %s",
op_signature_string(op, arg1, arg2)),
- errhint("Could not choose a best candidate operator. "
- "You might need to add explicit type casts."),
+ errdetail("Could not choose a best candidate operator."),
+ errhint("You might need to add explicit type casts."),
parser_errposition(pstate, location)));
else
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_FUNCTION),
errmsg("operator does not exist: %s",
op_signature_string(op, arg1, arg2)),
- (!arg1 || !arg2) ?
- errhint("No operator matches the given name and argument type. "
- "You might need to add an explicit type cast.") :
- errhint("No operator matches the given name and argument types. "
- "You might need to add explicit type casts."),
+ oper_lookup_failure_details(fgc_flags, (!arg1 || !arg2)),
parser_errposition(pstate, location)));
}
+/*
+ * Interpret the fgc_flags and issue a suitable detail or hint message.
+ */
+static int
+oper_lookup_failure_details(int fgc_flags, bool is_unary_op)
+{
+ /*
+ * If not FGC_NAME_VISIBLE, we shouldn't raise the question of whether the
+ * arguments are wrong. If the operator name was not schema-qualified,
+ * it's helpful to distinguish between doesn't-exist-anywhere and
+ * not-in-search-path; but if it was, there's really nothing to add to the
+ * basic "operator does not exist" message.
+ *
+ * Note: we passed missing_ok = false to OpernameGetCandidates, so there's
+ * no need to consider FGC_SCHEMA_EXISTS here: we'd have already thrown an
+ * error if an explicitly-given schema doesn't exist.
+ */
+ if (!(fgc_flags & FGC_NAME_VISIBLE))
+ {
+ if (fgc_flags & FGC_SCHEMA_GIVEN)
+ return 0; /* schema-qualified name */
+ else if (!(fgc_flags & FGC_NAME_EXISTS))
+ return errdetail("There is no operator of that name.");
+ else
+ return errdetail("An operator of that name exists, but it is not in the search_path.");
+ }
+
+ /*
+ * Otherwise, the problem must be incorrect argument type(s).
+ */
+ if (is_unary_op)
+ {
+ (void) errdetail("No operator of that name accepts the given argument type.");
+ return errhint("You might need to add an explicit type cast.");
+ }
+ else
+ {
+ (void) errdetail("No operator of that name accepts the given argument types.");
+ return errhint("You might need to add explicit type casts.");
+ }
+}
+
/*
* make_op()
* Operator expression construction.
diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c
index af17a3421a02..e5c2246f2c92 100644
--- a/src/backend/utils/adt/regproc.c
+++ b/src/backend/utils/adt/regproc.c
@@ -71,6 +71,7 @@ regprocin(PG_FUNCTION_ARGS)
RegProcedure result;
List *names;
FuncCandidateList clist;
+ int fgc_flags;
/* Handle "-" or numeric OID */
if (parseDashOrOid(pro_name_or_oid, &result, escontext))
@@ -93,7 +94,8 @@ regprocin(PG_FUNCTION_ARGS)
if (names == NIL)
PG_RETURN_NULL();
- clist = FuncnameGetCandidates(names, -1, NIL, false, false, false, true);
+ clist = FuncnameGetCandidates(names, -1, NIL, false, false, false, true,
+ &fgc_flags);
if (clist == NULL)
ereturn(escontext, (Datum) 0,
@@ -164,13 +166,15 @@ regprocout(PG_FUNCTION_ARGS)
{
char *nspname;
FuncCandidateList clist;
+ int fgc_flags;
/*
* Would this proc be found (uniquely!) by regprocin? If not,
* qualify it.
*/
clist = FuncnameGetCandidates(list_make1(makeString(proname)),
- -1, NIL, false, false, false, false);
+ -1, NIL, false, false, false, false,
+ &fgc_flags);
if (clist != NULL && clist->next == NULL &&
clist->oid == proid)
nspname = NULL;
@@ -231,6 +235,7 @@ regprocedurein(PG_FUNCTION_ARGS)
int nargs;
Oid argtypes[FUNC_MAX_ARGS];
FuncCandidateList clist;
+ int fgc_flags;
/* Handle "-" or numeric OID */
if (parseDashOrOid(pro_name_or_oid, &result, escontext))
@@ -251,8 +256,8 @@ regprocedurein(PG_FUNCTION_ARGS)
escontext))
PG_RETURN_NULL();
- clist = FuncnameGetCandidates(names, nargs, NIL, false, false,
- false, true);
+ clist = FuncnameGetCandidates(names, nargs, NIL, false, false, false, true,
+ &fgc_flags);
for (; clist; clist = clist->next)
{
@@ -483,6 +488,7 @@ regoperin(PG_FUNCTION_ARGS)
Oid result;
List *names;
FuncCandidateList clist;
+ int fgc_flags;
/* Handle "0" or numeric OID */
if (parseNumericOid(opr_name_or_oid, &result, escontext))
@@ -502,7 +508,7 @@ regoperin(PG_FUNCTION_ARGS)
if (names == NIL)
PG_RETURN_NULL();
- clist = OpernameGetCandidates(names, '\0', true);
+ clist = OpernameGetCandidates(names, '\0', true, &fgc_flags);
if (clist == NULL)
ereturn(escontext, (Datum) 0,
@@ -572,13 +578,14 @@ regoperout(PG_FUNCTION_ARGS)
else
{
FuncCandidateList clist;
+ int fgc_flags;
/*
* Would this oper be found (uniquely!) by regoperin? If not,
* qualify it.
*/
clist = OpernameGetCandidates(list_make1(makeString(oprname)),
- '\0', false);
+ '\0', false, &fgc_flags);
if (clist != NULL && clist->next == NULL &&
clist->oid == oprid)
result = pstrdup(oprname);
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 3d6e6bdbfd21..0408a95941dc 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -13265,6 +13265,7 @@ generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes,
bool use_variadic;
char *nspname;
FuncDetailCode p_result;
+ int fgc_flags;
Oid p_funcid;
Oid p_rettype;
bool p_retset;
@@ -13323,6 +13324,7 @@ generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes,
p_result = func_get_detail(list_make1(makeString(proname)),
NIL, argnames, nargs, argtypes,
!use_variadic, true, false,
+ &fgc_flags,
&p_funcid, &p_rettype,
&p_retset, &p_nvargs, &p_vatype,
&p_true_typeids, NULL);
diff --git a/src/include/catalog/namespace.h b/src/include/catalog/namespace.h
index 8c7ccc69a3c3..f1423f28c326 100644
--- a/src/include/catalog/namespace.h
+++ b/src/include/catalog/namespace.h
@@ -39,6 +39,24 @@ typedef struct _FuncCandidateList
Oid args[FLEXIBLE_ARRAY_MEMBER]; /* arg types */
} *FuncCandidateList;
+/*
+ * FuncnameGetCandidates also returns a bitmask containing these flags,
+ * which report on what it found or didn't find. They can help callers
+ * produce better error reports after a function lookup failure.
+ */
+#define FGC_SCHEMA_GIVEN 0x0001 /* Func name includes a schema */
+#define FGC_SCHEMA_EXISTS 0x0002 /* Found the explicitly-specified schema */
+#define FGC_NAME_EXISTS 0x0004 /* Found a routine by that name */
+#define FGC_NAME_VISIBLE 0x0008 /* Found a routine name/schema match */
+#define FGC_ARGCOUNT_MATCH 0x0010 /* Found a func with right # of args */
+/* These bits relate only to calls using named or mixed arguments: */
+#define FGC_ARGNAMES_MATCH 0x0020 /* Found a func matching all argnames */
+#define FGC_ARGNAMES_NONDUP 0x0040 /* argnames don't overlap positional args */
+#define FGC_ARGNAMES_ALL 0x0080 /* Found a func with no missing args */
+#define FGC_ARGNAMES_VALID 0x0100 /* Found a fully-valid use of argnames */
+/* These bits are actually filled by func_get_detail: */
+#define FGC_VARIADIC_FAIL 0x0200 /* Disallowed VARIADIC with named args */
+
/*
* Result of checkTempNamespaceStatus
*/
@@ -102,12 +120,14 @@ extern FuncCandidateList FuncnameGetCandidates(List *names,
bool expand_variadic,
bool expand_defaults,
bool include_out_arguments,
- bool missing_ok);
+ bool missing_ok,
+ int *fgc_flags);
extern bool FunctionIsVisible(Oid funcid);
extern Oid OpernameGetOprid(List *names, Oid oprleft, Oid oprright);
extern FuncCandidateList OpernameGetCandidates(List *names, char oprkind,
- bool missing_schema_ok);
+ bool missing_schema_ok,
+ int *fgc_flags);
extern bool OperatorIsVisible(Oid oprid);
extern Oid OpclassnameGetOpcid(Oid amid, const char *opcname);
diff --git a/src/include/parser/parse_func.h b/src/include/parser/parse_func.h
index a6f24b83d843..218bb14c5d6b 100644
--- a/src/include/parser/parse_func.h
+++ b/src/include/parser/parse_func.h
@@ -40,6 +40,7 @@ extern FuncDetailCode func_get_detail(List *funcname,
int nargs, Oid *argtypes,
bool expand_variadic, bool expand_defaults,
bool include_out_arguments,
+ int *fgc_flags,
Oid *funcid, Oid *rettype,
bool *retset, int *nvargs, Oid *vatype,
Oid **true_typeids, List **argdefaults);
diff --git a/src/pl/plperl/expected/plperl_elog.out b/src/pl/plperl/expected/plperl_elog.out
index a6d35cb79c4f..6343962b81d3 100644
--- a/src/pl/plperl/expected/plperl_elog.out
+++ b/src/pl/plperl/expected/plperl_elog.out
@@ -41,7 +41,7 @@ select uses_global();
ERROR: function uses_global() does not exist
LINE 1: select uses_global();
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: There is no function of that name.
SET plperl.use_strict = false;
create or replace function uses_global() returns text language plperl as $$
diff --git a/src/pl/plperl/expected/plperl_elog_1.out b/src/pl/plperl/expected/plperl_elog_1.out
index 85aa460ec4c2..a85dd17b5799 100644
--- a/src/pl/plperl/expected/plperl_elog_1.out
+++ b/src/pl/plperl/expected/plperl_elog_1.out
@@ -41,7 +41,7 @@ select uses_global();
ERROR: function uses_global() does not exist
LINE 1: select uses_global();
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: There is no function of that name.
SET plperl.use_strict = false;
create or replace function uses_global() returns text language plperl as $$
diff --git a/src/pl/plpgsql/src/expected/plpgsql_call.out b/src/pl/plpgsql/src/expected/plpgsql_call.out
index ea7107dca0d9..3d0b117f236b 100644
--- a/src/pl/plpgsql/src/expected/plpgsql_call.out
+++ b/src/pl/plpgsql/src/expected/plpgsql_call.out
@@ -440,7 +440,8 @@ $$;
ERROR: procedure test_proc12(integer, integer, text[]) does not exist
LINE 1: CALL test_proc12(_a, _b, _c)
^
-HINT: No procedure matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No procedure of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
QUERY: CALL test_proc12(_a, _b, _c)
CONTEXT: PL/pgSQL function inline_code_block line 5 at CALL
-- transition variable assignment
diff --git a/src/pl/plpgsql/src/expected/plpgsql_record.out b/src/pl/plpgsql/src/expected/plpgsql_record.out
index e5de7143606a..511f9e03c85d 100644
--- a/src/pl/plpgsql/src/expected/plpgsql_record.out
+++ b/src/pl/plpgsql/src/expected/plpgsql_record.out
@@ -466,7 +466,8 @@ select getf1(1);
ERROR: function getf1(integer) does not exist
LINE 1: select getf1(1);
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No function of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
select getf1(row(1,2));
getf1
-------
diff --git a/src/pl/plpython/expected/plpython_error.out b/src/pl/plpython/expected/plpython_error.out
index fd9cd73be743..96bbdfb95862 100644
--- a/src/pl/plpython/expected/plpython_error.out
+++ b/src/pl/plpython/expected/plpython_error.out
@@ -63,7 +63,7 @@ SELECT exception_index_invalid_nested();
ERROR: spiexceptions.UndefinedFunction: function test5(unknown) does not exist
LINE 1: SELECT test5('foo')
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: There is no function of that name.
QUERY: SELECT test5('foo')
CONTEXT: Traceback (most recent call last):
PL/Python function "exception_index_invalid_nested", line 1, in
diff --git a/src/test/modules/libpq_pipeline/traces/pipeline_abort.trace b/src/test/modules/libpq_pipeline/traces/pipeline_abort.trace
index cf6ccec6b9d1..3e5007d13b23 100644
--- a/src/test/modules/libpq_pipeline/traces/pipeline_abort.trace
+++ b/src/test/modules/libpq_pipeline/traces/pipeline_abort.trace
@@ -27,7 +27,7 @@ B 4 ParseComplete
B 4 BindComplete
B 4 NoData
B 15 CommandComplete "INSERT 0 1"
-B NN ErrorResponse S "ERROR" V "ERROR" C "42883" M "function no_such_function(integer) does not exist" H "No function matches the given name and argument types. You might need to add explicit type casts." P "8" F "SSSS" L "SSSS" R "SSSS" \x00
+B NN ErrorResponse S "ERROR" V "ERROR" C "42883" M "function no_such_function(integer) does not exist" D "There is no function of that name." P "8" F "SSSS" L "SSSS" R "SSSS" \x00
B 5 ReadyForQuery I
B 4 ParseComplete
B 4 BindComplete
diff --git a/src/test/modules/test_extensions/expected/test_extensions.out b/src/test/modules/test_extensions/expected/test_extensions.out
index 72bae1bf254b..fdae52d6ab2b 100644
--- a/src/test/modules/test_extensions/expected/test_extensions.out
+++ b/src/test/modules/test_extensions/expected/test_extensions.out
@@ -333,7 +333,7 @@ SELECT ext_cor_func();
ERROR: function ext_cor_func() does not exist
LINE 1: SELECT ext_cor_func();
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: There is no function of that name.
SELECT * FROM ext_cor_view;
col
------------------------
@@ -649,7 +649,6 @@ SELECT dep_req3b(); -- fails
ERROR: function public.dep_req2() does not exist
LINE 1: SELECT public.dep_req2() || ' req3b'
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
QUERY: SELECT public.dep_req2() || ' req3b'
CONTEXT: SQL function "dep_req3b" statement 1
DROP EXTENSION test_ext_req_schema3;
diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out
index b33e06a0d3d5..a08f115b0e5a 100644
--- a/src/test/regress/expected/alter_table.out
+++ b/src/test/regress/expected/alter_table.out
@@ -2041,7 +2041,8 @@ alter table anothertab alter column atcol1 drop default;
alter table anothertab alter column atcol1 type boolean
using case when atcol1 % 2 = 0 then true else false end; -- fails
ERROR: operator does not exist: boolean <= integer
-HINT: No operator matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No operator of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
alter table anothertab drop constraint anothertab_chk;
alter table anothertab drop constraint anothertab_chk; -- fails
ERROR: constraint "anothertab_chk" of relation "anothertab" does not exist
diff --git a/src/test/regress/expected/arrays.out b/src/test/regress/expected/arrays.out
index b815473f414b..69ea2cf5ad80 100644
--- a/src/test/regress/expected/arrays.out
+++ b/src/test/regress/expected/arrays.out
@@ -2747,7 +2747,8 @@ SELECT width_bucket('5'::text, ARRAY[3, 4]::integer[]);
ERROR: function width_bucket(text, integer[]) does not exist
LINE 1: SELECT width_bucket('5'::text, ARRAY[3, 4]::integer[]);
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No function of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
SELECT width_bucket(5, ARRAY[3, 4, NULL]);
ERROR: thresholds array must not contain NULLs
SELECT width_bucket(5, ARRAY[ARRAY[1, 2], ARRAY[3, 4]]);
diff --git a/src/test/regress/expected/create_cast.out b/src/test/regress/expected/create_cast.out
index fd4871d94db7..0e69644bca2a 100644
--- a/src/test/regress/expected/create_cast.out
+++ b/src/test/regress/expected/create_cast.out
@@ -28,14 +28,16 @@ SELECT casttestfunc('foo'::text); -- fails, as there's no cast
ERROR: function casttestfunc(text) does not exist
LINE 1: SELECT casttestfunc('foo'::text);
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No function of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
-- Try binary coercion cast
CREATE CAST (text AS casttesttype) WITHOUT FUNCTION;
SELECT casttestfunc('foo'::text); -- doesn't work, as the cast is explicit
ERROR: function casttestfunc(text) does not exist
LINE 1: SELECT casttestfunc('foo'::text);
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No function of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
SELECT casttestfunc('foo'::text::casttesttype); -- should work
casttestfunc
--------------
diff --git a/src/test/regress/expected/create_function_sql.out b/src/test/regress/expected/create_function_sql.out
index da112608d661..73c6730d4591 100644
--- a/src/test/regress/expected/create_function_sql.out
+++ b/src/test/regress/expected/create_function_sql.out
@@ -304,7 +304,8 @@ CREATE FUNCTION functest_S_xx(x date) RETURNS boolean
ERROR: operator does not exist: date > integer
LINE 3: RETURN x > 1;
^
-HINT: No operator matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No operator of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
-- tricky parsing
CREATE FUNCTION functest_S_15(x int) RETURNS boolean
LANGUAGE SQL
diff --git a/src/test/regress/expected/create_procedure.out b/src/test/regress/expected/create_procedure.out
index 45b402e25e79..f89042cf7987 100644
--- a/src/test/regress/expected/create_procedure.out
+++ b/src/test/regress/expected/create_procedure.out
@@ -2,7 +2,7 @@ CALL nonexistent(); -- error
ERROR: procedure nonexistent() does not exist
LINE 1: CALL nonexistent();
^
-HINT: No procedure matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: There is no procedure of that name.
CALL random(); -- error
ERROR: random() is not a procedure
LINE 1: CALL random();
@@ -299,7 +299,8 @@ CALL ptest9(1./0.); -- error
ERROR: procedure ptest9(numeric) does not exist
LINE 1: CALL ptest9(1./0.);
^
-HINT: No procedure matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No procedure of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
-- check named-parameter matching
CREATE PROCEDURE ptest10(OUT a int, IN b int, IN c int)
LANGUAGE SQL AS $$ SELECT b - c $$;
diff --git a/src/test/regress/expected/create_view.out b/src/test/regress/expected/create_view.out
index f551624afb3a..49dd13c345cc 100644
--- a/src/test/regress/expected/create_view.out
+++ b/src/test/regress/expected/create_view.out
@@ -1924,7 +1924,8 @@ select 'foo'::text = any((select array['abc','def','foo']::text[])); -- fail
ERROR: operator does not exist: text = text[]
LINE 1: select 'foo'::text = any((select array['abc','def','foo']::t...
^
-HINT: No operator matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No operator of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
select 'foo'::text = any((select array['abc','def','foo']::text[])::text[]);
?column?
----------
diff --git a/src/test/regress/expected/domain.out b/src/test/regress/expected/domain.out
index b5ea707df310..62a48a523a2d 100644
--- a/src/test/regress/expected/domain.out
+++ b/src/test/regress/expected/domain.out
@@ -415,7 +415,8 @@ select row(0,1)::dcomptype; -- fail
ERROR: value for domain dcomptype violates check constraint "c1"
alter type comptype alter attribute r type varchar; -- fail
ERROR: operator does not exist: character varying > double precision
-HINT: No operator matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No operator of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
alter type comptype alter attribute r type bigint;
alter type comptype drop attribute r; -- fail
ERROR: cannot drop column r of composite type comptype because other objects depend on it
diff --git a/src/test/regress/expected/expressions.out b/src/test/regress/expected/expressions.out
index 21c54fc1989c..9a3c97b15a3a 100644
--- a/src/test/regress/expected/expressions.out
+++ b/src/test/regress/expected/expressions.out
@@ -218,7 +218,8 @@ select '(0,0)'::point in ('(0,0,0,0)'::box, point(0,0));
ERROR: operator does not exist: point = box
LINE 1: select '(0,0)'::point in ('(0,0,0,0)'::box, point(0,0));
^
-HINT: No operator matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No operator of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
--
-- Tests for ScalarArrayOpExpr with a hashfn
--
diff --git a/src/test/regress/expected/geometry.out b/src/test/regress/expected/geometry.out
index 8be694f46be1..1d168b21cbca 100644
--- a/src/test/regress/expected/geometry.out
+++ b/src/test/regress/expected/geometry.out
@@ -1777,7 +1777,8 @@ SELECT p.f1, l.s, l.s # p.f1 AS intersection
ERROR: operator does not exist: lseg # point
LINE 1: SELECT p.f1, l.s, l.s # p.f1 AS intersection
^
-HINT: No operator matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No operator of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
-- Length
SELECT s, @-@ s FROM LSEG_TBL;
s | ?column?
diff --git a/src/test/regress/expected/horology.out b/src/test/regress/expected/horology.out
index 5ae93d8e8a51..32cf62b67417 100644
--- a/src/test/regress/expected/horology.out
+++ b/src/test/regress/expected/horology.out
@@ -605,7 +605,8 @@ SELECT date '1991-02-03' - time with time zone '04:05:06 UTC' AS "Subtract Time
ERROR: operator does not exist: date - time with time zone
LINE 1: SELECT date '1991-02-03' - time with time zone '04:05:06 UTC...
^
-HINT: No operator matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No operator of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
--
-- timestamp, interval arithmetic
--
diff --git a/src/test/regress/expected/misc_functions.out b/src/test/regress/expected/misc_functions.out
index c3b2b9d86034..36164a99c832 100644
--- a/src/test/regress/expected/misc_functions.out
+++ b/src/test/regress/expected/misc_functions.out
@@ -171,12 +171,12 @@ SELECT num_nonnulls();
ERROR: function num_nonnulls() does not exist
LINE 1: SELECT num_nonnulls();
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No function of that name accepts the given number of arguments.
SELECT num_nulls();
ERROR: function num_nulls() does not exist
LINE 1: SELECT num_nulls();
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No function of that name accepts the given number of arguments.
--
-- canonicalize_path()
--
diff --git a/src/test/regress/expected/multirangetypes.out b/src/test/regress/expected/multirangetypes.out
index c6363ebeb24c..63de4d09b153 100644
--- a/src/test/regress/expected/multirangetypes.out
+++ b/src/test/regress/expected/multirangetypes.out
@@ -3096,7 +3096,8 @@ select multirange_of_text(textrange2('a','Z')); -- should fail
ERROR: function multirange_of_text(textrange2) does not exist
LINE 1: select multirange_of_text(textrange2('a','Z'));
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No function of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
select multirange_of_text(textrange1('a','Z')) @> 'b'::text;
ERROR: range lower bound must be less than or equal to range upper bound
select unnest(multirange_of_text(textrange1('a','b'), textrange1('d','e')));
@@ -3160,7 +3161,8 @@ select anyarray_anymultirange_func(ARRAY[1,2], nummultirange(numrange(10,20)));
ERROR: function anyarray_anymultirange_func(integer[], nummultirange) does not exist
LINE 1: select anyarray_anymultirange_func(ARRAY[1,2], nummultirange...
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No function of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
drop function anyarray_anymultirange_func(anyarray, anymultirange);
-- should fail
create function bogus_func(anyelement)
@@ -3199,7 +3201,8 @@ select multirangetypes_sql(nummultirange(numrange(1,10)), ARRAY[2,20]); -- matc
ERROR: function multirangetypes_sql(nummultirange, integer[]) does not exist
LINE 1: select multirangetypes_sql(nummultirange(numrange(1,10)), AR...
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No function of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
create function anycompatiblearray_anycompatiblemultirange_func(a anycompatiblearray, mr anycompatiblemultirange)
returns anycompatible as 'select $1[1] + lower($2);' language sql;
select anycompatiblearray_anycompatiblemultirange_func(ARRAY[1,2], multirange(int4range(10,20)));
@@ -3219,7 +3222,8 @@ select anycompatiblearray_anycompatiblemultirange_func(ARRAY[1.1,2], multirange(
ERROR: function anycompatiblearray_anycompatiblemultirange_func(numeric[], int4multirange) does not exist
LINE 1: select anycompatiblearray_anycompatiblemultirange_func(ARRAY...
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No function of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
drop function anycompatiblearray_anycompatiblemultirange_func(anycompatiblearray, anycompatiblemultirange);
create function anycompatiblerange_anycompatiblemultirange_func(r anycompatiblerange, mr anycompatiblemultirange)
returns anycompatible as 'select lower($1) + lower($2);' language sql;
@@ -3234,7 +3238,8 @@ select anycompatiblerange_anycompatiblemultirange_func(numrange(1,2), multirange
ERROR: function anycompatiblerange_anycompatiblemultirange_func(numrange, int4multirange) does not exist
LINE 1: select anycompatiblerange_anycompatiblemultirange_func(numra...
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No function of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
drop function anycompatiblerange_anycompatiblemultirange_func(anycompatiblerange, anycompatiblemultirange);
-- should fail
create function bogus_func(anycompatible)
diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out
index d8ce39dba3c1..474be478ce8e 100644
--- a/src/test/regress/expected/plpgsql.out
+++ b/src/test/regress/expected/plpgsql.out
@@ -1763,7 +1763,8 @@ select f1(point(3,4)); -- fail for lack of + operator
ERROR: operator does not exist: point + integer
LINE 1: x + 1
^
-HINT: No operator matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No operator of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
QUERY: x + 1
CONTEXT: PL/pgSQL function f1(anyelement) line 3 at RETURN
drop function f1(x anyelement);
@@ -1848,7 +1849,8 @@ select f1(int4range(42, 49), 11, 4.5) as fail; -- range type doesn't fit
ERROR: function f1(int4range, integer, numeric) does not exist
LINE 1: select f1(int4range(42, 49), 11, 4.5) as fail;
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No function of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
drop function f1(x anycompatiblerange, y anycompatible, z anycompatible);
-- fail, can't infer type:
create function f1(x anycompatible) returns anycompatiblerange as $$
@@ -1902,7 +1904,8 @@ select x, pg_typeof(x), y, pg_typeof(y)
ERROR: function f1(integer, numeric[], integer, numeric) does not exist
LINE 2: from f1(11, array[1, 2.2], 42, 34.5);
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No function of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
drop function f1(a anyelement, b anyarray,
c anycompatible, d anycompatible);
--
@@ -3072,7 +3075,7 @@ select shadowtest(1);
ERROR: function shadowtest(integer) does not exist
LINE 1: select shadowtest(1);
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: There is no function of that name.
reset plpgsql.extra_errors;
reset plpgsql.extra_warnings;
create or replace function shadowtest(f1 int)
diff --git a/src/test/regress/expected/polymorphism.out b/src/test/regress/expected/polymorphism.out
index 94eedfe375ee..3cd99a92aa55 100644
--- a/src/test/regress/expected/polymorphism.out
+++ b/src/test/regress/expected/polymorphism.out
@@ -15,7 +15,8 @@ select polyf(point(3,4)); -- fail for lack of + operator
ERROR: operator does not exist: point + integer
LINE 2: select x + 1
^
-HINT: No operator matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No operator of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
QUERY:
select x + 1
@@ -95,7 +96,8 @@ select polyf(int4range(42, 49), 11, 4.5) as fail; -- range type doesn't fit
ERROR: function polyf(int4range, integer, numeric) does not exist
LINE 1: select polyf(int4range(42, 49), 11, 4.5) as fail;
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No function of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
drop function polyf(x anycompatiblerange, y anycompatible, z anycompatible);
create function polyf(x anycompatiblemultirange, y anycompatible, z anycompatible) returns anycompatiblearray as $$
select array[lower(x), upper(x), y, z]
@@ -110,7 +112,8 @@ select polyf(multirange(int4range(42, 49)), 11, 4.5) as fail; -- range type doe
ERROR: function polyf(int4multirange, integer, numeric) does not exist
LINE 1: select polyf(multirange(int4range(42, 49)), 11, 4.5) as fail...
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No function of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
drop function polyf(x anycompatiblemultirange, y anycompatible, z anycompatible);
-- fail, can't infer type:
create function polyf(x anycompatible) returns anycompatiblerange as $$
@@ -176,7 +179,8 @@ select x, pg_typeof(x), y, pg_typeof(y)
ERROR: function polyf(integer, numeric[], integer, numeric) does not exist
LINE 2: from polyf(11, array[1, 2.2], 42, 34.5);
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No function of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
drop function polyf(a anyelement, b anyarray,
c anycompatible, d anycompatible);
create function polyf(anyrange) returns anymultirange
@@ -990,7 +994,7 @@ select myleast(); -- fail
ERROR: function myleast() does not exist
LINE 1: select myleast();
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No function of that name accepts the given number of arguments.
-- test with variadic call parameter
select myleast(variadic array[1,2,3,4,-1]);
myleast
@@ -1060,17 +1064,20 @@ select formarray(1.1, array[1.2,55.5]); -- fail without variadic
ERROR: function formarray(numeric, numeric[]) does not exist
LINE 1: select formarray(1.1, array[1.2,55.5]);
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No function of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
select formarray(1, 'x'::text); -- fail, type mismatch
ERROR: function formarray(integer, text) does not exist
LINE 1: select formarray(1, 'x'::text);
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No function of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
select formarray(1, variadic array['x'::text]); -- fail, type mismatch
ERROR: function formarray(integer, text[]) does not exist
LINE 1: select formarray(1, variadic array['x'::text]);
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No function of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
drop function formarray(anyelement, variadic anyarray);
-- test pg_typeof() function
select pg_typeof(null); -- unknown
@@ -1154,7 +1161,7 @@ select dfunc(10, 20, 30); -- fail
ERROR: function dfunc(integer, integer, integer) does not exist
LINE 1: select dfunc(10, 20, 30);
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No function of that name accepts the given number of arguments.
drop function dfunc(); -- fail
ERROR: function dfunc() does not exist
drop function dfunc(int); -- fail
@@ -1203,7 +1210,8 @@ select dfunc(); -- fail: which dfunc should be called? int or text
ERROR: function dfunc() is not unique
LINE 1: select dfunc();
^
-HINT: Could not choose a best candidate function. You might need to add explicit type casts.
+DETAIL: Could not choose a best candidate function.
+HINT: You might need to add explicit type casts.
select dfunc('Hi'); -- ok
dfunc
-----------
@@ -1242,17 +1250,20 @@ select dfunc(); -- fail
ERROR: function dfunc() is not unique
LINE 1: select dfunc();
^
-HINT: Could not choose a best candidate function. You might need to add explicit type casts.
+DETAIL: Could not choose a best candidate function.
+HINT: You might need to add explicit type casts.
select dfunc(1); -- fail
ERROR: function dfunc(integer) is not unique
LINE 1: select dfunc(1);
^
-HINT: Could not choose a best candidate function. You might need to add explicit type casts.
+DETAIL: Could not choose a best candidate function.
+HINT: You might need to add explicit type casts.
select dfunc(1, 2); -- fail
ERROR: function dfunc(integer, integer) is not unique
LINE 1: select dfunc(1, 2);
^
-HINT: Could not choose a best candidate function. You might need to add explicit type casts.
+DETAIL: Could not choose a best candidate function.
+HINT: You might need to add explicit type casts.
select dfunc(1, 2, 3); -- ok
dfunc
-------
@@ -1310,7 +1321,7 @@ select dfunc(); -- fail
ERROR: function dfunc() does not exist
LINE 1: select dfunc();
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No function of that name accepts the given number of arguments.
select dfunc(10);
dfunc
-------
@@ -1371,7 +1382,8 @@ select dfunc(1); -- fail
ERROR: function dfunc(integer) is not unique
LINE 1: select dfunc(1);
^
-HINT: Could not choose a best candidate function. You might need to add explicit type casts.
+DETAIL: Could not choose a best candidate function.
+HINT: You might need to add explicit type casts.
-- but this works since the ambiguous functions aren't preferred anyway
select dfunc('Hi');
dfunc
@@ -1417,7 +1429,7 @@ select * from dfunc(0); -- fail
ERROR: function dfunc(integer) does not exist
LINE 1: select * from dfunc(0);
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No function of that name accepts the given number of arguments.
select * from dfunc(1,2);
a | b | c | d
---+---+---+---
@@ -1448,18 +1460,65 @@ select * from dfunc(x := 10, b := 20, c := 30); -- fail, unknown param
ERROR: function dfunc(x => integer, b => integer, c => integer) does not exist
LINE 1: select * from dfunc(x := 10, b := 20, c := 30);
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No function of that name accepts the given argument names.
select * from dfunc(10, 10, a := 20); -- fail, a overlaps positional parameter
ERROR: function dfunc(integer, integer, a => integer) does not exist
LINE 1: select * from dfunc(10, 10, a := 20);
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: In the closest available match, an argument was specified both positionally and by name.
select * from dfunc(1,c := 2,d := 3); -- fail, no value for b
ERROR: function dfunc(integer, c => integer, d => integer) does not exist
LINE 1: select * from dfunc(1,c := 2,d := 3);
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: In the closest available match, not all required arguments were supplied.
drop function dfunc(int, int, int, int);
+create function xleast(x numeric, variadic arr numeric[])
+ returns numeric as $$
+ select least(x, min(arr[i])) from generate_subscripts(arr, 1) g(i);
+$$ language sql;
+select xleast(x => 1, variadic arr => array[2,3]);
+ xleast
+--------
+ 1
+(1 row)
+
+select xleast(1, variadic arr => array[2,3]);
+ xleast
+--------
+ 1
+(1 row)
+
+select xleast(foo => 1, variadic arr => array[2,3]); -- wrong argument name
+ERROR: function xleast(foo => integer, arr => integer[]) does not exist
+LINE 1: select xleast(foo => 1, variadic arr => array[2,3]);
+ ^
+DETAIL: No function of that name accepts the given argument names.
+select xleast(x => 1, variadic array[2,3]); -- misuse of mixed notation
+ERROR: positional argument cannot follow named argument
+LINE 1: select xleast(x => 1, variadic array[2,3]);
+ ^
+select xleast(1, variadic x => array[2,3]); -- misuse of mixed notation
+ERROR: function xleast(integer, x => integer[]) does not exist
+LINE 1: select xleast(1, variadic x => array[2,3]);
+ ^
+DETAIL: In the closest available match, an argument was specified both positionally and by name.
+select xleast(arr => array[1], variadic x => 3); -- wrong arg is VARIADIC
+ERROR: function xleast(arr => integer[], x => integer) does not exist
+LINE 1: select xleast(arr => array[1], variadic x => 3);
+ ^
+HINT: The VARIADIC parameter must be placed last, even when using argument names.
+select xleast(arr => array[1], x => 3); -- failed to use VARIADIC
+ERROR: function xleast(arr => integer[], x => integer) does not exist
+LINE 1: select xleast(arr => array[1], x => 3);
+ ^
+HINT: This call would be correct if the variadic array were labeled VARIADIC and placed last.
+select xleast(arr => 1, variadic x => array[2,3]); -- mixed-up args
+ERROR: function xleast(arr => integer, x => integer[]) does not exist
+LINE 1: select xleast(arr => 1, variadic x => array[2,3]);
+ ^
+DETAIL: No function of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
+drop function xleast(x numeric, variadic arr numeric[]);
-- test with different parameter types
create function dfunc(a varchar, b numeric, c date = current_date)
returns table (a varchar, b numeric, c date) as $$
@@ -1499,7 +1558,8 @@ select * from dfunc('Hello World', c := 20, b := '2009-07-25'::date); -- fail
ERROR: function dfunc(unknown, c => integer, b => date) does not exist
LINE 1: select * from dfunc('Hello World', c := 20, b := '2009-07-25...
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No function of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
drop function dfunc(varchar, numeric, date);
-- test out parameters with named params
create function dfunc(a varchar = 'def a', out _a varchar, c numeric = NULL, out _c numeric)
@@ -1844,7 +1904,8 @@ select x, pg_typeof(x) from anyctest(11, point(1,2)) x; -- fail
ERROR: function anyctest(integer, point) does not exist
LINE 1: select x, pg_typeof(x) from anyctest(11, point(1,2)) x;
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No function of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
select x, pg_typeof(x) from anyctest('11', '12.3') x; -- defaults to text
x | pg_typeof
------+-----------
@@ -1872,7 +1933,8 @@ select x, pg_typeof(x) from anyctest(11, array[1,2]) x; -- fail
ERROR: function anyctest(integer, integer[]) does not exist
LINE 1: select x, pg_typeof(x) from anyctest(11, array[1,2]) x;
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No function of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
drop function anyctest(anycompatible, anycompatible);
create function anyctest(anycompatible, anycompatiblearray)
returns anycompatiblearray as $$
@@ -1906,12 +1968,14 @@ select x, pg_typeof(x) from anyctest(11, array[point(1,2)]) x; -- fail
ERROR: function anyctest(integer, point[]) does not exist
LINE 1: select x, pg_typeof(x) from anyctest(11, array[point(1,2)]) ...
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No function of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
select x, pg_typeof(x) from anyctest(11, 12) x; -- fail
ERROR: function anyctest(integer, integer) does not exist
LINE 1: select x, pg_typeof(x) from anyctest(11, 12) x;
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No function of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
drop function anyctest(anycompatible, anycompatiblearray);
create function anyctest(anycompatible, anycompatiblerange)
returns anycompatiblerange as $$
@@ -1933,12 +1997,14 @@ select x, pg_typeof(x) from anyctest(11, 12) x; -- fail
ERROR: function anyctest(integer, integer) does not exist
LINE 1: select x, pg_typeof(x) from anyctest(11, 12) x;
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No function of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
select x, pg_typeof(x) from anyctest(11.2, int4range(4,7)) x; -- fail
ERROR: function anyctest(numeric, int4range) does not exist
LINE 1: select x, pg_typeof(x) from anyctest(11.2, int4range(4,7)) x...
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No function of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
select x, pg_typeof(x) from anyctest(11.2, '[4,7)') x; -- fail
ERROR: could not determine polymorphic type anycompatiblerange because input has type unknown
drop function anyctest(anycompatible, anycompatiblerange);
@@ -1956,7 +2022,8 @@ select x, pg_typeof(x) from anyctest(int4range(11,12), numrange(4,7)) x; -- fail
ERROR: function anyctest(int4range, numrange) does not exist
LINE 1: select x, pg_typeof(x) from anyctest(int4range(11,12), numra...
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No function of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
drop function anyctest(anycompatiblerange, anycompatiblerange);
-- fail, can't infer result type:
create function anyctest(anycompatible)
@@ -1985,12 +2052,14 @@ select x, pg_typeof(x) from anyctest(11, 12) x; -- fail
ERROR: function anyctest(integer, integer) does not exist
LINE 1: select x, pg_typeof(x) from anyctest(11, 12) x;
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No function of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
select x, pg_typeof(x) from anyctest(11.2, multirange(int4range(4,7))) x; -- fail
ERROR: function anyctest(numeric, int4multirange) does not exist
LINE 1: select x, pg_typeof(x) from anyctest(11.2, multirange(int4ra...
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No function of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
select x, pg_typeof(x) from anyctest(11.2, '{[4,7)}') x; -- fail
ERROR: could not determine polymorphic type anycompatiblemultirange because input has type unknown
drop function anyctest(anycompatible, anycompatiblemultirange);
@@ -2008,7 +2077,8 @@ select x, pg_typeof(x) from anyctest(multirange(int4range(11,12)), multirange(nu
ERROR: function anyctest(int4multirange, nummultirange) does not exist
LINE 1: select x, pg_typeof(x) from anyctest(multirange(int4range(11...
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No function of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
drop function anyctest(anycompatiblemultirange, anycompatiblemultirange);
-- fail, can't infer result type:
create function anyctest(anycompatible)
@@ -2037,7 +2107,8 @@ select x, pg_typeof(x) from anyctest(array[11], array[1,2]) x; -- fail
ERROR: function anyctest(integer[], integer[]) does not exist
LINE 1: select x, pg_typeof(x) from anyctest(array[11], array[1,2]) ...
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No function of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
drop function anyctest(anycompatiblenonarray, anycompatiblenonarray);
create function anyctest(a anyelement, b anyarray,
c anycompatible, d anycompatible)
@@ -2066,7 +2137,8 @@ select x, pg_typeof(x) from anyctest(11, array[1, 2.2], 42, 34.5) x; -- fail
ERROR: function anyctest(integer, numeric[], integer, numeric) does not exist
LINE 1: select x, pg_typeof(x) from anyctest(11, array[1, 2.2], 42, ...
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No function of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
drop function anyctest(a anyelement, b anyarray,
c anycompatible, d anycompatible);
create function anyctest(variadic anycompatiblearray)
diff --git a/src/test/regress/expected/rangetypes.out b/src/test/regress/expected/rangetypes.out
index a7cc220bf0d6..cdd95799cd5c 100644
--- a/src/test/regress/expected/rangetypes.out
+++ b/src/test/regress/expected/rangetypes.out
@@ -1630,7 +1630,8 @@ select anyarray_anyrange_func(ARRAY[1,2], numrange(10,20));
ERROR: function anyarray_anyrange_func(integer[], numrange) does not exist
LINE 1: select anyarray_anyrange_func(ARRAY[1,2], numrange(10,20));
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No function of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
drop function anyarray_anyrange_func(anyarray, anyrange);
-- should fail
create function bogus_func(anyelement)
@@ -1669,7 +1670,8 @@ select rangetypes_sql(numrange(1,10), ARRAY[2,20]); -- match failure
ERROR: function rangetypes_sql(numrange, integer[]) does not exist
LINE 1: select rangetypes_sql(numrange(1,10), ARRAY[2,20]);
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No function of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
create function anycompatiblearray_anycompatiblerange_func(a anycompatiblearray, r anycompatiblerange)
returns anycompatible as 'select $1[1] + lower($2);' language sql;
select anycompatiblearray_anycompatiblerange_func(ARRAY[1,2], int4range(10,20));
@@ -1689,7 +1691,8 @@ select anycompatiblearray_anycompatiblerange_func(ARRAY[1.1,2], int4range(10,20)
ERROR: function anycompatiblearray_anycompatiblerange_func(numeric[], int4range) does not exist
LINE 1: select anycompatiblearray_anycompatiblerange_func(ARRAY[1.1,...
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No function of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
drop function anycompatiblearray_anycompatiblerange_func(anycompatiblearray, anycompatiblerange);
-- should fail
create function bogus_func(anycompatible)
diff --git a/src/test/regress/expected/rowtypes.out b/src/test/regress/expected/rowtypes.out
index 9168979a6206..d84122881aff 100644
--- a/src/test/regress/expected/rowtypes.out
+++ b/src/test/regress/expected/rowtypes.out
@@ -965,7 +965,8 @@ select text(fullname) from fullname; -- error
ERROR: function text(fullname) does not exist
LINE 1: select text(fullname) from fullname;
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No function of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
select fullname.text from fullname; -- error
ERROR: column fullname.text does not exist
LINE 1: select fullname.text from fullname;
@@ -987,7 +988,8 @@ select text(row('Jim', 'Beam')); -- error
ERROR: function text(record) does not exist
LINE 1: select text(row('Jim', 'Beam'));
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No function of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
select (row('Jim', 'Beam')).text; -- error
ERROR: could not identify column "text" in record data type
LINE 1: select (row('Jim', 'Beam')).text;
diff --git a/src/test/regress/expected/subselect.out b/src/test/regress/expected/subselect.out
index c16dff05bc12..d4a36a273713 100644
--- a/src/test/regress/expected/subselect.out
+++ b/src/test/regress/expected/subselect.out
@@ -1175,7 +1175,8 @@ select * from int8_tbl where q1 in (select c1 from inner_text);
ERROR: operator does not exist: bigint = text
LINE 1: select * from int8_tbl where q1 in (select c1 from inner_tex...
^
-HINT: No operator matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No operator of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
begin;
-- make an operator to allow it to succeed
create function bogus_int8_text_eq(int8, text) returns boolean
diff --git a/src/test/regress/expected/temp.out b/src/test/regress/expected/temp.out
index 370361543b30..a50c7ae88a9c 100644
--- a/src/test/regress/expected/temp.out
+++ b/src/test/regress/expected/temp.out
@@ -229,7 +229,7 @@ select nonempty('');
ERROR: function nonempty(unknown) does not exist
LINE 1: select nonempty('');
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: There is no function of that name.
select pg_temp.nonempty('');
ERROR: value for domain nonempty violates check constraint "nonempty_check"
-- other syntax matches rules for tables
diff --git a/src/test/regress/expected/text.out b/src/test/regress/expected/text.out
index 4c65b238e764..3f9982388baf 100644
--- a/src/test/regress/expected/text.out
+++ b/src/test/regress/expected/text.out
@@ -27,7 +27,8 @@ select length(42);
ERROR: function length(integer) does not exist
LINE 1: select length(42);
^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No function of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
-- But as a special exception for usability's sake, we still allow implicit
-- casting to text in concatenations, so long as the other input is text or
-- an unknown literal. So these work:
@@ -48,7 +49,8 @@ select 3 || 4.0;
ERROR: operator does not exist: integer || numeric
LINE 1: select 3 || 4.0;
^
-HINT: No operator matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No operator of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
/*
* various string functions
*/
diff --git a/src/test/regress/expected/time.out b/src/test/regress/expected/time.out
index 4247fae9412b..765adeb6e515 100644
--- a/src/test/regress/expected/time.out
+++ b/src/test/regress/expected/time.out
@@ -157,7 +157,8 @@ SELECT f1 + time '00:01' AS "Illegal" FROM TIME_TBL;
ERROR: operator is not unique: time without time zone + time without time zone
LINE 1: SELECT f1 + time '00:01' AS "Illegal" FROM TIME_TBL;
^
-HINT: Could not choose a best candidate operator. You might need to add explicit type casts.
+DETAIL: Could not choose a best candidate operator.
+HINT: You might need to add explicit type casts.
--
-- test EXTRACT
--
diff --git a/src/test/regress/expected/timetz.out b/src/test/regress/expected/timetz.out
index cbab6cfe5d7f..324b1a740e86 100644
--- a/src/test/regress/expected/timetz.out
+++ b/src/test/regress/expected/timetz.out
@@ -174,7 +174,8 @@ SELECT f1 + time with time zone '00:01' AS "Illegal" FROM TIMETZ_TBL;
ERROR: operator does not exist: time with time zone + time with time zone
LINE 1: SELECT f1 + time with time zone '00:01' AS "Illegal" FROM TI...
^
-HINT: No operator matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No operator of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
--
-- test EXTRACT
--
diff --git a/src/test/regress/expected/with.out b/src/test/regress/expected/with.out
index 26c885051400..f015e9972761 100644
--- a/src/test/regress/expected/with.out
+++ b/src/test/regress/expected/with.out
@@ -175,7 +175,8 @@ SELECT n, pg_typeof(n) FROM t;
ERROR: operator does not exist: text + integer
LINE 4: SELECT n+1 FROM t WHERE n < 10
^
-HINT: No operator matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No operator of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
-- Deeply nested WITH caused a list-munging problem in v13
-- Detection of cross-references and self-references
WITH RECURSIVE w1(c1) AS
diff --git a/src/test/regress/expected/xid.out b/src/test/regress/expected/xid.out
index 835077e9d578..1ce7826cf904 100644
--- a/src/test/regress/expected/xid.out
+++ b/src/test/regress/expected/xid.out
@@ -110,22 +110,26 @@ select '1'::xid < '2'::xid;
ERROR: operator does not exist: xid < xid
LINE 1: select '1'::xid < '2'::xid;
^
-HINT: No operator matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No operator of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
select '1'::xid <= '2'::xid;
ERROR: operator does not exist: xid <= xid
LINE 1: select '1'::xid <= '2'::xid;
^
-HINT: No operator matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No operator of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
select '1'::xid > '2'::xid;
ERROR: operator does not exist: xid > xid
LINE 1: select '1'::xid > '2'::xid;
^
-HINT: No operator matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No operator of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
select '1'::xid >= '2'::xid;
ERROR: operator does not exist: xid >= xid
LINE 1: select '1'::xid >= '2'::xid;
^
-HINT: No operator matches the given name and argument types. You might need to add explicit type casts.
+DETAIL: No operator of that name accepts the given argument types.
+HINT: You might need to add explicit type casts.
-- we want them for xid8 though
select '1'::xid8 < '2'::xid8, '2'::xid8 < '2'::xid8, '2'::xid8 < '1'::xid8;
?column? | ?column? | ?column?
diff --git a/src/test/regress/sql/polymorphism.sql b/src/test/regress/sql/polymorphism.sql
index fa57db6559c3..023d67751ea0 100644
--- a/src/test/regress/sql/polymorphism.sql
+++ b/src/test/regress/sql/polymorphism.sql
@@ -873,6 +873,23 @@ select * from dfunc(1,c := 2,d := 3); -- fail, no value for b
drop function dfunc(int, int, int, int);
+create function xleast(x numeric, variadic arr numeric[])
+ returns numeric as $$
+ select least(x, min(arr[i])) from generate_subscripts(arr, 1) g(i);
+$$ language sql;
+
+select xleast(x => 1, variadic arr => array[2,3]);
+select xleast(1, variadic arr => array[2,3]);
+
+select xleast(foo => 1, variadic arr => array[2,3]); -- wrong argument name
+select xleast(x => 1, variadic array[2,3]); -- misuse of mixed notation
+select xleast(1, variadic x => array[2,3]); -- misuse of mixed notation
+select xleast(arr => array[1], variadic x => 3); -- wrong arg is VARIADIC
+select xleast(arr => array[1], x => 3); -- failed to use VARIADIC
+select xleast(arr => 1, variadic x => array[2,3]); -- mixed-up args
+
+drop function xleast(x numeric, variadic arr numeric[]);
+
-- test with different parameter types
create function dfunc(a varchar, b numeric, c date = current_date)
returns table (a varchar, b numeric, c date) as $$