summaryrefslogtreecommitdiffstats
path: root/src/backend/parser/parse_func.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser/parse_func.c')
-rw-r--r--src/backend/parser/parse_func.c2679
1 files changed, 2679 insertions, 0 deletions
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
new file mode 100644
index 0000000..542f916
--- /dev/null
+++ b/src/backend/parser/parse_func.c
@@ -0,0 +1,2679 @@
+/*-------------------------------------------------------------------------
+ *
+ * parse_func.c
+ * handle function calls in parser
+ *
+ * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * src/backend/parser/parse_func.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/htup_details.h"
+#include "catalog/pg_aggregate.h"
+#include "catalog/pg_proc.h"
+#include "catalog/pg_type.h"
+#include "funcapi.h"
+#include "lib/stringinfo.h"
+#include "nodes/makefuncs.h"
+#include "nodes/nodeFuncs.h"
+#include "parser/parse_agg.h"
+#include "parser/parse_clause.h"
+#include "parser/parse_coerce.h"
+#include "parser/parse_expr.h"
+#include "parser/parse_func.h"
+#include "parser/parse_relation.h"
+#include "parser/parse_target.h"
+#include "parser/parse_type.h"
+#include "utils/builtins.h"
+#include "utils/lsyscache.h"
+#include "utils/syscache.h"
+
+
+/* Possible error codes from LookupFuncNameInternal */
+typedef enum
+{
+ FUNCLOOKUP_NOSUCHFUNC,
+ FUNCLOOKUP_AMBIGUOUS
+} FuncLookupError;
+
+static void unify_hypothetical_args(ParseState *pstate,
+ List *fargs, int numAggregatedArgs,
+ Oid *actual_arg_types, Oid *declared_arg_types);
+static Oid FuncNameAsType(List *funcname);
+static Node *ParseComplexProjection(ParseState *pstate, const char *funcname,
+ Node *first_arg, int location);
+static Oid LookupFuncNameInternal(ObjectType objtype, List *funcname,
+ int nargs, const Oid *argtypes,
+ bool include_out_arguments, bool missing_ok,
+ FuncLookupError *lookupError);
+
+
+/*
+ * Parse a function call
+ *
+ * For historical reasons, Postgres tries to treat the notations tab.col
+ * and col(tab) as equivalent: if a single-argument function call has an
+ * argument of complex type and the (unqualified) function name matches
+ * any attribute of the type, we can interpret it as a column projection.
+ * Conversely a function of a single complex-type argument can be written
+ * like a column reference, allowing functions to act like computed columns.
+ *
+ * If both interpretations are possible, we prefer the one matching the
+ * syntactic form, but otherwise the form does not matter.
+ *
+ * Hence, both cases come through here. If fn is null, we're dealing with
+ * column syntax not function syntax. In the function-syntax case,
+ * the FuncCall struct is needed to carry various decoration that applies
+ * to aggregate and window functions.
+ *
+ * Also, when fn is null, we return NULL on failure rather than
+ * reporting a no-such-function error.
+ *
+ * The argument expressions (in fargs) must have been transformed
+ * already. However, nothing in *fn has been transformed.
+ *
+ * last_srf should be a copy of pstate->p_last_srf from just before we
+ * started transforming fargs. If the caller knows that fargs couldn't
+ * contain any SRF calls, last_srf can just be pstate->p_last_srf.
+ *
+ * proc_call is true if we are considering a CALL statement, so that the
+ * name must resolve to a procedure name, not anything else. This flag
+ * also specifies that the argument list includes any OUT-mode arguments.
+ */
+Node *
+ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
+ Node *last_srf, FuncCall *fn, bool proc_call, int location)
+{
+ bool is_column = (fn == NULL);
+ List *agg_order = (fn ? fn->agg_order : NIL);
+ Expr *agg_filter = NULL;
+ WindowDef *over = (fn ? fn->over : NULL);
+ bool agg_within_group = (fn ? fn->agg_within_group : false);
+ bool agg_star = (fn ? fn->agg_star : false);
+ bool agg_distinct = (fn ? fn->agg_distinct : false);
+ bool func_variadic = (fn ? fn->func_variadic : false);
+ CoercionForm funcformat = (fn ? fn->funcformat : COERCE_EXPLICIT_CALL);
+ bool could_be_projection;
+ Oid rettype;
+ Oid funcid;
+ ListCell *l;
+ Node *first_arg = NULL;
+ int nargs;
+ int nargsplusdefs;
+ Oid actual_arg_types[FUNC_MAX_ARGS];
+ Oid *declared_arg_types;
+ List *argnames;
+ List *argdefaults;
+ Node *retval;
+ bool retset;
+ int nvargs;
+ Oid vatype;
+ FuncDetailCode fdresult;
+ char aggkind = 0;
+ ParseCallbackState pcbstate;
+
+ /*
+ * If there's an aggregate filter, transform it using transformWhereClause
+ */
+ if (fn && fn->agg_filter != NULL)
+ agg_filter = (Expr *) transformWhereClause(pstate, fn->agg_filter,
+ EXPR_KIND_FILTER,
+ "FILTER");
+
+ /*
+ * Most of the rest of the parser just assumes that functions do not have
+ * more than FUNC_MAX_ARGS parameters. We have to test here to protect
+ * against array overruns, etc. Of course, this may not be a function,
+ * but the test doesn't hurt.
+ */
+ if (list_length(fargs) > FUNC_MAX_ARGS)
+ ereport(ERROR,
+ (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
+ errmsg_plural("cannot pass more than %d argument to a function",
+ "cannot pass more than %d arguments to a function",
+ FUNC_MAX_ARGS,
+ FUNC_MAX_ARGS),
+ parser_errposition(pstate, location)));
+
+ /*
+ * Extract arg type info in preparation for function lookup.
+ *
+ * If any arguments are Param markers of type VOID, we discard them from
+ * the parameter list. This is a hack to allow the JDBC driver to not have
+ * to distinguish "input" and "output" parameter symbols while parsing
+ * function-call constructs. Don't do this if dealing with column syntax,
+ * nor if we had WITHIN GROUP (because in that case it's critical to keep
+ * the argument count unchanged).
+ */
+ nargs = 0;
+ foreach(l, fargs)
+ {
+ Node *arg = lfirst(l);
+ Oid argtype = exprType(arg);
+
+ if (argtype == VOIDOID && IsA(arg, Param) &&
+ !is_column && !agg_within_group)
+ {
+ fargs = foreach_delete_current(fargs, l);
+ continue;
+ }
+
+ actual_arg_types[nargs++] = argtype;
+ }
+
+ /*
+ * Check for named arguments; if there are any, build a list of names.
+ *
+ * We allow mixed notation (some named and some not), but only with all
+ * the named parameters after all the unnamed ones. So the name list
+ * corresponds to the last N actual parameters and we don't need any extra
+ * bookkeeping to match things up.
+ */
+ argnames = NIL;
+ foreach(l, fargs)
+ {
+ Node *arg = lfirst(l);
+
+ if (IsA(arg, NamedArgExpr))
+ {
+ NamedArgExpr *na = (NamedArgExpr *) arg;
+ ListCell *lc;
+
+ /* Reject duplicate arg names */
+ foreach(lc, argnames)
+ {
+ if (strcmp(na->name, (char *) lfirst(lc)) == 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("argument name \"%s\" used more than once",
+ na->name),
+ parser_errposition(pstate, na->location)));
+ }
+ argnames = lappend(argnames, na->name);
+ }
+ else
+ {
+ if (argnames != NIL)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("positional argument cannot follow named argument"),
+ parser_errposition(pstate, exprLocation(arg))));
+ }
+ }
+
+ if (fargs)
+ {
+ first_arg = linitial(fargs);
+ Assert(first_arg != NULL);
+ }
+
+ /*
+ * Decide whether it's legitimate to consider the construct to be a column
+ * projection. For that, there has to be a single argument of complex
+ * type, the function name must not be qualified, and there cannot be any
+ * syntactic decoration that'd require it to be a function (such as
+ * aggregate or variadic decoration, or named arguments).
+ */
+ could_be_projection = (nargs == 1 && !proc_call &&
+ agg_order == NIL && agg_filter == NULL &&
+ !agg_star && !agg_distinct && over == NULL &&
+ !func_variadic && argnames == NIL &&
+ list_length(funcname) == 1 &&
+ (actual_arg_types[0] == RECORDOID ||
+ ISCOMPLEX(actual_arg_types[0])));
+
+ /*
+ * If it's column syntax, check for column projection case first.
+ */
+ if (could_be_projection && is_column)
+ {
+ retval = ParseComplexProjection(pstate,
+ strVal(linitial(funcname)),
+ first_arg,
+ location);
+ if (retval)
+ return retval;
+
+ /*
+ * If ParseComplexProjection doesn't recognize it as a projection,
+ * just press on.
+ */
+ }
+
+ /*
+ * func_get_detail looks up the function in the catalogs, does
+ * disambiguation for polymorphic functions, handles inheritance, and
+ * returns the funcid and type and set or singleton status of the
+ * function's return value. It also returns the true argument types to
+ * the function.
+ *
+ * Note: for a named-notation or variadic function call, the reported
+ * "true" types aren't really what is in pg_proc: the types are reordered
+ * to match the given argument order of named arguments, and a variadic
+ * argument is replaced by a suitable number of copies of its element
+ * type. We'll fix up the variadic case below. We may also have to deal
+ * with default arguments.
+ */
+
+ setup_parser_errposition_callback(&pcbstate, pstate, location);
+
+ fdresult = func_get_detail(funcname, fargs, argnames, nargs,
+ actual_arg_types,
+ !func_variadic, true, proc_call,
+ &funcid, &rettype, &retset,
+ &nvargs, &vatype,
+ &declared_arg_types, &argdefaults);
+
+ cancel_parser_errposition_callback(&pcbstate);
+
+ /*
+ * Check for various wrong-kind-of-routine cases.
+ */
+
+ /* If this is a CALL, reject things that aren't procedures */
+ if (proc_call &&
+ (fdresult == FUNCDETAIL_NORMAL ||
+ fdresult == FUNCDETAIL_AGGREGATE ||
+ fdresult == FUNCDETAIL_WINDOWFUNC ||
+ fdresult == FUNCDETAIL_COERCION))
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("%s is not a procedure",
+ func_signature_string(funcname, nargs,
+ argnames,
+ actual_arg_types)),
+ errhint("To call a function, use SELECT."),
+ parser_errposition(pstate, location)));
+ /* Conversely, if not a CALL, reject procedures */
+ if (fdresult == FUNCDETAIL_PROCEDURE && !proc_call)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("%s is a procedure",
+ func_signature_string(funcname, nargs,
+ argnames,
+ actual_arg_types)),
+ errhint("To call a procedure, use CALL."),
+ parser_errposition(pstate, location)));
+
+ if (fdresult == FUNCDETAIL_NORMAL ||
+ fdresult == FUNCDETAIL_PROCEDURE ||
+ fdresult == FUNCDETAIL_COERCION)
+ {
+ /*
+ * In these cases, complain if there was anything indicating it must
+ * be an aggregate or window function.
+ */
+ if (agg_star)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("%s(*) specified, but %s is not an aggregate function",
+ NameListToString(funcname),
+ NameListToString(funcname)),
+ parser_errposition(pstate, location)));
+ if (agg_distinct)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("DISTINCT specified, but %s is not an aggregate function",
+ NameListToString(funcname)),
+ parser_errposition(pstate, location)));
+ if (agg_within_group)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("WITHIN GROUP specified, but %s is not an aggregate function",
+ NameListToString(funcname)),
+ parser_errposition(pstate, location)));
+ if (agg_order != NIL)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("ORDER BY specified, but %s is not an aggregate function",
+ NameListToString(funcname)),
+ parser_errposition(pstate, location)));
+ if (agg_filter)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("FILTER specified, but %s is not an aggregate function",
+ NameListToString(funcname)),
+ parser_errposition(pstate, location)));
+ if (over)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("OVER specified, but %s is not a window function nor an aggregate function",
+ NameListToString(funcname)),
+ parser_errposition(pstate, location)));
+ }
+
+ /*
+ * So far so good, so do some fdresult-type-specific processing.
+ */
+ if (fdresult == FUNCDETAIL_NORMAL || fdresult == FUNCDETAIL_PROCEDURE)
+ {
+ /* Nothing special to do for these cases. */
+ }
+ else if (fdresult == FUNCDETAIL_AGGREGATE)
+ {
+ /*
+ * It's an aggregate; fetch needed info from the pg_aggregate entry.
+ */
+ HeapTuple tup;
+ Form_pg_aggregate classForm;
+ int catDirectArgs;
+
+ tup = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(funcid));
+ if (!HeapTupleIsValid(tup)) /* should not happen */
+ elog(ERROR, "cache lookup failed for aggregate %u", funcid);
+ classForm = (Form_pg_aggregate) GETSTRUCT(tup);
+ aggkind = classForm->aggkind;
+ catDirectArgs = classForm->aggnumdirectargs;
+ ReleaseSysCache(tup);
+
+ /* Now check various disallowed cases. */
+ if (AGGKIND_IS_ORDERED_SET(aggkind))
+ {
+ int numAggregatedArgs;
+ int numDirectArgs;
+
+ if (!agg_within_group)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("WITHIN GROUP is required for ordered-set aggregate %s",
+ NameListToString(funcname)),
+ parser_errposition(pstate, location)));
+ if (over)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("OVER is not supported for ordered-set aggregate %s",
+ NameListToString(funcname)),
+ parser_errposition(pstate, location)));
+ /* gram.y rejects DISTINCT + WITHIN GROUP */
+ Assert(!agg_distinct);
+ /* gram.y rejects VARIADIC + WITHIN GROUP */
+ Assert(!func_variadic);
+
+ /*
+ * Since func_get_detail was working with an undifferentiated list
+ * of arguments, it might have selected an aggregate that doesn't
+ * really match because it requires a different division of direct
+ * and aggregated arguments. Check that the number of direct
+ * arguments is actually OK; if not, throw an "undefined function"
+ * error, similarly to the case where a misplaced ORDER BY is used
+ * in a regular aggregate call.
+ */
+ numAggregatedArgs = list_length(agg_order);
+ numDirectArgs = nargs - numAggregatedArgs;
+ Assert(numDirectArgs >= 0);
+
+ if (!OidIsValid(vatype))
+ {
+ /* Test is simple if aggregate isn't variadic */
+ if (numDirectArgs != catDirectArgs)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("function %s does not exist",
+ func_signature_string(funcname, nargs,
+ argnames,
+ actual_arg_types)),
+ errhint_plural("There is an ordered-set aggregate %s, but it requires %d direct argument, not %d.",
+ "There is an ordered-set aggregate %s, but it requires %d direct arguments, not %d.",
+ catDirectArgs,
+ NameListToString(funcname),
+ catDirectArgs, numDirectArgs),
+ parser_errposition(pstate, location)));
+ }
+ else
+ {
+ /*
+ * If it's variadic, we have two cases depending on whether
+ * the agg was "... ORDER BY VARIADIC" or "..., VARIADIC ORDER
+ * BY VARIADIC". It's the latter if catDirectArgs equals
+ * pronargs; to save a catalog lookup, we reverse-engineer
+ * pronargs from the info we got from func_get_detail.
+ */
+ int pronargs;
+
+ pronargs = nargs;
+ if (nvargs > 1)
+ pronargs -= nvargs - 1;
+ if (catDirectArgs < pronargs)
+ {
+ /* VARIADIC isn't part of direct args, so still easy */
+ if (numDirectArgs != catDirectArgs)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("function %s does not exist",
+ func_signature_string(funcname, nargs,
+ argnames,
+ actual_arg_types)),
+ errhint_plural("There is an ordered-set aggregate %s, but it requires %d direct argument, not %d.",
+ "There is an ordered-set aggregate %s, but it requires %d direct arguments, not %d.",
+ catDirectArgs,
+ NameListToString(funcname),
+ catDirectArgs, numDirectArgs),
+ parser_errposition(pstate, location)));
+ }
+ else
+ {
+ /*
+ * Both direct and aggregated args were declared variadic.
+ * For a standard ordered-set aggregate, it's okay as long
+ * as there aren't too few direct args. For a
+ * hypothetical-set aggregate, we assume that the
+ * hypothetical arguments are those that matched the
+ * variadic parameter; there must be just as many of them
+ * as there are aggregated arguments.
+ */
+ if (aggkind == AGGKIND_HYPOTHETICAL)
+ {
+ if (nvargs != 2 * numAggregatedArgs)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("function %s does not exist",
+ func_signature_string(funcname, nargs,
+ argnames,
+ actual_arg_types)),
+ errhint("To use the hypothetical-set aggregate %s, the number of hypothetical direct arguments (here %d) must match the number of ordering columns (here %d).",
+ NameListToString(funcname),
+ nvargs - numAggregatedArgs, numAggregatedArgs),
+ parser_errposition(pstate, location)));
+ }
+ else
+ {
+ if (nvargs <= numAggregatedArgs)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("function %s does not exist",
+ func_signature_string(funcname, nargs,
+ argnames,
+ actual_arg_types)),
+ errhint_plural("There is an ordered-set aggregate %s, but it requires at least %d direct argument.",
+ "There is an ordered-set aggregate %s, but it requires at least %d direct arguments.",
+ catDirectArgs,
+ NameListToString(funcname),
+ catDirectArgs),
+ parser_errposition(pstate, location)));
+ }
+ }
+ }
+
+ /* Check type matching of hypothetical arguments */
+ if (aggkind == AGGKIND_HYPOTHETICAL)
+ unify_hypothetical_args(pstate, fargs, numAggregatedArgs,
+ actual_arg_types, declared_arg_types);
+ }
+ else
+ {
+ /* Normal aggregate, so it can't have WITHIN GROUP */
+ if (agg_within_group)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("%s is not an ordered-set aggregate, so it cannot have WITHIN GROUP",
+ NameListToString(funcname)),
+ parser_errposition(pstate, location)));
+ }
+ }
+ else if (fdresult == FUNCDETAIL_WINDOWFUNC)
+ {
+ /*
+ * True window functions must be called with a window definition.
+ */
+ if (!over)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("window function %s requires an OVER clause",
+ NameListToString(funcname)),
+ parser_errposition(pstate, location)));
+ /* And, per spec, WITHIN GROUP isn't allowed */
+ if (agg_within_group)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("window function %s cannot have WITHIN GROUP",
+ NameListToString(funcname)),
+ parser_errposition(pstate, location)));
+ }
+ else if (fdresult == FUNCDETAIL_COERCION)
+ {
+ /*
+ * We interpreted it as a type coercion. coerce_type can handle these
+ * cases, so why duplicate code...
+ */
+ return coerce_type(pstate, linitial(fargs),
+ actual_arg_types[0], rettype, -1,
+ COERCION_EXPLICIT, COERCE_EXPLICIT_CALL, location);
+ }
+ else if (fdresult == FUNCDETAIL_MULTIPLE)
+ {
+ /*
+ * We found multiple possible functional matches. If we are dealing
+ * with attribute notation, return failure, letting the caller report
+ * "no such column" (we already determined there wasn't one). If
+ * dealing with function notation, report "ambiguous function",
+ * regardless of whether there's also a column by this name.
+ */
+ if (is_column)
+ return NULL;
+
+ if (proc_call)
+ ereport(ERROR,
+ (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
+ 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."),
+ parser_errposition(pstate, location)));
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
+ 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."),
+ parser_errposition(pstate, location)));
+ }
+ else
+ {
+ /*
+ * Not found as a function. If we are dealing with attribute
+ * notation, return failure, letting the caller report "no such
+ * column" (we already determined there wasn't one).
+ */
+ if (is_column)
+ return NULL;
+
+ /*
+ * Check for column projection interpretation, since we didn't before.
+ */
+ if (could_be_projection)
+ {
+ retval = ParseComplexProjection(pstate,
+ strVal(linitial(funcname)),
+ first_arg,
+ location);
+ if (retval)
+ return retval;
+ }
+
+ /*
+ * No function, and no column either. Since we're dealing with
+ * function notation, report "function does not exist".
+ */
+ if (list_length(agg_order) > 1 && !agg_within_group)
+ {
+ /* It's agg(x, ORDER BY y,z) ... perhaps misplaced ORDER BY */
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ 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 "
+ "after all regular arguments of the aggregate."),
+ parser_errposition(pstate, location)));
+ }
+ else if (proc_call)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ 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."),
+ parser_errposition(pstate, location)));
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ 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."),
+ parser_errposition(pstate, location)));
+ }
+
+ /*
+ * If there are default arguments, we have to include their types in
+ * actual_arg_types for the purpose of checking generic type consistency.
+ * However, we do NOT put them into the generated parse node, because
+ * their actual values might change before the query gets run. The
+ * planner has to insert the up-to-date values at plan time.
+ */
+ nargsplusdefs = nargs;
+ foreach(l, argdefaults)
+ {
+ Node *expr = (Node *) lfirst(l);
+
+ /* probably shouldn't happen ... */
+ if (nargsplusdefs >= FUNC_MAX_ARGS)
+ ereport(ERROR,
+ (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
+ errmsg_plural("cannot pass more than %d argument to a function",
+ "cannot pass more than %d arguments to a function",
+ FUNC_MAX_ARGS,
+ FUNC_MAX_ARGS),
+ parser_errposition(pstate, location)));
+
+ actual_arg_types[nargsplusdefs++] = exprType(expr);
+ }
+
+ /*
+ * enforce consistency with polymorphic argument and return types,
+ * possibly adjusting return type or declared_arg_types (which will be
+ * used as the cast destination by make_fn_arguments)
+ */
+ rettype = enforce_generic_type_consistency(actual_arg_types,
+ declared_arg_types,
+ nargsplusdefs,
+ rettype,
+ false);
+
+ /* perform the necessary typecasting of arguments */
+ make_fn_arguments(pstate, fargs, actual_arg_types, declared_arg_types);
+
+ /*
+ * If the function isn't actually variadic, forget any VARIADIC decoration
+ * on the call. (Perhaps we should throw an error instead, but
+ * historically we've allowed people to write that.)
+ */
+ if (!OidIsValid(vatype))
+ {
+ Assert(nvargs == 0);
+ func_variadic = false;
+ }
+
+ /*
+ * If it's a variadic function call, transform the last nvargs arguments
+ * into an array --- unless it's an "any" variadic.
+ */
+ if (nvargs > 0 && vatype != ANYOID)
+ {
+ ArrayExpr *newa = makeNode(ArrayExpr);
+ int non_var_args = nargs - nvargs;
+ List *vargs;
+
+ Assert(non_var_args >= 0);
+ vargs = list_copy_tail(fargs, non_var_args);
+ fargs = list_truncate(fargs, non_var_args);
+
+ newa->elements = vargs;
+ /* assume all the variadic arguments were coerced to the same type */
+ newa->element_typeid = exprType((Node *) linitial(vargs));
+ newa->array_typeid = get_array_type(newa->element_typeid);
+ if (!OidIsValid(newa->array_typeid))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("could not find array type for data type %s",
+ format_type_be(newa->element_typeid)),
+ parser_errposition(pstate, exprLocation((Node *) vargs))));
+ /* array_collid will be set by parse_collate.c */
+ newa->multidims = false;
+ newa->location = exprLocation((Node *) vargs);
+
+ fargs = lappend(fargs, newa);
+
+ /* We could not have had VARIADIC marking before ... */
+ Assert(!func_variadic);
+ /* ... but now, it's a VARIADIC call */
+ func_variadic = true;
+ }
+
+ /*
+ * If an "any" variadic is called with explicit VARIADIC marking, insist
+ * that the variadic parameter be of some array type.
+ */
+ if (nargs > 0 && vatype == ANYOID && func_variadic)
+ {
+ Oid va_arr_typid = actual_arg_types[nargs - 1];
+
+ if (!OidIsValid(get_base_element_type(va_arr_typid)))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATATYPE_MISMATCH),
+ errmsg("VARIADIC argument must be an array"),
+ parser_errposition(pstate,
+ exprLocation((Node *) llast(fargs)))));
+ }
+
+ /* if it returns a set, check that's OK */
+ if (retset)
+ check_srf_call_placement(pstate, last_srf, location);
+
+ /* build the appropriate output structure */
+ if (fdresult == FUNCDETAIL_NORMAL || fdresult == FUNCDETAIL_PROCEDURE)
+ {
+ FuncExpr *funcexpr = makeNode(FuncExpr);
+
+ funcexpr->funcid = funcid;
+ funcexpr->funcresulttype = rettype;
+ funcexpr->funcretset = retset;
+ funcexpr->funcvariadic = func_variadic;
+ funcexpr->funcformat = funcformat;
+ /* funccollid and inputcollid will be set by parse_collate.c */
+ funcexpr->args = fargs;
+ funcexpr->location = location;
+
+ retval = (Node *) funcexpr;
+ }
+ else if (fdresult == FUNCDETAIL_AGGREGATE && !over)
+ {
+ /* aggregate function */
+ Aggref *aggref = makeNode(Aggref);
+
+ aggref->aggfnoid = funcid;
+ aggref->aggtype = rettype;
+ /* aggcollid and inputcollid will be set by parse_collate.c */
+ aggref->aggtranstype = InvalidOid; /* will be set by planner */
+ /* aggargtypes will be set by transformAggregateCall */
+ /* aggdirectargs and args will be set by transformAggregateCall */
+ /* aggorder and aggdistinct will be set by transformAggregateCall */
+ aggref->aggfilter = agg_filter;
+ aggref->aggstar = agg_star;
+ aggref->aggvariadic = func_variadic;
+ aggref->aggkind = aggkind;
+ /* agglevelsup will be set by transformAggregateCall */
+ aggref->aggsplit = AGGSPLIT_SIMPLE; /* planner might change this */
+ aggref->aggno = -1; /* planner will set aggno and aggtransno */
+ aggref->aggtransno = -1;
+ aggref->location = location;
+
+ /*
+ * Reject attempt to call a parameterless aggregate without (*)
+ * syntax. This is mere pedantry but some folks insisted ...
+ */
+ if (fargs == NIL && !agg_star && !agg_within_group)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("%s(*) must be used to call a parameterless aggregate function",
+ NameListToString(funcname)),
+ parser_errposition(pstate, location)));
+
+ if (retset)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
+ errmsg("aggregates cannot return sets"),
+ parser_errposition(pstate, location)));
+
+ /*
+ * We might want to support named arguments later, but disallow it for
+ * now. We'd need to figure out the parsed representation (should the
+ * NamedArgExprs go above or below the TargetEntry nodes?) and then
+ * teach the planner to reorder the list properly. Or maybe we could
+ * make transformAggregateCall do that? However, if you'd also like
+ * to allow default arguments for aggregates, we'd need to do it in
+ * planning to avoid semantic problems.
+ */
+ if (argnames != NIL)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("aggregates cannot use named arguments"),
+ parser_errposition(pstate, location)));
+
+ /* parse_agg.c does additional aggregate-specific processing */
+ transformAggregateCall(pstate, aggref, fargs, agg_order, agg_distinct);
+
+ retval = (Node *) aggref;
+ }
+ else
+ {
+ /* window function */
+ WindowFunc *wfunc = makeNode(WindowFunc);
+
+ Assert(over); /* lack of this was checked above */
+ Assert(!agg_within_group); /* also checked above */
+
+ wfunc->winfnoid = funcid;
+ wfunc->wintype = rettype;
+ /* wincollid and inputcollid will be set by parse_collate.c */
+ wfunc->args = fargs;
+ /* winref will be set by transformWindowFuncCall */
+ wfunc->winstar = agg_star;
+ wfunc->winagg = (fdresult == FUNCDETAIL_AGGREGATE);
+ wfunc->aggfilter = agg_filter;
+ wfunc->location = location;
+
+ /*
+ * agg_star is allowed for aggregate functions but distinct isn't
+ */
+ if (agg_distinct)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("DISTINCT is not implemented for window functions"),
+ parser_errposition(pstate, location)));
+
+ /*
+ * Reject attempt to call a parameterless aggregate without (*)
+ * syntax. This is mere pedantry but some folks insisted ...
+ */
+ if (wfunc->winagg && fargs == NIL && !agg_star)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("%s(*) must be used to call a parameterless aggregate function",
+ NameListToString(funcname)),
+ parser_errposition(pstate, location)));
+
+ /*
+ * ordered aggs not allowed in windows yet
+ */
+ if (agg_order != NIL)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("aggregate ORDER BY is not implemented for window functions"),
+ parser_errposition(pstate, location)));
+
+ /*
+ * FILTER is not yet supported with true window functions
+ */
+ if (!wfunc->winagg && agg_filter)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("FILTER is not implemented for non-aggregate window functions"),
+ parser_errposition(pstate, location)));
+
+ /*
+ * Window functions can't either take or return sets
+ */
+ if (pstate->p_last_srf != last_srf)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("window function calls cannot contain set-returning function calls"),
+ errhint("You might be able to move the set-returning function into a LATERAL FROM item."),
+ parser_errposition(pstate,
+ exprLocation(pstate->p_last_srf))));
+
+ if (retset)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
+ errmsg("window functions cannot return sets"),
+ parser_errposition(pstate, location)));
+
+ /* parse_agg.c does additional window-func-specific processing */
+ transformWindowFuncCall(pstate, wfunc, over);
+
+ retval = (Node *) wfunc;
+ }
+
+ /* if it returns a set, remember it for error checks at higher levels */
+ if (retset)
+ pstate->p_last_srf = retval;
+
+ return retval;
+}
+
+
+/* func_match_argtypes()
+ *
+ * Given a list of candidate functions (having the right name and number
+ * of arguments) and an array of input datatype OIDs, produce a shortlist of
+ * those candidates that actually accept the input datatypes (either exactly
+ * or by coercion), and return the number of such candidates.
+ *
+ * Note that can_coerce_type will assume that UNKNOWN inputs are coercible to
+ * anything, so candidates will not be eliminated on that basis.
+ *
+ * NB: okay to modify input list structure, as long as we find at least
+ * one match. If no match at all, the list must remain unmodified.
+ */
+int
+func_match_argtypes(int nargs,
+ Oid *input_typeids,
+ FuncCandidateList raw_candidates,
+ FuncCandidateList *candidates) /* return value */
+{
+ FuncCandidateList current_candidate;
+ FuncCandidateList next_candidate;
+ int ncandidates = 0;
+
+ *candidates = NULL;
+
+ for (current_candidate = raw_candidates;
+ current_candidate != NULL;
+ current_candidate = next_candidate)
+ {
+ next_candidate = current_candidate->next;
+ if (can_coerce_type(nargs, input_typeids, current_candidate->args,
+ COERCION_IMPLICIT))
+ {
+ current_candidate->next = *candidates;
+ *candidates = current_candidate;
+ ncandidates++;
+ }
+ }
+
+ return ncandidates;
+} /* func_match_argtypes() */
+
+
+/* func_select_candidate()
+ * Given the input argtype array and more than one candidate
+ * for the function, attempt to resolve the conflict.
+ *
+ * Returns the selected candidate if the conflict can be resolved,
+ * otherwise returns NULL.
+ *
+ * Note that the caller has already determined that there is no candidate
+ * exactly matching the input argtypes, and has pruned away any "candidates"
+ * that aren't actually coercion-compatible with the input types.
+ *
+ * This is also used for resolving ambiguous operator references. Formerly
+ * parse_oper.c had its own, essentially duplicate code for the purpose.
+ * The following comments (formerly in parse_oper.c) are kept to record some
+ * of the history of these heuristics.
+ *
+ * OLD COMMENTS:
+ *
+ * This routine is new code, replacing binary_oper_select_candidate()
+ * which dates from v4.2/v1.0.x days. It tries very hard to match up
+ * operators with types, including allowing type coercions if necessary.
+ * The important thing is that the code do as much as possible,
+ * while _never_ doing the wrong thing, where "the wrong thing" would
+ * be returning an operator when other better choices are available,
+ * or returning an operator which is a non-intuitive possibility.
+ * - thomas 1998-05-21
+ *
+ * The comments below came from binary_oper_select_candidate(), and
+ * illustrate the issues and choices which are possible:
+ * - thomas 1998-05-20
+ *
+ * current wisdom holds that the default operator should be one in which
+ * both operands have the same type (there will only be one such
+ * operator)
+ *
+ * 7.27.93 - I have decided not to do this; it's too hard to justify, and
+ * it's easy enough to typecast explicitly - avi
+ * [the rest of this routine was commented out since then - ay]
+ *
+ * 6/23/95 - I don't complete agree with avi. In particular, casting
+ * floats is a pain for users. Whatever the rationale behind not doing
+ * this is, I need the following special case to work.
+ *
+ * In the WHERE clause of a query, if a float is specified without
+ * quotes, we treat it as float8. I added the float48* operators so
+ * that we can operate on float4 and float8. But now we have more than
+ * one matching operator if the right arg is unknown (eg. float
+ * specified with quotes). This break some stuff in the regression
+ * test where there are floats in quotes not properly casted. Below is
+ * the solution. In addition to requiring the operator operates on the
+ * same type for both operands [as in the code Avi originally
+ * commented out], we also require that the operators be equivalent in
+ * some sense. (see equivalentOpersAfterPromotion for details.)
+ * - ay 6/95
+ */
+FuncCandidateList
+func_select_candidate(int nargs,
+ Oid *input_typeids,
+ FuncCandidateList candidates)
+{
+ FuncCandidateList current_candidate,
+ first_candidate,
+ last_candidate;
+ Oid *current_typeids;
+ Oid current_type;
+ int i;
+ int ncandidates;
+ int nbestMatch,
+ nmatch,
+ nunknowns;
+ Oid input_base_typeids[FUNC_MAX_ARGS];
+ TYPCATEGORY slot_category[FUNC_MAX_ARGS],
+ current_category;
+ bool current_is_preferred;
+ bool slot_has_preferred_type[FUNC_MAX_ARGS];
+ bool resolved_unknowns;
+
+ /* protect local fixed-size arrays */
+ if (nargs > FUNC_MAX_ARGS)
+ ereport(ERROR,
+ (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
+ errmsg_plural("cannot pass more than %d argument to a function",
+ "cannot pass more than %d arguments to a function",
+ FUNC_MAX_ARGS,
+ FUNC_MAX_ARGS)));
+
+ /*
+ * If any input types are domains, reduce them to their base types. This
+ * ensures that we will consider functions on the base type to be "exact
+ * matches" in the exact-match heuristic; it also makes it possible to do
+ * something useful with the type-category heuristics. Note that this
+ * makes it difficult, but not impossible, to use functions declared to
+ * take a domain as an input datatype. Such a function will be selected
+ * over the base-type function only if it is an exact match at all
+ * argument positions, and so was already chosen by our caller.
+ *
+ * While we're at it, count the number of unknown-type arguments for use
+ * later.
+ */
+ nunknowns = 0;
+ for (i = 0; i < nargs; i++)
+ {
+ if (input_typeids[i] != UNKNOWNOID)
+ input_base_typeids[i] = getBaseType(input_typeids[i]);
+ else
+ {
+ /* no need to call getBaseType on UNKNOWNOID */
+ input_base_typeids[i] = UNKNOWNOID;
+ nunknowns++;
+ }
+ }
+
+ /*
+ * Run through all candidates and keep those with the most matches on
+ * exact types. Keep all candidates if none match.
+ */
+ ncandidates = 0;
+ nbestMatch = 0;
+ last_candidate = NULL;
+ for (current_candidate = candidates;
+ current_candidate != NULL;
+ current_candidate = current_candidate->next)
+ {
+ current_typeids = current_candidate->args;
+ nmatch = 0;
+ for (i = 0; i < nargs; i++)
+ {
+ if (input_base_typeids[i] != UNKNOWNOID &&
+ current_typeids[i] == input_base_typeids[i])
+ nmatch++;
+ }
+
+ /* take this one as the best choice so far? */
+ if ((nmatch > nbestMatch) || (last_candidate == NULL))
+ {
+ nbestMatch = nmatch;
+ candidates = current_candidate;
+ last_candidate = current_candidate;
+ ncandidates = 1;
+ }
+ /* no worse than the last choice, so keep this one too? */
+ else if (nmatch == nbestMatch)
+ {
+ last_candidate->next = current_candidate;
+ last_candidate = current_candidate;
+ ncandidates++;
+ }
+ /* otherwise, don't bother keeping this one... */
+ }
+
+ if (last_candidate) /* terminate rebuilt list */
+ last_candidate->next = NULL;
+
+ if (ncandidates == 1)
+ return candidates;
+
+ /*
+ * Still too many candidates? Now look for candidates which have either
+ * exact matches or preferred types at the args that will require
+ * coercion. (Restriction added in 7.4: preferred type must be of same
+ * category as input type; give no preference to cross-category
+ * conversions to preferred types.) Keep all candidates if none match.
+ */
+ for (i = 0; i < nargs; i++) /* avoid multiple lookups */
+ slot_category[i] = TypeCategory(input_base_typeids[i]);
+ ncandidates = 0;
+ nbestMatch = 0;
+ last_candidate = NULL;
+ for (current_candidate = candidates;
+ current_candidate != NULL;
+ current_candidate = current_candidate->next)
+ {
+ current_typeids = current_candidate->args;
+ nmatch = 0;
+ for (i = 0; i < nargs; i++)
+ {
+ if (input_base_typeids[i] != UNKNOWNOID)
+ {
+ if (current_typeids[i] == input_base_typeids[i] ||
+ IsPreferredType(slot_category[i], current_typeids[i]))
+ nmatch++;
+ }
+ }
+
+ if ((nmatch > nbestMatch) || (last_candidate == NULL))
+ {
+ nbestMatch = nmatch;
+ candidates = current_candidate;
+ last_candidate = current_candidate;
+ ncandidates = 1;
+ }
+ else if (nmatch == nbestMatch)
+ {
+ last_candidate->next = current_candidate;
+ last_candidate = current_candidate;
+ ncandidates++;
+ }
+ }
+
+ if (last_candidate) /* terminate rebuilt list */
+ last_candidate->next = NULL;
+
+ if (ncandidates == 1)
+ return candidates;
+
+ /*
+ * Still too many candidates? Try assigning types for the unknown inputs.
+ *
+ * If there are no unknown inputs, we have no more heuristics that apply,
+ * and must fail.
+ */
+ if (nunknowns == 0)
+ return NULL; /* failed to select a best candidate */
+
+ /*
+ * The next step examines each unknown argument position to see if we can
+ * determine a "type category" for it. If any candidate has an input
+ * datatype of STRING category, use STRING category (this bias towards
+ * STRING is appropriate since unknown-type literals look like strings).
+ * Otherwise, if all the candidates agree on the type category of this
+ * argument position, use that category. Otherwise, fail because we
+ * cannot determine a category.
+ *
+ * If we are able to determine a type category, also notice whether any of
+ * the candidates takes a preferred datatype within the category.
+ *
+ * Having completed this examination, remove candidates that accept the
+ * wrong category at any unknown position. Also, if at least one
+ * candidate accepted a preferred type at a position, remove candidates
+ * that accept non-preferred types. If just one candidate remains, return
+ * that one. However, if this rule turns out to reject all candidates,
+ * keep them all instead.
+ */
+ resolved_unknowns = false;
+ for (i = 0; i < nargs; i++)
+ {
+ bool have_conflict;
+
+ if (input_base_typeids[i] != UNKNOWNOID)
+ continue;
+ resolved_unknowns = true; /* assume we can do it */
+ slot_category[i] = TYPCATEGORY_INVALID;
+ slot_has_preferred_type[i] = false;
+ have_conflict = false;
+ for (current_candidate = candidates;
+ current_candidate != NULL;
+ current_candidate = current_candidate->next)
+ {
+ current_typeids = current_candidate->args;
+ current_type = current_typeids[i];
+ get_type_category_preferred(current_type,
+ &current_category,
+ &current_is_preferred);
+ if (slot_category[i] == TYPCATEGORY_INVALID)
+ {
+ /* first candidate */
+ slot_category[i] = current_category;
+ slot_has_preferred_type[i] = current_is_preferred;
+ }
+ else if (current_category == slot_category[i])
+ {
+ /* more candidates in same category */
+ slot_has_preferred_type[i] |= current_is_preferred;
+ }
+ else
+ {
+ /* category conflict! */
+ if (current_category == TYPCATEGORY_STRING)
+ {
+ /* STRING always wins if available */
+ slot_category[i] = current_category;
+ slot_has_preferred_type[i] = current_is_preferred;
+ }
+ else
+ {
+ /*
+ * Remember conflict, but keep going (might find STRING)
+ */
+ have_conflict = true;
+ }
+ }
+ }
+ if (have_conflict && slot_category[i] != TYPCATEGORY_STRING)
+ {
+ /* Failed to resolve category conflict at this position */
+ resolved_unknowns = false;
+ break;
+ }
+ }
+
+ if (resolved_unknowns)
+ {
+ /* Strip non-matching candidates */
+ ncandidates = 0;
+ first_candidate = candidates;
+ last_candidate = NULL;
+ for (current_candidate = candidates;
+ current_candidate != NULL;
+ current_candidate = current_candidate->next)
+ {
+ bool keepit = true;
+
+ current_typeids = current_candidate->args;
+ for (i = 0; i < nargs; i++)
+ {
+ if (input_base_typeids[i] != UNKNOWNOID)
+ continue;
+ current_type = current_typeids[i];
+ get_type_category_preferred(current_type,
+ &current_category,
+ &current_is_preferred);
+ if (current_category != slot_category[i])
+ {
+ keepit = false;
+ break;
+ }
+ if (slot_has_preferred_type[i] && !current_is_preferred)
+ {
+ keepit = false;
+ break;
+ }
+ }
+ if (keepit)
+ {
+ /* keep this candidate */
+ last_candidate = current_candidate;
+ ncandidates++;
+ }
+ else
+ {
+ /* forget this candidate */
+ if (last_candidate)
+ last_candidate->next = current_candidate->next;
+ else
+ first_candidate = current_candidate->next;
+ }
+ }
+
+ /* if we found any matches, restrict our attention to those */
+ if (last_candidate)
+ {
+ candidates = first_candidate;
+ /* terminate rebuilt list */
+ last_candidate->next = NULL;
+ }
+
+ if (ncandidates == 1)
+ return candidates;
+ }
+
+ /*
+ * Last gasp: if there are both known- and unknown-type inputs, and all
+ * the known types are the same, assume the unknown inputs are also that
+ * type, and see if that gives us a unique match. If so, use that match.
+ *
+ * NOTE: for a binary operator with one unknown and one non-unknown input,
+ * we already tried this heuristic in binary_oper_exact(). However, that
+ * code only finds exact matches, whereas here we will handle matches that
+ * involve coercion, polymorphic type resolution, etc.
+ */
+ if (nunknowns < nargs)
+ {
+ Oid known_type = UNKNOWNOID;
+
+ for (i = 0; i < nargs; i++)
+ {
+ if (input_base_typeids[i] == UNKNOWNOID)
+ continue;
+ if (known_type == UNKNOWNOID) /* first known arg? */
+ known_type = input_base_typeids[i];
+ else if (known_type != input_base_typeids[i])
+ {
+ /* oops, not all match */
+ known_type = UNKNOWNOID;
+ break;
+ }
+ }
+
+ if (known_type != UNKNOWNOID)
+ {
+ /* okay, just one known type, apply the heuristic */
+ for (i = 0; i < nargs; i++)
+ input_base_typeids[i] = known_type;
+ ncandidates = 0;
+ last_candidate = NULL;
+ for (current_candidate = candidates;
+ current_candidate != NULL;
+ current_candidate = current_candidate->next)
+ {
+ current_typeids = current_candidate->args;
+ if (can_coerce_type(nargs, input_base_typeids, current_typeids,
+ COERCION_IMPLICIT))
+ {
+ if (++ncandidates > 1)
+ break; /* not unique, give up */
+ last_candidate = current_candidate;
+ }
+ }
+ if (ncandidates == 1)
+ {
+ /* successfully identified a unique match */
+ last_candidate->next = NULL;
+ return last_candidate;
+ }
+ }
+ }
+
+ return NULL; /* failed to select a best candidate */
+} /* func_select_candidate() */
+
+
+/* func_get_detail()
+ *
+ * Find the named function in the system catalogs.
+ *
+ * Attempt to find the named function in the system catalogs with
+ * arguments exactly as specified, so that the normal case (exact match)
+ * is as quick as possible.
+ *
+ * If an exact match isn't found:
+ * 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.
+ *
+ * When processing a named- or mixed-notation call (ie, fargnames isn't NIL),
+ * the returned true_typeids and argdefaults are ordered according to the
+ * call's argument ordering: first any positional arguments, then the named
+ * arguments, then defaulted arguments (if needed and allowed by
+ * expand_defaults). Some care is needed if this information is to be compared
+ * to the function's pg_proc entry, but in practice the caller can usually
+ * just work with the call's argument ordering.
+ *
+ * We rely primarily on fargnames/nargs/argtypes as the argument description.
+ * The actual expression node list is passed in fargs so that we can check
+ * for type coercion of a constant. Some callers pass fargs == NIL indicating
+ * they don't need that check made. Note also that when fargnames isn't NIL,
+ * the fargs list must be passed if the caller wants actual argument position
+ * information to be returned into the NamedArgExpr nodes.
+ */
+FuncDetailCode
+func_get_detail(List *funcname,
+ List *fargs,
+ List *fargnames,
+ int nargs,
+ Oid *argtypes,
+ bool expand_variadic,
+ bool expand_defaults,
+ bool include_out_arguments,
+ Oid *funcid, /* return value */
+ Oid *rettype, /* return value */
+ bool *retset, /* return value */
+ int *nvargs, /* return value */
+ Oid *vatype, /* return value */
+ Oid **true_typeids, /* return value */
+ List **argdefaults) /* optional return value */
+{
+ FuncCandidateList raw_candidates;
+ FuncCandidateList best_candidate;
+
+ /* initialize output arguments to silence compiler warnings */
+ *funcid = InvalidOid;
+ *rettype = InvalidOid;
+ *retset = false;
+ *nvargs = 0;
+ *vatype = InvalidOid;
+ *true_typeids = NULL;
+ if (argdefaults)
+ *argdefaults = NIL;
+
+ /* Get list of possible candidates from namespace search */
+ raw_candidates = FuncnameGetCandidates(funcname, nargs, fargnames,
+ expand_variadic, expand_defaults,
+ include_out_arguments, false);
+
+ /*
+ * Quickly check if there is an exact match to the input datatypes (there
+ * can be only one)
+ */
+ for (best_candidate = raw_candidates;
+ best_candidate != NULL;
+ best_candidate = best_candidate->next)
+ {
+ /* if nargs==0, argtypes can be null; don't pass that to memcmp */
+ if (nargs == 0 ||
+ memcmp(argtypes, best_candidate->args, nargs * sizeof(Oid)) == 0)
+ break;
+ }
+
+ if (best_candidate == NULL)
+ {
+ /*
+ * If we didn't find an exact match, next consider the possibility
+ * that this is really a type-coercion request: a single-argument
+ * function call where the function name is a type name. If so, and
+ * if the coercion path is RELABELTYPE or COERCEVIAIO, then go ahead
+ * and treat the "function call" as a coercion.
+ *
+ * This interpretation needs to be given higher priority than
+ * interpretations involving a type coercion followed by a function
+ * call, otherwise we can produce surprising results. For example, we
+ * want "text(varchar)" to be interpreted as a simple coercion, not as
+ * "text(name(varchar))" which the code below this point is entirely
+ * capable of selecting.
+ *
+ * We also treat a coercion of a previously-unknown-type literal
+ * constant to a specific type this way.
+ *
+ * The reason we reject COERCION_PATH_FUNC here is that we expect the
+ * cast implementation function to be named after the target type.
+ * Thus the function will be found by normal lookup if appropriate.
+ *
+ * The reason we reject COERCION_PATH_ARRAYCOERCE is mainly that you
+ * can't write "foo[] (something)" as a function call. In theory
+ * someone might want to invoke it as "_foo (something)" but we have
+ * never supported that historically, so we can insist that people
+ * write it as a normal cast instead.
+ *
+ * We also reject the specific case of COERCEVIAIO for a composite
+ * source type and a string-category target type. This is a case that
+ * find_coercion_pathway() allows by default, but experience has shown
+ * that it's too commonly invoked by mistake. So, again, insist that
+ * people use cast syntax if they want to do that.
+ *
+ * NB: it's important that this code does not exceed what coerce_type
+ * can do, because the caller will try to apply coerce_type if we
+ * return FUNCDETAIL_COERCION. If we return that result for something
+ * coerce_type can't handle, we'll cause infinite recursion between
+ * this module and coerce_type!
+ */
+ if (nargs == 1 && fargs != NIL && fargnames == NIL)
+ {
+ Oid targetType = FuncNameAsType(funcname);
+
+ if (OidIsValid(targetType))
+ {
+ Oid sourceType = argtypes[0];
+ Node *arg1 = linitial(fargs);
+ bool iscoercion;
+
+ if (sourceType == UNKNOWNOID && IsA(arg1, Const))
+ {
+ /* always treat typename('literal') as coercion */
+ iscoercion = true;
+ }
+ else
+ {
+ CoercionPathType cpathtype;
+ Oid cfuncid;
+
+ cpathtype = find_coercion_pathway(targetType, sourceType,
+ COERCION_EXPLICIT,
+ &cfuncid);
+ switch (cpathtype)
+ {
+ case COERCION_PATH_RELABELTYPE:
+ iscoercion = true;
+ break;
+ case COERCION_PATH_COERCEVIAIO:
+ if ((sourceType == RECORDOID ||
+ ISCOMPLEX(sourceType)) &&
+ TypeCategory(targetType) == TYPCATEGORY_STRING)
+ iscoercion = false;
+ else
+ iscoercion = true;
+ break;
+ default:
+ iscoercion = false;
+ break;
+ }
+ }
+
+ if (iscoercion)
+ {
+ /* Treat it as a type coercion */
+ *funcid = InvalidOid;
+ *rettype = targetType;
+ *retset = false;
+ *nvargs = 0;
+ *vatype = InvalidOid;
+ *true_typeids = argtypes;
+ return FUNCDETAIL_COERCION;
+ }
+ }
+ }
+
+ /*
+ * didn't find an exact match, so now try to match up candidates...
+ */
+ if (raw_candidates != NULL)
+ {
+ FuncCandidateList current_candidates;
+ int ncandidates;
+
+ ncandidates = func_match_argtypes(nargs,
+ argtypes,
+ raw_candidates,
+ &current_candidates);
+
+ /* one match only? then run with it... */
+ if (ncandidates == 1)
+ best_candidate = current_candidates;
+
+ /*
+ * multiple candidates? then better decide or throw an error...
+ */
+ else if (ncandidates > 1)
+ {
+ best_candidate = func_select_candidate(nargs,
+ argtypes,
+ current_candidates);
+
+ /*
+ * If we were able to choose a best candidate, we're done.
+ * Otherwise, ambiguous function call.
+ */
+ if (!best_candidate)
+ return FUNCDETAIL_MULTIPLE;
+ }
+ }
+ }
+
+ if (best_candidate)
+ {
+ HeapTuple ftup;
+ Form_pg_proc pform;
+ FuncDetailCode result;
+
+ /*
+ * If processing named args or expanding variadics or defaults, the
+ * "best candidate" might represent multiple equivalently good
+ * functions; treat this case as ambiguous.
+ */
+ if (!OidIsValid(best_candidate->oid))
+ return FUNCDETAIL_MULTIPLE;
+
+ /*
+ * We disallow VARIADIC with named arguments unless the last argument
+ * (the one with VARIADIC attached) actually matched the variadic
+ * parameter. This is mere pedantry, really, but some folks insisted.
+ */
+ if (fargnames != NIL && !expand_variadic && nargs > 0 &&
+ best_candidate->argnumbers[nargs - 1] != nargs - 1)
+ return FUNCDETAIL_NOTFOUND;
+
+ *funcid = best_candidate->oid;
+ *nvargs = best_candidate->nvargs;
+ *true_typeids = best_candidate->args;
+
+ /*
+ * If processing named args, return actual argument positions into
+ * NamedArgExpr nodes in the fargs list. This is a bit ugly but not
+ * worth the extra notation needed to do it differently.
+ */
+ if (best_candidate->argnumbers != NULL)
+ {
+ int i = 0;
+ ListCell *lc;
+
+ foreach(lc, fargs)
+ {
+ NamedArgExpr *na = (NamedArgExpr *) lfirst(lc);
+
+ if (IsA(na, NamedArgExpr))
+ na->argnumber = best_candidate->argnumbers[i];
+ i++;
+ }
+ }
+
+ ftup = SearchSysCache1(PROCOID,
+ ObjectIdGetDatum(best_candidate->oid));
+ if (!HeapTupleIsValid(ftup)) /* should not happen */
+ elog(ERROR, "cache lookup failed for function %u",
+ best_candidate->oid);
+ pform = (Form_pg_proc) GETSTRUCT(ftup);
+ *rettype = pform->prorettype;
+ *retset = pform->proretset;
+ *vatype = pform->provariadic;
+ /* fetch default args if caller wants 'em */
+ if (argdefaults && best_candidate->ndargs > 0)
+ {
+ Datum proargdefaults;
+ bool isnull;
+ char *str;
+ List *defaults;
+
+ /* shouldn't happen, FuncnameGetCandidates messed up */
+ if (best_candidate->ndargs > pform->pronargdefaults)
+ elog(ERROR, "not enough default arguments");
+
+ proargdefaults = SysCacheGetAttr(PROCOID, ftup,
+ Anum_pg_proc_proargdefaults,
+ &isnull);
+ Assert(!isnull);
+ str = TextDatumGetCString(proargdefaults);
+ defaults = castNode(List, stringToNode(str));
+ pfree(str);
+
+ /* Delete any unused defaults from the returned list */
+ if (best_candidate->argnumbers != NULL)
+ {
+ /*
+ * This is a bit tricky in named notation, since the supplied
+ * arguments could replace any subset of the defaults. We
+ * work by making a bitmapset of the argnumbers of defaulted
+ * arguments, then scanning the defaults list and selecting
+ * the needed items. (This assumes that defaulted arguments
+ * should be supplied in their positional order.)
+ */
+ Bitmapset *defargnumbers;
+ int *firstdefarg;
+ List *newdefaults;
+ ListCell *lc;
+ int i;
+
+ defargnumbers = NULL;
+ firstdefarg = &best_candidate->argnumbers[best_candidate->nargs - best_candidate->ndargs];
+ for (i = 0; i < best_candidate->ndargs; i++)
+ defargnumbers = bms_add_member(defargnumbers,
+ firstdefarg[i]);
+ newdefaults = NIL;
+ i = best_candidate->nominalnargs - pform->pronargdefaults;
+ foreach(lc, defaults)
+ {
+ if (bms_is_member(i, defargnumbers))
+ newdefaults = lappend(newdefaults, lfirst(lc));
+ i++;
+ }
+ Assert(list_length(newdefaults) == best_candidate->ndargs);
+ bms_free(defargnumbers);
+ *argdefaults = newdefaults;
+ }
+ else
+ {
+ /*
+ * Defaults for positional notation are lots easier; just
+ * remove any unwanted ones from the front.
+ */
+ int ndelete;
+
+ ndelete = list_length(defaults) - best_candidate->ndargs;
+ if (ndelete > 0)
+ defaults = list_delete_first_n(defaults, ndelete);
+ *argdefaults = defaults;
+ }
+ }
+
+ switch (pform->prokind)
+ {
+ case PROKIND_AGGREGATE:
+ result = FUNCDETAIL_AGGREGATE;
+ break;
+ case PROKIND_FUNCTION:
+ result = FUNCDETAIL_NORMAL;
+ break;
+ case PROKIND_PROCEDURE:
+ result = FUNCDETAIL_PROCEDURE;
+ break;
+ case PROKIND_WINDOW:
+ result = FUNCDETAIL_WINDOWFUNC;
+ break;
+ default:
+ elog(ERROR, "unrecognized prokind: %c", pform->prokind);
+ result = FUNCDETAIL_NORMAL; /* keep compiler quiet */
+ break;
+ }
+
+ ReleaseSysCache(ftup);
+ return result;
+ }
+
+ return FUNCDETAIL_NOTFOUND;
+}
+
+
+/*
+ * unify_hypothetical_args()
+ *
+ * Ensure that each hypothetical direct argument of a hypothetical-set
+ * aggregate has the same type as the corresponding aggregated argument.
+ * Modify the expressions in the fargs list, if necessary, and update
+ * actual_arg_types[].
+ *
+ * If the agg declared its args non-ANY (even ANYELEMENT), we need only a
+ * sanity check that the declared types match; make_fn_arguments will coerce
+ * the actual arguments to match the declared ones. But if the declaration
+ * is ANY, nothing will happen in make_fn_arguments, so we need to fix any
+ * mismatch here. We use the same type resolution logic as UNION etc.
+ */
+static void
+unify_hypothetical_args(ParseState *pstate,
+ List *fargs,
+ int numAggregatedArgs,
+ Oid *actual_arg_types,
+ Oid *declared_arg_types)
+{
+ int numDirectArgs,
+ numNonHypotheticalArgs;
+ int hargpos;
+
+ numDirectArgs = list_length(fargs) - numAggregatedArgs;
+ numNonHypotheticalArgs = numDirectArgs - numAggregatedArgs;
+ /* safety check (should only trigger with a misdeclared agg) */
+ if (numNonHypotheticalArgs < 0)
+ elog(ERROR, "incorrect number of arguments to hypothetical-set aggregate");
+
+ /* Check each hypothetical arg and corresponding aggregated arg */
+ for (hargpos = numNonHypotheticalArgs; hargpos < numDirectArgs; hargpos++)
+ {
+ int aargpos = numDirectArgs + (hargpos - numNonHypotheticalArgs);
+ ListCell *harg = list_nth_cell(fargs, hargpos);
+ ListCell *aarg = list_nth_cell(fargs, aargpos);
+ Oid commontype;
+ int32 commontypmod;
+
+ /* A mismatch means AggregateCreate didn't check properly ... */
+ if (declared_arg_types[hargpos] != declared_arg_types[aargpos])
+ elog(ERROR, "hypothetical-set aggregate has inconsistent declared argument types");
+
+ /* No need to unify if make_fn_arguments will coerce */
+ if (declared_arg_types[hargpos] != ANYOID)
+ continue;
+
+ /*
+ * Select common type, giving preference to the aggregated argument's
+ * type (we'd rather coerce the direct argument once than coerce all
+ * the aggregated values).
+ */
+ commontype = select_common_type(pstate,
+ list_make2(lfirst(aarg), lfirst(harg)),
+ "WITHIN GROUP",
+ NULL);
+ commontypmod = select_common_typmod(pstate,
+ list_make2(lfirst(aarg), lfirst(harg)),
+ commontype);
+
+ /*
+ * Perform the coercions. We don't need to worry about NamedArgExprs
+ * here because they aren't supported with aggregates.
+ */
+ lfirst(harg) = coerce_type(pstate,
+ (Node *) lfirst(harg),
+ actual_arg_types[hargpos],
+ commontype, commontypmod,
+ COERCION_IMPLICIT,
+ COERCE_IMPLICIT_CAST,
+ -1);
+ actual_arg_types[hargpos] = commontype;
+ lfirst(aarg) = coerce_type(pstate,
+ (Node *) lfirst(aarg),
+ actual_arg_types[aargpos],
+ commontype, commontypmod,
+ COERCION_IMPLICIT,
+ COERCE_IMPLICIT_CAST,
+ -1);
+ actual_arg_types[aargpos] = commontype;
+ }
+}
+
+
+/*
+ * make_fn_arguments()
+ *
+ * Given the actual argument expressions for a function, and the desired
+ * input types for the function, add any necessary typecasting to the
+ * expression tree. Caller should already have verified that casting is
+ * allowed.
+ *
+ * Caution: given argument list is modified in-place.
+ *
+ * As with coerce_type, pstate may be NULL if no special unknown-Param
+ * processing is wanted.
+ */
+void
+make_fn_arguments(ParseState *pstate,
+ List *fargs,
+ Oid *actual_arg_types,
+ Oid *declared_arg_types)
+{
+ ListCell *current_fargs;
+ int i = 0;
+
+ foreach(current_fargs, fargs)
+ {
+ /* types don't match? then force coercion using a function call... */
+ if (actual_arg_types[i] != declared_arg_types[i])
+ {
+ Node *node = (Node *) lfirst(current_fargs);
+
+ /*
+ * If arg is a NamedArgExpr, coerce its input expr instead --- we
+ * want the NamedArgExpr to stay at the top level of the list.
+ */
+ if (IsA(node, NamedArgExpr))
+ {
+ NamedArgExpr *na = (NamedArgExpr *) node;
+
+ node = coerce_type(pstate,
+ (Node *) na->arg,
+ actual_arg_types[i],
+ declared_arg_types[i], -1,
+ COERCION_IMPLICIT,
+ COERCE_IMPLICIT_CAST,
+ -1);
+ na->arg = (Expr *) node;
+ }
+ else
+ {
+ node = coerce_type(pstate,
+ node,
+ actual_arg_types[i],
+ declared_arg_types[i], -1,
+ COERCION_IMPLICIT,
+ COERCE_IMPLICIT_CAST,
+ -1);
+ lfirst(current_fargs) = node;
+ }
+ }
+ i++;
+ }
+}
+
+/*
+ * FuncNameAsType -
+ * convenience routine to see if a function name matches a type name
+ *
+ * Returns the OID of the matching type, or InvalidOid if none. We ignore
+ * shell types and complex types.
+ */
+static Oid
+FuncNameAsType(List *funcname)
+{
+ Oid result;
+ Type typtup;
+
+ /*
+ * temp_ok=false protects the <refsect1 id="sql-createfunction-security">
+ * contract for writing SECURITY DEFINER functions safely.
+ */
+ typtup = LookupTypeNameExtended(NULL, makeTypeNameFromNameList(funcname),
+ NULL, false, false);
+ if (typtup == NULL)
+ return InvalidOid;
+
+ if (((Form_pg_type) GETSTRUCT(typtup))->typisdefined &&
+ !OidIsValid(typeTypeRelid(typtup)))
+ result = typeTypeId(typtup);
+ else
+ result = InvalidOid;
+
+ ReleaseSysCache(typtup);
+ return result;
+}
+
+/*
+ * ParseComplexProjection -
+ * handles function calls with a single argument that is of complex type.
+ * If the function call is actually a column projection, return a suitably
+ * transformed expression tree. If not, return NULL.
+ */
+static Node *
+ParseComplexProjection(ParseState *pstate, const char *funcname, Node *first_arg,
+ int location)
+{
+ TupleDesc tupdesc;
+ int i;
+
+ /*
+ * Special case for whole-row Vars so that we can resolve (foo.*).bar even
+ * when foo is a reference to a subselect, join, or RECORD function. A
+ * bonus is that we avoid generating an unnecessary FieldSelect; our
+ * result can omit the whole-row Var and just be a Var for the selected
+ * field.
+ *
+ * This case could be handled by expandRecordVariable, but it's more
+ * efficient to do it this way when possible.
+ */
+ if (IsA(first_arg, Var) &&
+ ((Var *) first_arg)->varattno == InvalidAttrNumber)
+ {
+ ParseNamespaceItem *nsitem;
+
+ nsitem = GetNSItemByRangeTablePosn(pstate,
+ ((Var *) first_arg)->varno,
+ ((Var *) first_arg)->varlevelsup);
+ /* Return a Var if funcname matches a column, else NULL */
+ return scanNSItemForColumn(pstate, nsitem,
+ ((Var *) first_arg)->varlevelsup,
+ funcname, location);
+ }
+
+ /*
+ * Else do it the hard way with get_expr_result_tupdesc().
+ *
+ * If it's a Var of type RECORD, we have to work even harder: we have to
+ * find what the Var refers to, and pass that to get_expr_result_tupdesc.
+ * That task is handled by expandRecordVariable().
+ */
+ if (IsA(first_arg, Var) &&
+ ((Var *) first_arg)->vartype == RECORDOID)
+ tupdesc = expandRecordVariable(pstate, (Var *) first_arg, 0);
+ else
+ tupdesc = get_expr_result_tupdesc(first_arg, true);
+ if (!tupdesc)
+ return NULL; /* unresolvable RECORD type */
+
+ for (i = 0; i < tupdesc->natts; i++)
+ {
+ Form_pg_attribute att = TupleDescAttr(tupdesc, i);
+
+ if (strcmp(funcname, NameStr(att->attname)) == 0 &&
+ !att->attisdropped)
+ {
+ /* Success, so generate a FieldSelect expression */
+ FieldSelect *fselect = makeNode(FieldSelect);
+
+ fselect->arg = (Expr *) first_arg;
+ fselect->fieldnum = i + 1;
+ fselect->resulttype = att->atttypid;
+ fselect->resulttypmod = att->atttypmod;
+ /* save attribute's collation for parse_collate.c */
+ fselect->resultcollid = att->attcollation;
+ return (Node *) fselect;
+ }
+ }
+
+ return NULL; /* funcname does not match any column */
+}
+
+/*
+ * funcname_signature_string
+ * Build a string representing a function name, including arg types.
+ * The result is something like "foo(integer)".
+ *
+ * If argnames isn't NIL, it is a list of C strings representing the actual
+ * arg names for the last N arguments. This must be considered part of the
+ * function signature too, when dealing with named-notation function calls.
+ *
+ * This is typically used in the construction of function-not-found error
+ * messages.
+ */
+const char *
+funcname_signature_string(const char *funcname, int nargs,
+ List *argnames, const Oid *argtypes)
+{
+ StringInfoData argbuf;
+ int numposargs;
+ ListCell *lc;
+ int i;
+
+ initStringInfo(&argbuf);
+
+ appendStringInfo(&argbuf, "%s(", funcname);
+
+ numposargs = nargs - list_length(argnames);
+ lc = list_head(argnames);
+
+ for (i = 0; i < nargs; i++)
+ {
+ if (i)
+ appendStringInfoString(&argbuf, ", ");
+ if (i >= numposargs)
+ {
+ appendStringInfo(&argbuf, "%s => ", (char *) lfirst(lc));
+ lc = lnext(argnames, lc);
+ }
+ appendStringInfoString(&argbuf, format_type_be(argtypes[i]));
+ }
+
+ appendStringInfoChar(&argbuf, ')');
+
+ return argbuf.data; /* return palloc'd string buffer */
+}
+
+/*
+ * func_signature_string
+ * As above, but function name is passed as a qualified name list.
+ */
+const char *
+func_signature_string(List *funcname, int nargs,
+ List *argnames, const Oid *argtypes)
+{
+ return funcname_signature_string(NameListToString(funcname),
+ nargs, argnames, argtypes);
+}
+
+/*
+ * LookupFuncNameInternal
+ * Workhorse for LookupFuncName/LookupFuncWithArgs
+ *
+ * In an error situation, e.g. can't find the function, then we return
+ * InvalidOid and set *lookupError to indicate what went wrong.
+ *
+ * Possible errors:
+ * FUNCLOOKUP_NOSUCHFUNC: we can't find a function of this name.
+ * FUNCLOOKUP_AMBIGUOUS: more than one function matches.
+ */
+static Oid
+LookupFuncNameInternal(ObjectType objtype, List *funcname,
+ int nargs, const Oid *argtypes,
+ bool include_out_arguments, bool missing_ok,
+ FuncLookupError *lookupError)
+{
+ Oid result = InvalidOid;
+ FuncCandidateList clist;
+
+ /* NULL argtypes allowed for nullary functions only */
+ Assert(argtypes != NULL || nargs == 0);
+
+ /* Always set *lookupError, to forestall uninitialized-variable warnings */
+ *lookupError = FUNCLOOKUP_NOSUCHFUNC;
+
+ /* Get list of candidate objects */
+ clist = FuncnameGetCandidates(funcname, nargs, NIL, false, false,
+ include_out_arguments, missing_ok);
+
+ /* Scan list for a match to the arg types (if specified) and the objtype */
+ for (; clist != NULL; clist = clist->next)
+ {
+ /* Check arg type match, if specified */
+ if (nargs >= 0)
+ {
+ /* if nargs==0, argtypes can be null; don't pass that to memcmp */
+ if (nargs > 0 &&
+ memcmp(argtypes, clist->args, nargs * sizeof(Oid)) != 0)
+ continue;
+ }
+
+ /* Check for duplicates reported by FuncnameGetCandidates */
+ if (!OidIsValid(clist->oid))
+ {
+ *lookupError = FUNCLOOKUP_AMBIGUOUS;
+ return InvalidOid;
+ }
+
+ /* Check objtype match, if specified */
+ switch (objtype)
+ {
+ case OBJECT_FUNCTION:
+ case OBJECT_AGGREGATE:
+ /* Ignore procedures */
+ if (get_func_prokind(clist->oid) == PROKIND_PROCEDURE)
+ continue;
+ break;
+ case OBJECT_PROCEDURE:
+ /* Ignore non-procedures */
+ if (get_func_prokind(clist->oid) != PROKIND_PROCEDURE)
+ continue;
+ break;
+ case OBJECT_ROUTINE:
+ /* no restriction */
+ break;
+ default:
+ Assert(false);
+ }
+
+ /* Check for multiple matches */
+ if (OidIsValid(result))
+ {
+ *lookupError = FUNCLOOKUP_AMBIGUOUS;
+ return InvalidOid;
+ }
+
+ /* OK, we have a candidate */
+ result = clist->oid;
+ }
+
+ return result;
+}
+
+/*
+ * LookupFuncName
+ *
+ * Given a possibly-qualified function name and optionally a set of argument
+ * types, look up the function. Pass nargs == -1 to indicate that the number
+ * and types of the arguments are unspecified (this is NOT the same as
+ * specifying that there are no arguments).
+ *
+ * If the function name is not schema-qualified, it is sought in the current
+ * namespace search path.
+ *
+ * If the function is not found, we return InvalidOid if missing_ok is true,
+ * else raise an error.
+ *
+ * If nargs == -1 and multiple functions are found matching this function name
+ * we will raise an ambiguous-function error, regardless of what missing_ok is
+ * set to.
+ *
+ * Only functions will be found; procedures will be ignored even if they
+ * match the name and argument types. (However, we don't trouble to reject
+ * aggregates or window functions here.)
+ */
+Oid
+LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool missing_ok)
+{
+ Oid funcoid;
+ FuncLookupError lookupError;
+
+ funcoid = LookupFuncNameInternal(OBJECT_FUNCTION,
+ funcname, nargs, argtypes,
+ false, missing_ok,
+ &lookupError);
+
+ if (OidIsValid(funcoid))
+ return funcoid;
+
+ switch (lookupError)
+ {
+ case FUNCLOOKUP_NOSUCHFUNC:
+ /* Let the caller deal with it when missing_ok is true */
+ if (missing_ok)
+ return InvalidOid;
+
+ if (nargs < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("could not find a function named \"%s\"",
+ NameListToString(funcname))));
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("function %s does not exist",
+ func_signature_string(funcname, nargs,
+ NIL, argtypes))));
+ break;
+
+ case FUNCLOOKUP_AMBIGUOUS:
+ /* Raise an error regardless of missing_ok */
+ ereport(ERROR,
+ (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
+ errmsg("function name \"%s\" is not unique",
+ NameListToString(funcname)),
+ errhint("Specify the argument list to select the function unambiguously.")));
+ break;
+ }
+
+ return InvalidOid; /* Keep compiler quiet */
+}
+
+/*
+ * LookupFuncWithArgs
+ *
+ * Like LookupFuncName, but the argument types are specified by an
+ * ObjectWithArgs node. Also, this function can check whether the result is a
+ * function, procedure, or aggregate, based on the objtype argument. Pass
+ * OBJECT_ROUTINE to accept any of them.
+ *
+ * For historical reasons, we also accept aggregates when looking for a
+ * function.
+ *
+ * When missing_ok is true we don't generate any error for missing objects and
+ * return InvalidOid. Other types of errors can still be raised, regardless
+ * of the value of missing_ok.
+ */
+Oid
+LookupFuncWithArgs(ObjectType objtype, ObjectWithArgs *func, bool missing_ok)
+{
+ Oid argoids[FUNC_MAX_ARGS];
+ int argcount;
+ int nargs;
+ int i;
+ ListCell *args_item;
+ Oid oid;
+ FuncLookupError lookupError;
+
+ Assert(objtype == OBJECT_AGGREGATE ||
+ objtype == OBJECT_FUNCTION ||
+ objtype == OBJECT_PROCEDURE ||
+ objtype == OBJECT_ROUTINE);
+
+ argcount = list_length(func->objargs);
+ if (argcount > FUNC_MAX_ARGS)
+ {
+ if (objtype == OBJECT_PROCEDURE)
+ ereport(ERROR,
+ (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
+ errmsg_plural("procedures cannot have more than %d argument",
+ "procedures cannot have more than %d arguments",
+ FUNC_MAX_ARGS,
+ FUNC_MAX_ARGS)));
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
+ errmsg_plural("functions cannot have more than %d argument",
+ "functions cannot have more than %d arguments",
+ FUNC_MAX_ARGS,
+ FUNC_MAX_ARGS)));
+ }
+
+ /*
+ * First, perform a lookup considering only input arguments (traditional
+ * Postgres rules).
+ */
+ i = 0;
+ foreach(args_item, func->objargs)
+ {
+ TypeName *t = lfirst_node(TypeName, args_item);
+
+ argoids[i] = LookupTypeNameOid(NULL, t, missing_ok);
+ if (!OidIsValid(argoids[i]))
+ return InvalidOid; /* missing_ok must be true */
+ i++;
+ }
+
+ /*
+ * Set nargs for LookupFuncNameInternal. It expects -1 to mean no args
+ * were specified.
+ */
+ nargs = func->args_unspecified ? -1 : argcount;
+
+ /*
+ * In args_unspecified mode, also tell LookupFuncNameInternal to consider
+ * the object type, since there seems no reason not to. However, if we
+ * have an argument list, disable the objtype check, because we'd rather
+ * complain about "object is of wrong type" than "object doesn't exist".
+ * (Note that with args, FuncnameGetCandidates will have ensured there's
+ * only one argtype match, so we're not risking an ambiguity failure via
+ * this choice.)
+ */
+ oid = LookupFuncNameInternal(func->args_unspecified ? objtype : OBJECT_ROUTINE,
+ func->objname, nargs, argoids,
+ false, missing_ok,
+ &lookupError);
+
+ /*
+ * If PROCEDURE or ROUTINE was specified, and we have an argument list
+ * that contains no parameter mode markers, and we didn't already discover
+ * that there's ambiguity, perform a lookup considering all arguments.
+ * (Note: for a zero-argument procedure, or in args_unspecified mode, the
+ * normal lookup is sufficient; so it's OK to require non-NIL objfuncargs
+ * to perform this lookup.)
+ */
+ if ((objtype == OBJECT_PROCEDURE || objtype == OBJECT_ROUTINE) &&
+ func->objfuncargs != NIL &&
+ lookupError != FUNCLOOKUP_AMBIGUOUS)
+ {
+ bool have_param_mode = false;
+
+ /*
+ * Check for non-default parameter mode markers. If there are any,
+ * then the command does not conform to SQL-spec syntax, so we may
+ * assume that the traditional Postgres lookup method of considering
+ * only input parameters is sufficient. (Note that because the spec
+ * doesn't have OUT arguments for functions, we also don't need this
+ * hack in FUNCTION or AGGREGATE mode.)
+ */
+ foreach(args_item, func->objfuncargs)
+ {
+ FunctionParameter *fp = lfirst_node(FunctionParameter, args_item);
+
+ if (fp->mode != FUNC_PARAM_DEFAULT)
+ {
+ have_param_mode = true;
+ break;
+ }
+ }
+
+ if (!have_param_mode)
+ {
+ Oid poid;
+
+ /* Without mode marks, objargs surely includes all params */
+ Assert(list_length(func->objfuncargs) == argcount);
+
+ /* For objtype == OBJECT_PROCEDURE, we can ignore non-procedures */
+ poid = LookupFuncNameInternal(objtype, func->objname,
+ argcount, argoids,
+ true, missing_ok,
+ &lookupError);
+
+ /* Combine results, handling ambiguity */
+ if (OidIsValid(poid))
+ {
+ if (OidIsValid(oid) && oid != poid)
+ {
+ /* oops, we got hits both ways, on different objects */
+ oid = InvalidOid;
+ lookupError = FUNCLOOKUP_AMBIGUOUS;
+ }
+ else
+ oid = poid;
+ }
+ else if (lookupError == FUNCLOOKUP_AMBIGUOUS)
+ oid = InvalidOid;
+ }
+ }
+
+ if (OidIsValid(oid))
+ {
+ /*
+ * Even if we found the function, perform validation that the objtype
+ * matches the prokind of the found function. For historical reasons
+ * we allow the objtype of FUNCTION to include aggregates and window
+ * functions; but we draw the line if the object is a procedure. That
+ * is a new enough feature that this historical rule does not apply.
+ *
+ * (This check is partially redundant with the objtype check in
+ * LookupFuncNameInternal; but not entirely, since we often don't tell
+ * LookupFuncNameInternal to apply that check at all.)
+ */
+ switch (objtype)
+ {
+ case OBJECT_FUNCTION:
+ /* Only complain if it's a procedure. */
+ if (get_func_prokind(oid) == PROKIND_PROCEDURE)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("%s is not a function",
+ func_signature_string(func->objname, argcount,
+ NIL, argoids))));
+ break;
+
+ case OBJECT_PROCEDURE:
+ /* Reject if found object is not a procedure. */
+ if (get_func_prokind(oid) != PROKIND_PROCEDURE)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("%s is not a procedure",
+ func_signature_string(func->objname, argcount,
+ NIL, argoids))));
+ break;
+
+ case OBJECT_AGGREGATE:
+ /* Reject if found object is not an aggregate. */
+ if (get_func_prokind(oid) != PROKIND_AGGREGATE)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("function %s is not an aggregate",
+ func_signature_string(func->objname, argcount,
+ NIL, argoids))));
+ break;
+
+ default:
+ /* OBJECT_ROUTINE accepts anything. */
+ break;
+ }
+
+ return oid; /* All good */
+ }
+ else
+ {
+ /* Deal with cases where the lookup failed */
+ switch (lookupError)
+ {
+ case FUNCLOOKUP_NOSUCHFUNC:
+ /* Suppress no-such-func errors when missing_ok is true */
+ if (missing_ok)
+ break;
+
+ switch (objtype)
+ {
+ case OBJECT_PROCEDURE:
+ if (func->args_unspecified)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("could not find a procedure named \"%s\"",
+ NameListToString(func->objname))));
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("procedure %s does not exist",
+ func_signature_string(func->objname, argcount,
+ NIL, argoids))));
+ break;
+
+ case OBJECT_AGGREGATE:
+ if (func->args_unspecified)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("could not find an aggregate named \"%s\"",
+ NameListToString(func->objname))));
+ else if (argcount == 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("aggregate %s(*) does not exist",
+ NameListToString(func->objname))));
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("aggregate %s does not exist",
+ func_signature_string(func->objname, argcount,
+ NIL, argoids))));
+ break;
+
+ default:
+ /* FUNCTION and ROUTINE */
+ if (func->args_unspecified)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("could not find a function named \"%s\"",
+ NameListToString(func->objname))));
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("function %s does not exist",
+ func_signature_string(func->objname, argcount,
+ NIL, argoids))));
+ break;
+ }
+ break;
+
+ case FUNCLOOKUP_AMBIGUOUS:
+ switch (objtype)
+ {
+ case OBJECT_FUNCTION:
+ ereport(ERROR,
+ (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
+ errmsg("function name \"%s\" is not unique",
+ NameListToString(func->objname)),
+ func->args_unspecified ?
+ errhint("Specify the argument list to select the function unambiguously.") : 0));
+ break;
+ case OBJECT_PROCEDURE:
+ ereport(ERROR,
+ (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
+ errmsg("procedure name \"%s\" is not unique",
+ NameListToString(func->objname)),
+ func->args_unspecified ?
+ errhint("Specify the argument list to select the procedure unambiguously.") : 0));
+ break;
+ case OBJECT_AGGREGATE:
+ ereport(ERROR,
+ (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
+ errmsg("aggregate name \"%s\" is not unique",
+ NameListToString(func->objname)),
+ func->args_unspecified ?
+ errhint("Specify the argument list to select the aggregate unambiguously.") : 0));
+ break;
+ case OBJECT_ROUTINE:
+ ereport(ERROR,
+ (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
+ errmsg("routine name \"%s\" is not unique",
+ NameListToString(func->objname)),
+ func->args_unspecified ?
+ errhint("Specify the argument list to select the routine unambiguously.") : 0));
+ break;
+
+ default:
+ Assert(false); /* Disallowed by Assert above */
+ break;
+ }
+ break;
+ }
+
+ return InvalidOid;
+ }
+}
+
+/*
+ * check_srf_call_placement
+ * Verify that a set-returning function is called in a valid place,
+ * and throw a nice error if not.
+ *
+ * A side-effect is to set pstate->p_hasTargetSRFs true if appropriate.
+ *
+ * last_srf should be a copy of pstate->p_last_srf from just before we
+ * started transforming the function's arguments. This allows detection
+ * of whether the SRF's arguments contain any SRFs.
+ */
+void
+check_srf_call_placement(ParseState *pstate, Node *last_srf, int location)
+{
+ const char *err;
+ bool errkind;
+
+ /*
+ * Check to see if the set-returning function is in an invalid place
+ * within the query. Basically, we don't allow SRFs anywhere except in
+ * the targetlist (which includes GROUP BY/ORDER BY expressions), VALUES,
+ * and functions in FROM.
+ *
+ * For brevity we support two schemes for reporting an error here: set
+ * "err" to a custom message, or set "errkind" true if the error context
+ * is sufficiently identified by what ParseExprKindName will return, *and*
+ * what it will return is just a SQL keyword. (Otherwise, use a custom
+ * message to avoid creating translation problems.)
+ */
+ err = NULL;
+ errkind = false;
+ switch (pstate->p_expr_kind)
+ {
+ case EXPR_KIND_NONE:
+ Assert(false); /* can't happen */
+ break;
+ case EXPR_KIND_OTHER:
+ /* Accept SRF here; caller must throw error if wanted */
+ break;
+ case EXPR_KIND_JOIN_ON:
+ case EXPR_KIND_JOIN_USING:
+ err = _("set-returning functions are not allowed in JOIN conditions");
+ break;
+ case EXPR_KIND_FROM_SUBSELECT:
+ /* can't get here, but just in case, throw an error */
+ errkind = true;
+ break;
+ case EXPR_KIND_FROM_FUNCTION:
+ /* okay, but we don't allow nested SRFs here */
+ /* errmsg is chosen to match transformRangeFunction() */
+ /* errposition should point to the inner SRF */
+ if (pstate->p_last_srf != last_srf)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("set-returning functions must appear at top level of FROM"),
+ parser_errposition(pstate,
+ exprLocation(pstate->p_last_srf))));
+ break;
+ case EXPR_KIND_WHERE:
+ errkind = true;
+ break;
+ case EXPR_KIND_POLICY:
+ err = _("set-returning functions are not allowed in policy expressions");
+ break;
+ case EXPR_KIND_HAVING:
+ errkind = true;
+ break;
+ case EXPR_KIND_FILTER:
+ errkind = true;
+ break;
+ case EXPR_KIND_WINDOW_PARTITION:
+ case EXPR_KIND_WINDOW_ORDER:
+ /* okay, these are effectively GROUP BY/ORDER BY */
+ pstate->p_hasTargetSRFs = true;
+ break;
+ case EXPR_KIND_WINDOW_FRAME_RANGE:
+ case EXPR_KIND_WINDOW_FRAME_ROWS:
+ case EXPR_KIND_WINDOW_FRAME_GROUPS:
+ err = _("set-returning functions are not allowed in window definitions");
+ break;
+ case EXPR_KIND_SELECT_TARGET:
+ case EXPR_KIND_INSERT_TARGET:
+ /* okay */
+ pstate->p_hasTargetSRFs = true;
+ break;
+ case EXPR_KIND_UPDATE_SOURCE:
+ case EXPR_KIND_UPDATE_TARGET:
+ /* disallowed because it would be ambiguous what to do */
+ errkind = true;
+ break;
+ case EXPR_KIND_GROUP_BY:
+ case EXPR_KIND_ORDER_BY:
+ /* okay */
+ pstate->p_hasTargetSRFs = true;
+ break;
+ case EXPR_KIND_DISTINCT_ON:
+ /* okay */
+ pstate->p_hasTargetSRFs = true;
+ break;
+ case EXPR_KIND_LIMIT:
+ case EXPR_KIND_OFFSET:
+ errkind = true;
+ break;
+ case EXPR_KIND_RETURNING:
+ errkind = true;
+ break;
+ case EXPR_KIND_VALUES:
+ /* SRFs are presently not supported by nodeValuesscan.c */
+ errkind = true;
+ break;
+ case EXPR_KIND_VALUES_SINGLE:
+ /* okay, since we process this like a SELECT tlist */
+ pstate->p_hasTargetSRFs = true;
+ break;
+ case EXPR_KIND_CHECK_CONSTRAINT:
+ case EXPR_KIND_DOMAIN_CHECK:
+ err = _("set-returning functions are not allowed in check constraints");
+ break;
+ case EXPR_KIND_COLUMN_DEFAULT:
+ case EXPR_KIND_FUNCTION_DEFAULT:
+ err = _("set-returning functions are not allowed in DEFAULT expressions");
+ break;
+ case EXPR_KIND_INDEX_EXPRESSION:
+ err = _("set-returning functions are not allowed in index expressions");
+ break;
+ case EXPR_KIND_INDEX_PREDICATE:
+ err = _("set-returning functions are not allowed in index predicates");
+ break;
+ case EXPR_KIND_STATS_EXPRESSION:
+ err = _("set-returning functions are not allowed in statistics expressions");
+ break;
+ case EXPR_KIND_ALTER_COL_TRANSFORM:
+ err = _("set-returning functions are not allowed in transform expressions");
+ break;
+ case EXPR_KIND_EXECUTE_PARAMETER:
+ err = _("set-returning functions are not allowed in EXECUTE parameters");
+ break;
+ case EXPR_KIND_TRIGGER_WHEN:
+ err = _("set-returning functions are not allowed in trigger WHEN conditions");
+ break;
+ case EXPR_KIND_PARTITION_BOUND:
+ err = _("set-returning functions are not allowed in partition bound");
+ break;
+ case EXPR_KIND_PARTITION_EXPRESSION:
+ err = _("set-returning functions are not allowed in partition key expressions");
+ break;
+ case EXPR_KIND_CALL_ARGUMENT:
+ err = _("set-returning functions are not allowed in CALL arguments");
+ break;
+ case EXPR_KIND_COPY_WHERE:
+ err = _("set-returning functions are not allowed in COPY FROM WHERE conditions");
+ break;
+ case EXPR_KIND_GENERATED_COLUMN:
+ err = _("set-returning functions are not allowed in column generation expressions");
+ break;
+ case EXPR_KIND_CYCLE_MARK:
+ errkind = true;
+ break;
+
+ /*
+ * There is intentionally no default: case here, so that the
+ * compiler will warn if we add a new ParseExprKind without
+ * extending this switch. If we do see an unrecognized value at
+ * runtime, the behavior will be the same as for EXPR_KIND_OTHER,
+ * which is sane anyway.
+ */
+ }
+ if (err)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg_internal("%s", err),
+ parser_errposition(pstate, location)));
+ if (errkind)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ /* translator: %s is name of a SQL construct, eg GROUP BY */
+ errmsg("set-returning functions are not allowed in %s",
+ ParseExprKindName(pstate->p_expr_kind)),
+ parser_errposition(pstate, location)));
+}