📄 parse_func.c
字号:
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 columns. * * NOTE: for a binary operator with one unknown and one non-unknown input, * we already tried the heuristic of looking for a candidate with the * known input type on both sides (see binary_oper_exact()). That's * essentially a special case of the general algorithm we try next. * * We do this by examining 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 we are down to one candidate at the end, we win. */ 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] = INVALID_TYPE; 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]; current_category = TypeCategory(current_type); if (slot_category[i] == INVALID_TYPE) { /* first candidate */ slot_category[i] = current_category; slot_has_preferred_type[i] = IsPreferredType(current_category, current_type); } else if (current_category == slot_category[i]) { /* more candidates in same category */ slot_has_preferred_type[i] |= IsPreferredType(current_category, current_type); } else { /* category conflict! */ if (current_category == STRING_TYPE) { /* STRING always wins if available */ slot_category[i] = current_category; slot_has_preferred_type[i] = IsPreferredType(current_category, current_type); } else { /* * Remember conflict, but keep going (might find STRING) */ have_conflict = true; } } } if (have_conflict && slot_category[i] != STRING_TYPE) { /* Failed to resolve category conflict at this position */ resolved_unknowns = false; break; } } if (resolved_unknowns) { /* Strip non-matching candidates */ ncandidates = 0; 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]; current_category = TypeCategory(current_type); if (current_category != slot_category[i]) { keepit = false; break; } if (slot_has_preferred_type[i] && !IsPreferredType(current_category, current_type)) { 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 candidates = current_candidate->next; } } if (last_candidate) /* terminate rebuilt list */ last_candidate->next = NULL; } if (ncandidates == 1) return candidates; 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 trivial type coercion * 2) get a vector of all possible input arg type arrays constructed * from the superclasses of the original input arg types * 3) get a list of all possible argument type arrays to the function * with given name and number of arguments * 4) for each input arg type array from vector #1: * a) find how many of the function arg type arrays from list #2 * it can be coerced to * b) if the answer is one, we have our function * c) if the answer is more than one, attempt to resolve the conflict * d) if the answer is zero, try the next array from vector #1 * * Note: we rely primarily on 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 want that check made. */FuncDetailCodefunc_get_detail(List *funcname, List *fargs, int nargs, Oid *argtypes, Oid *funcid, /* return value */ Oid *rettype, /* return value */ bool *retset, /* return value */ Oid **true_typeids) /* return value */{ FuncCandidateList raw_candidates; FuncCandidateList best_candidate; /* Get list of possible candidates from namespace search */ raw_candidates = FuncnameGetCandidates(funcname, nargs); /* * 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 we can do the coercion trivially (no run-time function call * needed), 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 trivial coercion, not * as "text(name(varchar))" which the code below this point is * entirely capable of selecting. * * "Trivial" coercions are ones that involve binary-compatible types * and ones that are coercing a previously-unknown-type literal * constant to a specific type. * * The reason we can restrict our check to binary-compatible coercions * here is that we expect non-binary-compatible coercions to have an * implementation function named after the target type. That function * will be found by normal lookup if appropriate. * * NB: it's important that this code stays in sync with 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) { Oid targetType; TypeName *tn = makeNode(TypeName); tn->names = funcname; tn->typmod = -1; targetType = LookupTypeName(tn); if (OidIsValid(targetType) && !ISCOMPLEX(targetType)) { Oid sourceType = argtypes[0]; Node *arg1 = linitial(fargs); Oid cfuncid; if ((sourceType == UNKNOWNOID && IsA(arg1, Const)) || (find_coercion_pathway(targetType, sourceType, COERCION_EXPLICIT, &cfuncid) && cfuncid == InvalidOid)) { /* Yup, it's a type coercion */ *funcid = InvalidOid; *rettype = targetType; *retset = false; *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, ¤t_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; *funcid = best_candidate->oid; *true_typeids = best_candidate->args; ftup = SearchSysCache(PROCOID, ObjectIdGetDatum(best_candidate->oid), 0, 0, 0); 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; result = pform->proisagg ? FUNCDETAIL_AGGREGATE : FUNCDETAIL_NORMAL; ReleaseSysCache(ftup); return result; } return FUNCDETAIL_NOTFOUND;}/* * Given two type OIDs, determine whether the first is a complex type * (class type) that inherits from the second. */booltypeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -