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 $$