/* 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; }
/* 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 */ }
/** * @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, ¤t_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); }