Header And Logo

PostgreSQL
| The world's most advanced open source database.

Functions

parse_func.c File Reference

#include "postgres.h"
#include "access/htup_details.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_coerce.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"
Include dependency graph for parse_func.c:

Go to the source code of this file.

Functions

static Oid FuncNameAsType (List *funcname)
static NodeParseComplexProjection (ParseState *pstate, char *funcname, Node *first_arg, int location)
NodeParseFuncOrColumn (ParseState *pstate, List *funcname, List *fargs, List *agg_order, bool agg_star, bool agg_distinct, bool func_variadic, WindowDef *over, bool is_column, int location)
int func_match_argtypes (int nargs, Oid *input_typeids, FuncCandidateList raw_candidates, FuncCandidateList *candidates)
FuncCandidateList func_select_candidate (int nargs, Oid *input_typeids, FuncCandidateList candidates)
FuncDetailCode func_get_detail (List *funcname, List *fargs, List *fargnames, int nargs, Oid *argtypes, bool expand_variadic, bool expand_defaults, Oid *funcid, Oid *rettype, bool *retset, int *nvargs, Oid **true_typeids, List **argdefaults)
void make_fn_arguments (ParseState *pstate, List *fargs, Oid *actual_arg_types, Oid *declared_arg_types)
const char * funcname_signature_string (const char *funcname, int nargs, List *argnames, const Oid *argtypes)
const char * func_signature_string (List *funcname, int nargs, List *argnames, const Oid *argtypes)
Oid LookupFuncName (List *funcname, int nargs, const Oid *argtypes, bool noError)
static Oid LookupTypeNameOid (const TypeName *typename)
Oid LookupFuncNameTypeNames (List *funcname, List *argtypes, bool noError)
Oid LookupAggNameTypeNames (List *aggname, List *argtypes, bool noError)

Function Documentation

FuncDetailCode func_get_detail ( List funcname,
List fargs,
List fargnames,
int  nargs,
Oid argtypes,
bool  expand_variadic,
bool  expand_defaults,
Oid funcid,
Oid rettype,
bool retset,
int *  nvargs,
Oid **  true_typeids,
List **  argdefaults 
)

Definition at line 1007 of file parse_func.c.

References Anum_pg_proc_proargdefaults, NamedArgExpr::argnumber, _FuncCandidateList::argnumbers, _FuncCandidateList::args, Assert, bms_add_member(), bms_free(), bms_is_member(), COERCION_EXPLICIT, COERCION_PATH_COERCEVIAIO, COERCION_PATH_RELABELTYPE, elog, ERROR, find_coercion_pathway(), func_match_argtypes(), func_select_candidate(), FuncNameAsType(), FuncnameGetCandidates(), GETSTRUCT, HeapTupleIsValid, i, IsA, ISCOMPLEX, lappend(), lfirst, linitial, list_delete_first(), list_length(), memcmp(), _FuncCandidateList::nargs, _FuncCandidateList::ndargs, _FuncCandidateList::next, NIL, NULL, _FuncCandidateList::nvargs, ObjectIdGetDatum, _FuncCandidateList::oid, OidIsValid, pfree(), PROCOID, RECORDOID, ReleaseSysCache(), SearchSysCache1, stringToNode(), SysCacheGetAttr(), TextDatumGetCString, TYPCATEGORY_STRING, TypeCategory(), and UNKNOWNOID.

Referenced by generate_function_name(), lookup_agg_function(), and ParseFuncOrColumn().

