diff options
Diffstat (limited to 'src/backend/parser')
-rw-r--r-- | src/backend/parser/parse_coerce.c | 150 | ||||
-rw-r--r-- | src/backend/parser/parse_func.c | 213 | ||||
-rw-r--r-- | src/backend/parser/parse_oper.c | 421 |
3 files changed, 221 insertions, 563 deletions
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index 9dc0c7f1c19..fc35c2d6d41 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.96 2003/04/29 22:13:10 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.97 2003/05/26 00:11:27 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -32,7 +32,6 @@ static Node *coerce_type_typmod(Node *node, Oid targetTypeId, int32 targetTypMod, CoercionForm cformat, bool isExplicit); -static Oid PreferredType(CATEGORY category, Oid type); static Node *build_func_call(Oid funcid, Oid rettype, List *args, CoercionForm fformat); @@ -66,28 +65,43 @@ coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype, if (can_coerce_type(1, &exprtype, &targettype, ccontext)) expr = coerce_type(pstate, expr, exprtype, targettype, ccontext, cformat); - /* - * String hacks to get transparent conversions for char and varchar: - * if a coercion to text is available, use it for forced coercions to - * char(n) or varchar(n). - * - * This is pretty grotty, but seems easier to maintain than providing - * entries in pg_cast that parallel all the ones for text. - */ - else if (ccontext >= COERCION_ASSIGNMENT && - (targettype == BPCHAROID || targettype == VARCHAROID)) + else if (ccontext >= COERCION_ASSIGNMENT) { - Oid text_id = TEXTOID; + /* + * String hacks to get transparent conversions for char and varchar: + * if a coercion to text is available, use it for forced coercions to + * char(n) or varchar(n) or domains thereof. + * + * This is pretty grotty, but seems easier to maintain than providing + * entries in pg_cast that parallel all the ones for text. + */ + Oid targetbasetype = getBaseType(targettype); - if (can_coerce_type(1, &exprtype, &text_id, ccontext)) + if (targetbasetype == BPCHAROID || targetbasetype == VARCHAROID) { - expr = coerce_type(pstate, expr, exprtype, text_id, - ccontext, cformat); - /* Need a RelabelType if no typmod coercion is performed */ - if (targettypmod < 0) - expr = (Node *) makeRelabelType((Expr *) expr, - targettype, -1, - cformat); + Oid text_id = TEXTOID; + + if (can_coerce_type(1, &exprtype, &text_id, ccontext)) + { + expr = coerce_type(pstate, expr, exprtype, text_id, + ccontext, cformat); + if (targetbasetype != targettype) + { + /* need to coerce to domain over char or varchar */ + expr = coerce_to_domain(expr, targetbasetype, targettype, + cformat); + } + else + { + /* need a RelabelType if no typmod coercion will be performed */ + if (targettypmod < 0) + expr = (Node *) makeRelabelType((Expr *) expr, + targettype, -1, + cformat); + } + } + else + expr = NULL; } else expr = NULL; @@ -923,7 +937,10 @@ enforce_generic_type_consistency(Oid *actual_arg_types, /* TypeCategory() - * Assign a category to the specified OID. + * Assign a category to the specified type OID. + * + * NB: this must not return INVALID_TYPE. + * * XXX This should be moved to system catalog lookups * to allow for better type extensibility. * - thomas 2001-09-30 @@ -1026,7 +1043,11 @@ TypeCategory(Oid inType) /* IsPreferredType() - * Check if this type is a preferred type. + * Check if this type is a preferred type for the given category. + * + * If category is INVALID_TYPE, then we'll return TRUE for preferred types + * of any category; otherwise, only for preferred types of that category. + * * XXX This should be moved to system catalog lookups * to allow for better type extensibility. * - thomas 2001-09-30 @@ -1034,39 +1055,34 @@ TypeCategory(Oid inType) bool IsPreferredType(CATEGORY category, Oid type) { - return (type == PreferredType(category, type)); -} /* IsPreferredType() */ + Oid preftype; + if (category == INVALID_TYPE) + category = TypeCategory(type); + else if (category != TypeCategory(type)) + return false; -/* PreferredType() - * Return the preferred type OID for the specified category. - * XXX This should be moved to system catalog lookups - * to allow for better type extensibility. - * - thomas 2001-09-30 - */ -static Oid -PreferredType(CATEGORY category, Oid type) -{ - Oid result; - + /* + * This switch should agree with TypeCategory(), above. Note that + * at this point, category certainly matches the type. + */ switch (category) { - case (INVALID_TYPE): case (UNKNOWN_TYPE): case (GENERIC_TYPE): - result = UNKNOWNOID; + preftype = UNKNOWNOID; break; case (BOOLEAN_TYPE): - result = BOOLOID; + preftype = BOOLOID; break; case (STRING_TYPE): - result = TEXTOID; + preftype = TEXTOID; break; case (BITSTRING_TYPE): - result = VARBITOID; + preftype = VARBITOID; break; case (NUMERIC_TYPE): @@ -1077,52 +1093,59 @@ PreferredType(CATEGORY category, Oid type) type == REGOPERATOROID || type == REGCLASSOID || type == REGTYPEOID) - result = OIDOID; + preftype = OIDOID; else - result = FLOAT8OID; + preftype = FLOAT8OID; break; case (DATETIME_TYPE): if (type == DATEOID) - result = TIMESTAMPOID; + preftype = TIMESTAMPOID; else - result = TIMESTAMPTZOID; + preftype = TIMESTAMPTZOID; break; case (TIMESPAN_TYPE): - result = INTERVALOID; + preftype = INTERVALOID; break; case (GEOMETRIC_TYPE): - result = type; + preftype = type; break; case (NETWORK_TYPE): - result = INETOID; + preftype = INETOID; break; case (USER_TYPE): - result = type; + preftype = type; break; default: - elog(ERROR, "PreferredType: unknown category"); - result = UNKNOWNOID; + elog(ERROR, "IsPreferredType: unknown category"); + preftype = UNKNOWNOID; break; } - return result; -} /* PreferredType() */ + + return (type == preftype); +} /* IsPreferredType() */ /* IsBinaryCoercible() * Check if srctype is binary-coercible to targettype. * * This notion allows us to cheat and directly exchange values without - * going through the trouble of calling a conversion function. + * going through the trouble of calling a conversion function. Note that + * in general, this should only be an implementation shortcut. Before 7.4, + * this was also used as a heuristic for resolving overloaded functions and + * operators, but that's basically a bad idea. * * As of 7.3, binary coercibility isn't hardwired into the code anymore. * We consider two types binary-coercible if there is an implicitly - * invokable, no-function-needed pg_cast entry. + * invokable, no-function-needed pg_cast entry. Also, a domain is always + * binary-coercible to its base type, though *not* vice versa (in the other + * direction, one must apply domain constraint checks before accepting the + * value as legitimate). * * This function replaces IsBinaryCompatible(), which was an inherently * symmetric test. Since the pg_cast entries aren't necessarily symmetric, @@ -1139,13 +1162,11 @@ IsBinaryCoercible(Oid srctype, Oid targettype) if (srctype == targettype) return true; - /* Perhaps the types are domains; if so, look at their base types */ + /* If srctype is a domain, reduce to its base type */ if (OidIsValid(srctype)) srctype = getBaseType(srctype); - if (OidIsValid(targettype)) - targettype = getBaseType(targettype); - /* Somewhat-fast path if same base type */ + /* Somewhat-fast path for domain -> base type case */ if (srctype == targettype) return true; @@ -1174,8 +1195,13 @@ IsBinaryCoercible(Oid srctype, Oid targettype) * ccontext determines the set of available casts. * * If we find a suitable entry in pg_cast, return TRUE, and set *funcid - * to the castfunc value (which may be InvalidOid for a binary-compatible - * coercion). + * to the castfunc value, which may be InvalidOid for a binary-compatible + * coercion. + * + * NOTE: *funcid == InvalidOid does not necessarily mean that no work is + * needed to do the coercion; if the target is a domain then we may need to + * apply domain constraint checking. If you want to check for a zero-effort + * conversion then use IsBinaryCoercible(). */ bool find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, @@ -1193,7 +1219,7 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, if (OidIsValid(targetTypeId)) targetTypeId = getBaseType(targetTypeId); - /* Domains are automatically binary-compatible with their base type */ + /* Domains are always coercible to and from their base type */ if (sourceTypeId == targetTypeId) return true; diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c index 058b9aad73d..e9a40e03179 100644 --- a/src/backend/parser/parse_func.c +++ b/src/backend/parser/parse_func.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.147 2003/04/29 22:13:10 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.148 2003/05/26 00:11:27 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -16,7 +16,6 @@ #include "access/heapam.h" #include "catalog/catname.h" -#include "catalog/namespace.h" #include "catalog/pg_inherits.h" #include "catalog/pg_proc.h" #include "lib/stringinfo.h" @@ -37,13 +36,7 @@ static Oid **argtype_inherit(int nargs, Oid *argtypes); static int find_inheritors(Oid relid, Oid **supervec); static Oid **gen_cross_product(InhPaths *arginh, int nargs); -static int match_argtypes(int nargs, - Oid *input_typeids, - FuncCandidateList function_typeids, - FuncCandidateList *candidates); static FieldSelect *setup_field_select(Node *input, char *attname, Oid relid); -static FuncCandidateList func_select_candidate(int nargs, Oid *input_typeids, - FuncCandidateList candidates); static void unknown_attribute(const char *schemaname, const char *relname, const char *attname); @@ -355,21 +348,24 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, } -/* match_argtypes() +/* func_match_argtypes() * - * Given a list of possible typeid arrays to a function and an array of - * input typeids, produce a shortlist of those function typeid arrays - * that match the input typeids (either exactly or by coercion), and - * return the number of such arrays. + * 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. + * one match. If no match at all, the list must remain unmodified. */ -static int -match_argtypes(int nargs, - Oid *input_typeids, - FuncCandidateList function_typeids, - FuncCandidateList *candidates) /* return value */ +int +func_match_argtypes(int nargs, + Oid *input_typeids, + FuncCandidateList raw_candidates, + FuncCandidateList *candidates) /* return value */ { FuncCandidateList current_candidate; FuncCandidateList next_candidate; @@ -377,7 +373,7 @@ match_argtypes(int nargs, *candidates = NULL; - for (current_candidate = function_typeids; + for (current_candidate = raw_candidates; current_candidate != NULL; current_candidate = next_candidate) { @@ -392,21 +388,65 @@ match_argtypes(int nargs, } return ncandidates; -} /* match_argtypes() */ +} /* func_match_argtypes() */ /* func_select_candidate() - * Given the input argtype array and more than one candidate - * for the function, attempt to resolve the conflict. + * 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. * - * By design, this is pretty similar to oper_select_candidate in parse_oper.c. - * However, the calling convention is a little different: we assume the caller - * already pruned away "candidates" that aren't actually coercion-compatible - * with the input types, whereas oper_select_candidate must do that itself. + * 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 */ -static FuncCandidateList +FuncCandidateList func_select_candidate(int nargs, Oid *input_typeids, FuncCandidateList candidates) @@ -419,59 +459,28 @@ func_select_candidate(int nargs, int ncandidates; int nbestMatch, nmatch; + Oid input_base_typeids[FUNC_MAX_ARGS]; CATEGORY slot_category[FUNC_MAX_ARGS], current_category; bool slot_has_preferred_type[FUNC_MAX_ARGS]; bool resolved_unknowns; /* - * Run through all candidates and keep those with the most matches on - * exact types. Keep all candidates if none match. + * 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. */ - 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_typeids[i] != UNKNOWNOID && - current_typeids[i] == input_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; + for (i = 0; i < nargs; i++) + input_base_typeids[i] = getBaseType(input_typeids[i]); /* - * Still too many candidates? Run through all candidates and keep - * those with the most matches on exact types + binary-compatible - * types. Keep all candidates if none match. + * Run through all candidates and keep those with the most matches on + * exact types. Keep all candidates if none match. */ ncandidates = 0; nbestMatch = 0; @@ -484,11 +493,9 @@ func_select_candidate(int nargs, nmatch = 0; for (i = 0; i < nargs; i++) { - if (input_typeids[i] != UNKNOWNOID) - { - if (IsBinaryCoercible(input_typeids[i], current_typeids[i])) - nmatch++; - } + if (input_base_typeids[i] != UNKNOWNOID && + current_typeids[i] == input_base_typeids[i]) + nmatch++; } /* take this one as the best choice so far? */ @@ -516,10 +523,14 @@ func_select_candidate(int nargs, return candidates; /* - * Still too many candidates? Now look for candidates which are - * preferred types at the args that will require coercion. Keep all - * candidates if none match. + * 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; @@ -531,11 +542,10 @@ func_select_candidate(int nargs, nmatch = 0; for (i = 0; i < nargs; i++) { - if (input_typeids[i] != UNKNOWNOID) + if (input_base_typeids[i] != UNKNOWNOID) { - current_category = TypeCategory(current_typeids[i]); - if (current_typeids[i] == input_typeids[i] || - IsPreferredType(current_category, current_typeids[i])) + if (current_typeids[i] == input_base_typeids[i] || + IsPreferredType(slot_category[i], current_typeids[i])) nmatch++; } } @@ -565,6 +575,11 @@ func_select_candidate(int nargs, * 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 @@ -588,7 +603,7 @@ func_select_candidate(int nargs, { bool have_conflict; - if (input_typeids[i] != UNKNOWNOID) + if (input_base_typeids[i] != UNKNOWNOID) continue; resolved_unknowns = true; /* assume we can do it */ slot_category[i] = INVALID_TYPE; @@ -656,7 +671,7 @@ func_select_candidate(int nargs, current_typeids = current_candidate->args; for (i = 0; i < nargs; i++) { - if (input_typeids[i] != UNKNOWNOID) + if (input_base_typeids[i] != UNKNOWNOID) continue; current_type = current_typeids[i]; current_category = TypeCategory(current_type); @@ -694,7 +709,7 @@ func_select_candidate(int nargs, if (ncandidates == 1) return candidates; - return NULL; /* failed to determine a unique candidate */ + return NULL; /* failed to select a best candidate */ } /* func_select_candidate() */ @@ -734,16 +749,17 @@ func_get_detail(List *funcname, bool *retset, /* return value */ Oid **true_typeids) /* return value */ { - FuncCandidateList function_typeids; + FuncCandidateList raw_candidates; FuncCandidateList best_candidate; /* Get list of possible candidates from namespace search */ - function_typeids = FuncnameGetCandidates(funcname, nargs); + raw_candidates = FuncnameGetCandidates(funcname, nargs); /* - * See if there is an exact match + * Quickly check if there is an exact match to the input datatypes + * (there can be only one) */ - for (best_candidate = function_typeids; + for (best_candidate = raw_candidates; best_candidate != NULL; best_candidate = best_candidate->next) { @@ -815,7 +831,7 @@ func_get_detail(List *funcname, * didn't find an exact match, so now try to match up * candidates... */ - if (function_typeids != NULL) + if (raw_candidates != NULL) { Oid **input_typeid_vector = NULL; Oid *current_input_typeids; @@ -829,17 +845,18 @@ func_get_detail(List *funcname, do { - FuncCandidateList current_function_typeids; + FuncCandidateList current_candidates; int ncandidates; - ncandidates = match_argtypes(nargs, current_input_typeids, - function_typeids, - ¤t_function_typeids); + ncandidates = func_match_argtypes(nargs, + current_input_typeids, + raw_candidates, + ¤t_candidates); /* one match only? then run with it... */ if (ncandidates == 1) { - best_candidate = current_function_typeids; + best_candidate = current_candidates; break; } @@ -851,7 +868,7 @@ func_get_detail(List *funcname, { best_candidate = func_select_candidate(nargs, current_input_typeids, - current_function_typeids); + current_candidates); /* * If we were able to choose a best candidate, we're diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c index 6238258ed2f..21f73994c42 100644 --- a/src/backend/parser/parse_oper.c +++ b/src/backend/parser/parse_oper.c @@ -8,18 +8,13 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.63 2003/04/29 22:13:10 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.64 2003/05/26 00:11:27 tgl Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" -#include "access/genam.h" -#include "access/heapam.h" -#include "catalog/catname.h" -#include "catalog/indexing.h" -#include "catalog/namespace.h" #include "catalog/pg_operator.h" #include "parser/parse_coerce.h" #include "parser/parse_expr.h" @@ -289,107 +284,29 @@ binary_oper_exact(Oid arg1, Oid arg2, /* oper_select_candidate() - * Given the input argtype array and one or more candidates - * for the function argtype array, attempt to resolve the conflict. - * Returns the selected argtype array if the conflict can be resolved, - * otherwise returns NULL. + * Given the input argtype array and one or more candidates + * for the operator, attempt to resolve the conflict. * - * By design, this is pretty similar to func_select_candidate in parse_func.c. - * However, we can do a couple of extra things here because we know we can - * have no more than two args to deal with. Also, the calling convention - * is a little different: we must prune away "candidates" that aren't actually - * coercion-compatible with the input types, whereas in parse_func.c that - * gets done by match_argtypes before func_select_candidate is called. + * Returns the OID of the selected operator if the conflict can be resolved, + * otherwise returns InvalidOid. * - * 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 + * 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 Oid oper_select_candidate(int nargs, Oid *input_typeids, FuncCandidateList candidates) { - FuncCandidateList current_candidate; - FuncCandidateList last_candidate; - Oid *current_typeids; - Oid current_type; - int unknownOids; - int i; int ncandidates; - int nbestMatch, - nmatch; - CATEGORY slot_category[FUNC_MAX_ARGS], - current_category; - bool slot_has_preferred_type[FUNC_MAX_ARGS]; - bool resolved_unknowns; /* - * First, delete any candidates that cannot actually accept the given - * input types, whether directly or by coercion. (Note that - * can_coerce_type will assume that UNKNOWN inputs are coercible to - * anything, so candidates will not be eliminated on that basis.) + * Delete any candidates that cannot actually accept the given + * input types, whether directly or by coercion. */ - ncandidates = 0; - last_candidate = NULL; - for (current_candidate = candidates; - current_candidate != NULL; - current_candidate = current_candidate->next) - { - if (can_coerce_type(nargs, input_typeids, current_candidate->args, - COERCION_IMPLICIT)) - { - if (last_candidate == NULL) - { - candidates = current_candidate; - last_candidate = current_candidate; - ncandidates = 1; - } - else - { - 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; + ncandidates = func_match_argtypes(nargs, input_typeids, + candidates, &candidates); /* Done if no candidate or only one candidate survives */ if (ncandidates == 0) @@ -398,317 +315,15 @@ oper_select_candidate(int nargs, return candidates->oid; /* - * 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_typeids[i] != UNKNOWNOID && - current_typeids[i] == input_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->oid; - - /* - * Still too many candidates? Run through all candidates and keep - * those with the most matches on exact types + binary-compatible - * 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_typeids[i] != UNKNOWNOID) - { - if (IsBinaryCoercible(input_typeids[i], current_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->oid; - - /* - * Still too many candidates? Now look for candidates which are - * preferred types at the args that will require coercion. 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_typeids[i] != UNKNOWNOID) - { - current_category = TypeCategory(current_typeids[i]); - if (current_typeids[i] == input_typeids[i] || - IsPreferredType(current_category, 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->oid; - - /* - * Still too many candidates? Try assigning types for the unknown - * columns. - * - * First try: if we have an unknown and a non-unknown input, see whether - * there is a candidate all of whose input types are the same as the - * known input type (there can be at most one such candidate). If so, - * use that candidate. NOTE that this is cool only because operators - * can't have more than 2 args, so taking the last non-unknown as - * current_type can yield only one possibility if there is also an - * unknown. - */ - unknownOids = FALSE; - current_type = UNKNOWNOID; - for (i = 0; i < nargs; i++) - { - if ((input_typeids[i] != UNKNOWNOID) - && (input_typeids[i] != InvalidOid)) - current_type = input_typeids[i]; - else - unknownOids = TRUE; - } - - if (unknownOids && (current_type != UNKNOWNOID)) - { - 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 (current_type == current_typeids[i]) - nmatch++; - } - if (nmatch == nargs) - return current_candidate->oid; - } - } - - /* - * Second try: same algorithm as for unknown resolution in - * parse_func.c. - * - * 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. + * Use the same heuristics as for ambiguous functions to resolve + * the conflict. */ - resolved_unknowns = false; - for (i = 0; i < nargs; i++) - { - bool have_conflict; - - if (input_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; - } - } + candidates = func_select_candidate(nargs, input_typeids, candidates); - 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_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) + if (candidates) return candidates->oid; - return InvalidOid; /* failed to determine a unique candidate */ + return InvalidOid; /* failed to select a best candidate */ } /* oper_select_candidate() */ @@ -751,7 +366,7 @@ oper(List *opname, Oid ltypeId, Oid rtypeId, bool noError) /* * Unspecified type for one of the arguments? then use the - * other + * other (XXX this is probably dead code?) */ if (rtypeId == InvalidOid) rtypeId = ltypeId; |