/* Similar mechanism as in parse_oper.ci, in particular
 * in the static function oper_select_candidate */
Oid find_equality_operator(Oid ltypeId, Oid rtypeId)
{
  List * const equals=list_make1(makeString("="));

  FuncCandidateList clist;
  Oid inputOids[2] = {ltypeId,rtypeId};
  int ncandidates;
  
  Oid result = binary_oper_exact(equals, ltypeId, rtypeId);

  if(result!=InvalidOid)
    return result;

  clist = OpernameGetCandidates(equals, 'b', false);

  ncandidates = func_match_argtypes(2, inputOids,
      clist, &clist);

  if (ncandidates == 0)
    return InvalidOid;
  else if (ncandidates == 1)
    return clist->oid;
  
  clist = func_select_candidate(2, inputOids, clist);

  if(clist)
    return clist->oid;
  else
    return InvalidOid;
}
Beispiel #2
0
/* oper_select_candidate()
 *		Given the input argtype array and one or more candidates
 *		for the operator, attempt to resolve the conflict.
 *
 * Returns FUNCDETAIL_NOTFOUND, FUNCDETAIL_MULTIPLE, or FUNCDETAIL_NORMAL.
 * In the success case the Oid of the best candidate is stored in *operOid.
 *
 * Note that the caller has already determined that there is no candidate
 * exactly matching the input argtype(s).  Incompatible candidates are not yet
 * pruned away, however.
 */
static FuncDetailCode
oper_select_candidate(int nargs,
					  Oid *input_typeids,
					  FuncCandidateList candidates,
					  Oid *operOid)		/* output argument */
{
	int			ncandidates;

	/*
	 * Delete any candidates that cannot actually accept the given input
	 * types, whether directly or by coercion.
	 */
	ncandidates = func_match_argtypes(nargs, input_typeids,
									  candidates, &candidates);

	/* Done if no candidate or only one candidate survives */
	if (ncandidates == 0)
	{
		*operOid = InvalidOid;
		return FUNCDETAIL_NOTFOUND;
	}
	if (ncandidates == 1)
	{
		*operOid = candidates->oid;
		return FUNCDETAIL_NORMAL;
	}

	/*
	 * Use the same heuristics as for ambiguous functions to resolve the
	 * conflict.
	 */
	candidates = func_select_candidate(nargs, input_typeids, candidates);

	if (candidates)
	{
		*operOid = candidates->oid;
		return FUNCDETAIL_NORMAL;
	}

	*operOid = InvalidOid;
	return FUNCDETAIL_MULTIPLE; /* failed to select a best candidate */
}
Beispiel #3
0
/**
 * @brief Parse function expression
 */
ParsedFunction
ParseFunction(const char *value, bool argistype)
{
    int					i;
    ParsedFunction		ret;
    char			   *buf;
    const char		   *nextp;
    bool				done = false;
    List			   *names;
    ListCell		   *l;
    int					nargs;
    FuncCandidateList	candidates;
    FuncCandidateList	find = NULL;
    int					ncandidates = 0;
    HeapTuple			ftup;
    Form_pg_proc		pp;
    AclResult			aclresult;

    buf = palloc(strlen(value) + 1);

    /* parse function name */
    nextp = value;
    do
    {
        if (*nextp == '\"')
        {
            /* Quoted name */
            for (;;)
            {
                nextp = strchr(nextp + 1, '\"');

                /* mismatched quotes */
                if (nextp == NULL)
                    ereport(ERROR,
                            (errcode(ERRCODE_SYNTAX_ERROR),
                             errmsg("function call syntax error: %s", value)));

                if (nextp[1] != '\"')
                    break;		/* found end of quoted name */
            }

            /* nextp now points at the terminating quote */
            nextp = nextp + 1;
        }
        else if (IsIdentStart((unsigned char) *nextp))
        {
            /* Unquoted name */
            nextp++;
            while (IsIdentContent((unsigned char) *nextp))
                nextp++;
        }
        else
        {
            /* invalid syntax */
            ereport(ERROR,
                    (errcode(ERRCODE_SYNTAX_ERROR),
                     errmsg("function call syntax error: %s", value)));
        }

        while (isspace((unsigned char) *nextp))
            nextp++;			/* skip trailing whitespace */

        if (*nextp == '.')
        {
            nextp++;
            while (isspace((unsigned char) *nextp))
                nextp++;		/* skip leading whitespace for next */
            /* we expect another name, so done remains false */
        }
        else if (*nextp == '\0' || *nextp == '(')
            done = true;
        else
        {
            /* invalid syntax */
            ereport(ERROR,
                    (errcode(ERRCODE_SYNTAX_ERROR),
                     errmsg("function call syntax error: %s", value)));
        }

        /* Loop back if we didn't reach end of function name */
    } while (!done);

    strncpy(buf, value, nextp - value);
    buf[nextp - value] = '\0';

    names = stringToQualifiedNameList(buf);
    pfree(buf);

    if (*nextp == '\0')
    {
        if (!argistype)
            ereport(ERROR,
                    (errcode(ERRCODE_SYNTAX_ERROR),
                     errmsg("function call syntax error: %s", value)));

        nargs = -1;

        /* Get list of possible candidates from namespace search */
        candidates = FuncnameGetCandidates(names, nargs, NIL, false, false);
    }
    else
    {
        /* parse function arguments */
        nargs = 0;
        while (GetNextArgument(nextp, &ret.args[nargs], &ret.argtypes[nargs], &nextp, value, argistype))
        {
            nargs++;
            if (nargs > FUNC_MAX_ARGS)
                ereport(ERROR,
                        (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
                         errmsg("functions cannot have more than %d arguments", FUNC_MAX_ARGS)));
        }

        /* Get list of possible candidates from namespace search */
        candidates = FuncnameGetCandidates(names, nargs, NIL, true, true);
    }


    /* so now try to match up candidates */
    if (!argistype)
    {
        FuncCandidateList current_candidates;

        ncandidates = func_match_argtypes(nargs,
                                          ret.argtypes,
                                          candidates,
                                          &current_candidates);

        /* one match only? then run with it... */
        if (ncandidates == 1)
            find = current_candidates;

        /* multiple candidates? then better decide or throw an error... */
        else if (ncandidates > 1)
        {
            find = func_select_candidate(nargs, ret.argtypes,
                                         current_candidates);
        }
    }
    else if (nargs > 0)
    {
        /* Quickly check if there is an exact match to the input datatypes */
        for (find = candidates; find; find = find->next)
        {
            if (memcmp(find->args, ret.argtypes, nargs * sizeof(Oid)) == 0)
            {
                ncandidates = 1;
                break;
            }
        }
    }
    else
    {
        FuncCandidateList c;
        for (c = candidates; c; c = c->next)
            ncandidates++;
        find = candidates;
    }

    if (ncandidates == 0)
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_FUNCTION),
                 errmsg("function %s does not exist",
                        func_signature_string(names, nargs, NIL, ret.argtypes)),
                 errhint("No function matches the given name and argument types.")));

    /*
     * If we were able to choose a best candidate, we're done.
     * Otherwise, ambiguous function call.
     */
    if (ncandidates > 1 || !OidIsValid(find->oid))
        ereport(ERROR,
                (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
                 errmsg("function %s is not unique",
                        func_signature_string(names, nargs, NIL,
                                              ret.argtypes)),
                 errhint("Could not choose a best candidate function.")));

    foreach (l, names)
    {
        Value  *v = lfirst(l);

        pfree(strVal(v));
        pfree(v);
    }