{
    FuncCandidateList raw_candidates;
    FuncCandidateList best_candidate;

    /* initialize output arguments to silence compiler warnings */
    *funcid = InvalidOid;
    *rettype = InvalidOid;
    *retset = false;
    *nvargs = 0;
    *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);

    /*
     * 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 (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;
                    *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;
        /* 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 = (List *) stringToNode(str);
            Assert(IsA(defaults, List));
            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 = pform->pronargs - 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;
                while (ndelete-- > 0)
                    defaults = list_delete_first(defaults);
                *argdefaults = defaults;
            }
        }
        if (pform->proisagg)
            result = FUNCDETAIL_AGGREGATE;
        else if (pform->proiswindow)
            result = FUNCDETAIL_WINDOWFUNC;
        else
            result = FUNCDETAIL_NORMAL;
        ReleaseSysCache(ftup);
        return result;
    }

    return FUNCDETAIL_NOTFOUND;
}

int func_match_argtypes ( int  nargs,
Oid input_typeids,
FuncCandidateList  raw_candidates,
FuncCandidateList candidates 
)

Definition at line 535 of file parse_func.c.

References _FuncCandidateList::args, can_coerce_type(), COERCION_IMPLICIT, and _FuncCandidateList::next.

Referenced by func_get_detail(), and oper_select_candidate().

{
    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() */

FuncCandidateList func_select_candidate ( int  nargs,
Oid input_typeids,
FuncCandidateList  candidates 
)

Definition at line 620 of file parse_func.c.

References _FuncCandidateList::args, can_coerce_type(), COERCION_IMPLICIT, ereport, errcode(), errmsg_plural(), ERROR, FUNC_MAX_ARGS, get_type_category_preferred(), getBaseType(), i, IsPreferredType(), _FuncCandidateList::next, NULL, TYPCATEGORY_INVALID, TYPCATEGORY_STRING, TypeCategory(), and UNKNOWNOID.

Referenced by func_get_detail(), and oper_select_candidate().

{
    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() */

const char* func_signature_string ( List funcname,
int  nargs,
List argnames,
const Oid argtypes 
)
const char* funcname_signature_string ( const char *  funcname,
int  nargs,
List argnames,
const Oid argtypes 
)

Definition at line 1493 of file parse_func.c.

References appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), StringInfoData::data, format_type_be(), i, initStringInfo(), lfirst, list_head(), list_length(), and lnext.

Referenced by func_signature_string(), and IsThereFunctionInNamespace().

{
    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(lc);
        }
        appendStringInfoString(&argbuf, format_type_be(argtypes[i]));
    }

    appendStringInfoChar(&argbuf, ')');

    return argbuf.data;         /* return palloc'd string buffer */
}

static Oid FuncNameAsType ( List funcname  )  [static]

Definition at line 1389 of file parse_func.c.

References GETSTRUCT, LookupTypeName(), makeTypeNameFromNameList(), NULL, OidIsValid, ReleaseSysCache(), typeTypeId(), and typeTypeRelid().

Referenced by func_get_detail().

{
    Oid         result;
    Type        typtup;

    typtup = LookupTypeName(NULL, makeTypeNameFromNameList(funcname), NULL);
    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;
}

Oid LookupAggNameTypeNames ( List aggname,
List argtypes,
bool  noError 
)

Definition at line 1636 of file parse_func.c.

References elog, ereport, errcode(), errmsg(), errmsg_plural(), ERROR, FUNC_MAX_ARGS, func_signature_string(), GETSTRUCT, HeapTupleIsValid, i, lfirst, list_length(), LookupFuncName(), LookupTypeNameOid(), NameListToString(), NIL, ObjectIdGetDatum, OidIsValid, PROCOID, ReleaseSysCache(), and SearchSysCache1.

Referenced by get_object_address().

{
    Oid         argoids[FUNC_MAX_ARGS];
    int         argcount;
    int         i;
    ListCell   *lc;
    Oid         oid;
    HeapTuple   ftup;
    Form_pg_proc pform;

    argcount = list_length(argtypes);
    if (argcount > FUNC_MAX_ARGS)
        ereport(ERROR,
                (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
                 errmsg_plural("functions cannot have more than %d argument",
                               "functions cannot have more than %d arguments",
                               FUNC_MAX_ARGS,
                               FUNC_MAX_ARGS)));

    i = 0;
    foreach(lc, argtypes)
    {
        TypeName   *t = (TypeName *) lfirst(lc);

        argoids[i] = LookupTypeNameOid(t);
        i++;
    }

    oid = LookupFuncName(aggname, argcount, argoids, true);

    if (!OidIsValid(oid))
    {
        if (noError)
            return InvalidOid;
        if (argcount == 0)
            ereport(ERROR,
                    (errcode(ERRCODE_UNDEFINED_FUNCTION),
                     errmsg("aggregate %s(*) does not exist",
                            NameListToString(aggname))));
        else
            ereport(ERROR,
                    (errcode(ERRCODE_UNDEFINED_FUNCTION),
                     errmsg("aggregate %s does not exist",
                            func_signature_string(aggname, argcount,
                                                  NIL, argoids))));
    }

    /* Make sure it's an aggregate */
    ftup = SearchSysCache1(PROCOID, ObjectIdGetDatum(oid));
    if (!HeapTupleIsValid(ftup))    /* should not happen */
        elog(ERROR, "cache lookup failed for function %u", oid);
    pform = (Form_pg_proc) GETSTRUCT(ftup);

    if (!pform->proisagg)
    {
        ReleaseSysCache(ftup);
        if (noError)
            return InvalidOid;
        /* we do not use the (*) notation for functions... */
        ereport(ERROR,
                (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                 errmsg("function %s is not an aggregate",
                        func_signature_string(aggname, argcount,
                                              NIL, argoids))));
    }

    ReleaseSysCache(ftup);

    return oid;
}

Oid LookupFuncName ( List funcname,
int  nargs,
const Oid argtypes,
bool  noError 
)
Oid LookupFuncNameTypeNames ( List funcname,
List argtypes,
bool  noError 
)

Definition at line 1599 of file parse_func.c.

References ereport, errcode(), errmsg_plural(), ERROR, FUNC_MAX_ARGS, i, lfirst, list_head(), list_length(), lnext, LookupFuncName(), and LookupTypeNameOid().

Referenced by AlterFunction(), AlterOpFamilyAdd(), CreateCast(), DefineOpClass(), get_object_address(), and objectNamesToOids().

{
    Oid         argoids[FUNC_MAX_ARGS];
    int         argcount;
    int         i;
    ListCell   *args_item;

    argcount = list_length(argtypes);
    if (argcount > FUNC_MAX_ARGS)
        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)));

    args_item = list_head(argtypes);
    for (i = 0; i < argcount; i++)
    {
        TypeName   *t = (TypeName *) lfirst(args_item);

        argoids[i] = LookupTypeNameOid(t);
        args_item = lnext(args_item);
    }

    return LookupFuncName(funcname, argcount, argoids, noError);
}

static Oid LookupTypeNameOid ( const TypeName typename  )  [static]

Definition at line 1577 of file parse_func.c.

References ereport, errcode(), errmsg(), ERROR, LookupTypeName(), NULL, ReleaseSysCache(), TypeNameToString(), and typeTypeId().

Referenced by LookupAggNameTypeNames(), and LookupFuncNameTypeNames().

{
    Oid         result;
    Type        typtup;

    typtup = LookupTypeName(NULL, typename, NULL);
    if (typtup == NULL)
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_OBJECT),
                 errmsg("type \"%s\" does not exist",
                        TypeNameToString(typename))));
    result = typeTypeId(typtup);
    ReleaseSysCache(typtup);
    return result;
}

void make_fn_arguments ( ParseState pstate,
List fargs,
Oid actual_arg_types,
Oid declared_arg_types 
)

Definition at line 1333 of file parse_func.c.

References NamedArgExpr::arg, COERCE_IMPLICIT_CAST, coerce_type(), COERCION_IMPLICIT, i, IsA, and lfirst.

Referenced by make_op(), make_scalar_array_op(), ParseFuncOrColumn(), and recheck_cast_function_args().

{
    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++;
    }
}

static Node * ParseComplexProjection ( ParseState pstate,
char *  funcname,
Node first_arg,
int  location 
) [static]

Definition at line 1415 of file parse_func.c.

References FieldSelect::arg, Assert, tupleDesc::attrs, expandRecordVariable(), FieldSelect::fieldnum, get_expr_result_type(), GetRTEByRangeTablePosn(), i, InvalidAttrNumber, IsA, makeNode, NameStr, tupleDesc::natts, NULL, RECORDOID, FieldSelect::resultcollid, FieldSelect::resulttype, FieldSelect::resulttypmod, scanRTEForColumn(), and TYPEFUNC_COMPOSITE.

Referenced by ParseFuncOrColumn().

{
    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)
    {
        RangeTblEntry *rte;

        rte = GetRTEByRangeTablePosn(pstate,
                                     ((Var *) first_arg)->varno,
                                     ((Var *) first_arg)->varlevelsup);
        /* Return a Var if funcname matches a column, else NULL */
        return scanRTEForColumn(pstate, rte, funcname, location);
    }

    /*
     * Else do it the hard way with get_expr_result_type().
     *
     * 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_type.
     * That task is handled by expandRecordVariable().
     */
    if (IsA(first_arg, Var) &&
        ((Var *) first_arg)->vartype == RECORDOID)
        tupdesc = expandRecordVariable(pstate, (Var *) first_arg, 0);
    else if (get_expr_result_type(first_arg, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
        return NULL;            /* unresolvable RECORD type */
    Assert(tupdesc);

    for (i = 0; i < tupdesc->natts; i++)
    {
        Form_pg_attribute att = tupdesc->attrs[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 */
}

Node* ParseFuncOrColumn ( ParseState pstate,
List funcname,
List fargs,
List agg_order,
bool  agg_star,
bool  agg_distinct,
bool  func_variadic,
WindowDef over,
bool  is_column,
int  location 
)

Definition at line 63 of file parse_func.c.

References Aggref::aggfnoid, Aggref::aggstar, Aggref::aggtype, ANYOID, arg, WindowFunc::args, FuncExpr::args, ArrayExpr::array_typeid, Assert, COERCE_EXPLICIT_CALL, coerce_type(), COERCION_EXPLICIT, ArrayExpr::element_typeid, ArrayExpr::elements, enforce_generic_type_consistency(), ereport, errcode(), errhint(), errmsg(), errmsg_plural(), ERROR, exprLocation(), exprType(), format_type_be(), func_get_detail(), FUNC_MAX_ARGS, func_signature_string(), FUNCDETAIL_AGGREGATE, FUNCDETAIL_COERCION, FUNCDETAIL_MULTIPLE, FUNCDETAIL_NORMAL, FUNCDETAIL_WINDOWFUNC, FuncExpr::funcformat, FuncExpr::funcid, FuncExpr::funcresulttype, FuncExpr::funcretset, FuncExpr::funcvariadic, get_array_type(), IsA, ISCOMPLEX, lappend(), lfirst, linitial, list_copy_tail(), list_delete_ptr(), list_head(), list_length(), list_truncate(), lnext, WindowFunc::location, Aggref::location, FuncExpr::location, ArrayExpr::location, NamedArgExpr::location, make_fn_arguments(), makeNode, ArrayExpr::multidims, NamedArgExpr::name, NameListToString(), NIL, NULL, OidIsValid, ParseComplexProjection(), parser_errposition(), RECORDOID, strVal, transformAggregateCall(), transformWindowFuncCall(), VOIDOID, WindowFunc::winagg, WindowFunc::winfnoid, WindowFunc::winstar, and WindowFunc::wintype.

Referenced by sql_fn_post_column_ref(), transformColumnRef(), transformFuncCall(), and transformIndirection().

{
    Oid         rettype;
    Oid         funcid;
    ListCell   *l;
    ListCell   *nextl;
    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;
    FuncDetailCode fdresult;

    /*
     * 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.  We can't use foreach() because we
     * may modify the list ...
     */
    nargs = 0;
    for (l = list_head(fargs); l != NULL; l = nextl)
    {
        Node       *arg = lfirst(l);
        Oid         argtype = exprType(arg);

        nextl = lnext(l);

        if (argtype == VOIDOID && IsA(arg, Param) &&!is_column)
        {
            fargs = list_delete_ptr(fargs, arg);
            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);
    }

    /*
     * Check for column projection: if function has one argument, and that
     * argument is of complex type, and function name is not qualified, then
     * the "function call" could be a projection.  We also check that there
     * wasn't any aggregate or variadic decoration, nor an argument name.
     */
    if (nargs == 1 && agg_order == NIL && !agg_star && !agg_distinct &&
        over == NULL && !func_variadic && argnames == NIL &&
        list_length(funcname) == 1)
    {
        Oid         argtype = actual_arg_types[0];

        if (argtype == RECORDOID || ISCOMPLEX(argtype))
        {
            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.
             */
        }
    }

    /*
     * Okay, it's not a column projection, so it must really be a function.
     * 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.
     */
    fdresult = func_get_detail(funcname, fargs, argnames, nargs,
                               actual_arg_types,
                               !func_variadic, true,
                               &funcid, &rettype, &retset, &nvargs,
                               &declared_arg_types, &argdefaults);
    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_NORMAL)
    {
        /*
         * Normal function found; was there anything indicating it must be an
         * aggregate?
         */
        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_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 (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)));
    }
    else if (!(fdresult == FUNCDETAIL_AGGREGATE ||
               fdresult == FUNCDETAIL_WINDOWFUNC))
    {
        /*
         * Oops.  Time to die.
         *
         * If we are dealing with the attribute notation rel.function, let the
         * caller handle failure.
         */
        if (is_column)
            return NULL;

        /*
         * Else generate a detailed complaint for a function
         */
        if (fdresult == FUNCDETAIL_MULTIPLE)
            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 if (list_length(agg_order) > 1)
        {
            /* 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
            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 it's a variadic function call, transform the last nvargs arguments
     * into an array --- unless it's an "any" variadic.
     */
    if (nvargs > 0 && declared_arg_types[nargs - 1] != 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);
    }

    /* build the appropriate output structure */
    if (fdresult == FUNCDETAIL_NORMAL)
    {
        FuncExpr   *funcexpr = makeNode(FuncExpr);

        funcexpr->funcid = funcid;
        funcexpr->funcresulttype = rettype;
        funcexpr->funcretset = retset;
        funcexpr->funcvariadic = func_variadic;
        funcexpr->funcformat = COERCE_EXPLICIT_CALL;
        /* 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 */
        /* args, aggorder, aggdistinct will be set by transformAggregateCall */
        aggref->aggstar = agg_star;
        /* agglevelsup will be set by transformAggregateCall */
        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)
            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)));

        /*
         * Currently it's not possible to define an aggregate with named
         * arguments, so this case should be impossible.  Check anyway because
         * the planner and executor wouldn't cope with NamedArgExprs in an
         * Aggref node.
         */
        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);

        /*
         * True window functions must be called with a window definition.
         */
        if (!over)
            ereport(ERROR,
                    (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                     errmsg("window function call requires an OVER clause"),
                     parser_errposition(pstate, location)));

        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->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)));

        if (retset)
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
                     errmsg("window functions cannot return sets"),
                     parser_errposition(pstate, location)));

        /*
         * We might want to support this later, but for now reject it because
         * the planner and executor wouldn't cope with NamedArgExprs in a
         * WindowFunc node.
         */
        if (argnames != NIL)
            ereport(ERROR,
                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                     errmsg("window functions cannot use named arguments"),
                     parser_errposition(pstate, location)));

        /* parse_agg.c does additional window-func-specific processing */
        transformWindowFuncCall(pstate, wfunc, over);

        retval = (Node *) wfunc;
    }

    return retval;
}