diff options
Diffstat (limited to 'src/backend/parser/parse_oper.c')
-rw-r--r-- | src/backend/parser/parse_oper.c | 267 |
1 files changed, 169 insertions, 98 deletions
diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c index c944d235784..fd41f4f3a0f 100644 --- a/src/backend/parser/parse_oper.c +++ b/src/backend/parser/parse_oper.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.38 2000/03/18 19:53:54 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.39 2000/03/19 00:19:39 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -30,10 +30,9 @@ static Operator oper_exact(char *op, Oid arg1, Oid arg2); static Operator oper_inexact(char *op, Oid arg1, Oid arg2); static int binary_oper_get_candidates(char *opname, CandidateList *candidates); -static int unary_oper_get_candidates(char *op, - Oid typeId, - CandidateList *candidates, - char rightleft); +static int unary_oper_get_candidates(char *opname, + CandidateList *candidates, + char rightleft); static void op_error(char *op, Oid arg1, Oid arg2); static void unary_op_error(char *op, Oid arg, bool is_left_op); @@ -66,7 +65,8 @@ oprid(Operator op) /* binary_oper_get_candidates() * given opname, find all possible input type pairs for which an operator - * named opname exists. Build a list of the candidate input types. + * named opname exists. + * Build a list of the candidate input types. * Returns number of candidates found. */ static int @@ -79,7 +79,7 @@ binary_oper_get_candidates(char *opname, HeapTuple tup; Form_pg_operator oper; int ncandidates = 0; - ScanKeyData opKey[3]; + ScanKeyData opKey[2]; *candidates = NULL; @@ -102,10 +102,11 @@ binary_oper_get_candidates(char *opname, while (HeapTupleIsValid(tup = heap_getnext(pg_operator_scan, 0))) { + oper = (Form_pg_operator) GETSTRUCT(tup); + current_candidate = (CandidateList) palloc(sizeof(struct _CandidateList)); current_candidate->args = (Oid *) palloc(2 * sizeof(Oid)); - oper = (Form_pg_operator) GETSTRUCT(tup); current_candidate->args[0] = oper->oprleft; current_candidate->args[1] = oper->oprright; current_candidate->next = *candidates; @@ -123,9 +124,16 @@ binary_oper_get_candidates(char *opname, /* oper_select_candidate() * Given the input argtype array and more than one candidate * for the function argtype array, attempt to resolve the conflict. - * returns the selected argtype array if the conflict can be resolved, + * Returns the selected argtype array if the conflict can be resolved, * otherwise returns NULL. * + * 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. + * * 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. @@ -173,20 +181,57 @@ oper_select_candidate(int nargs, Oid *current_typeids; int unknownOids; int i; - int ncandidates; int nbestMatch, nmatch; - CATEGORY slot_category, current_category; Oid slot_type, current_type; -/* - * Run through all candidates and keep those with the most matches - * on exact types. Keep all candidates if none match. - */ + /* + * 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.) + */ + 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)) + { + 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; + + /* Done if no candidate or only one candidate survives */ + if (ncandidates == 0) + return NULL; + if (ncandidates == 1) + return candidates->args; + + /* + * 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; @@ -198,8 +243,8 @@ oper_select_candidate(int nargs, nmatch = 0; for (i = 0; i < nargs; i++) { - if ((input_typeids[i] != UNKNOWNOID) - && (current_typeids[i] == input_typeids[i])) + if (input_typeids[i] != UNKNOWNOID && + current_typeids[i] == input_typeids[i]) nmatch++; } @@ -224,21 +269,15 @@ oper_select_candidate(int nargs, if (last_candidate) /* terminate rebuilt list */ last_candidate->next = NULL; - if (ncandidates <= 1) - { - if (ncandidates > 0) - { - if (!can_coerce_type(nargs, input_typeids, candidates->args)) - ncandidates = 0; - } - return (ncandidates == 1) ? candidates->args : NULL; - } + if (ncandidates == 1) + return candidates->args; -/* - * Still too many candidates? - * Now look for candidates which allow coercion and are preferred types. - * Keep all candidates if none match. - */ + /* + * 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; @@ -252,15 +291,14 @@ oper_select_candidate(int nargs, { if (input_typeids[i] != UNKNOWNOID) { - current_category = TypeCategory(current_typeids[i]); - if (current_typeids[i] == input_typeids[i]) - nmatch++; - else if (IsPreferredType(current_category, current_typeids[i]) - && can_coerce_type(1, &input_typeids[i], ¤t_typeids[i])) + if (current_typeids[i] == input_typeids[i] || + IS_BINARY_COMPATIBLE(current_typeids[i], + input_typeids[i])) nmatch++; } } + /* take this one as the best choice so far? */ if ((nmatch > nbestMatch) || (last_candidate == NULL)) { nbestMatch = nmatch; @@ -268,38 +306,80 @@ oper_select_candidate(int nargs, 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) + if (ncandidates == 1) + return candidates->args; + + /* + * 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) { - if (ncandidates > 0) + 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) { - if (!can_coerce_type(nargs, input_typeids, candidates->args)) - ncandidates = 0; + last_candidate->next = current_candidate; + last_candidate = current_candidate; + ncandidates++; } - return (ncandidates == 1) ? candidates->args : NULL; } -/* - * 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. - */ + if (last_candidate) /* terminate rebuilt list */ + last_candidate->next = NULL; + + if (ncandidates == 1) + return candidates->args; + + /* + * 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++) @@ -325,25 +405,22 @@ oper_select_candidate(int nargs, nmatch++; } if (nmatch == nargs) - { - /* coercion check here is probably redundant, but be safe */ - if (can_coerce_type(nargs, input_typeids, current_typeids)) - return current_typeids; - } + return current_typeids; } } -/* - * Second try: examine each unknown argument position to see if all the - * candidates agree on the type category of that slot. If so, and if some - * candidates accept the preferred type in that category, eliminate the - * candidates with other input types. If we are down to one candidate - * at the end, we win. - * - * XXX It's kinda bogus to do this left-to-right, isn't it? If we eliminate - * some candidates because they are non-preferred at the first slot, we won't - * notice that they didn't have the same type category for a later slot. - */ + /* + * Second try: examine each unknown argument position to see if all the + * candidates agree on the type category of that slot. If so, and if some + * candidates accept the preferred type in that category, eliminate the + * candidates with other input types. If we are down to one candidate + * at the end, we win. + * + * XXX It's kinda bogus to do this left-to-right, isn't it? If we + * eliminate some candidates because they are non-preferred at the first + * slot, we won't notice that they didn't have the same type category for + * a later slot. + */ for (i = 0; i < nargs; i++) { if (input_typeids[i] == UNKNOWNOID) @@ -400,20 +477,11 @@ oper_select_candidate(int nargs, } } - 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)) - { - ncandidates++; - last_candidate = current_candidate; - } - } - - return (ncandidates == 1) ? last_candidate->args : NULL; + if (candidates == NULL) + return NULL; /* no remaining candidates */ + if (candidates->next != NULL) + return NULL; /* more than one remaining candidate */ + return candidates->args; } /* oper_select_candidate() */ @@ -529,13 +597,13 @@ oper(char *opname, Oid ltypeId, Oid rtypeId, bool noWarnings) /* unary_oper_get_candidates() - * given opname and typeId, find all possible types for which - * a right/left unary operator named opname exists, - * such that typeId can be coerced to it + * given opname, find all possible types for which + * a right/left unary operator named opname exists. + * Build a list of the candidate input types. + * Returns number of candidates found. */ static int -unary_oper_get_candidates(char *op, - Oid typeId, +unary_oper_get_candidates(char *opname, CandidateList *candidates, char rightleft) { @@ -545,17 +613,19 @@ unary_oper_get_candidates(char *op, HeapTuple tup; Form_pg_operator oper; int ncandidates = 0; - - static ScanKeyData opKey[2] = { - {0, Anum_pg_operator_oprname, F_NAMEEQ}, - {0, Anum_pg_operator_oprkind, F_CHAREQ}}; + ScanKeyData opKey[2]; *candidates = NULL; - fmgr_info(F_NAMEEQ, (FmgrInfo *) &opKey[0].sk_func); - opKey[0].sk_argument = NameGetDatum(op); - fmgr_info(F_CHAREQ, (FmgrInfo *) &opKey[1].sk_func); - opKey[1].sk_argument = CharGetDatum(rightleft); + ScanKeyEntryInitialize(&opKey[0], 0, + Anum_pg_operator_oprname, + F_NAMEEQ, + NameGetDatum(opname)); + + ScanKeyEntryInitialize(&opKey[1], 0, + Anum_pg_operator_oprkind, + F_CHAREQ, + CharGetDatum(rightleft)); pg_operator_desc = heap_openr(OperatorRelationName, AccessShareLock); pg_operator_scan = heap_beginscan(pg_operator_desc, @@ -566,10 +636,11 @@ unary_oper_get_candidates(char *op, while (HeapTupleIsValid(tup = heap_getnext(pg_operator_scan, 0))) { + oper = (Form_pg_operator) GETSTRUCT(tup); + current_candidate = (CandidateList) palloc(sizeof(struct _CandidateList)); current_candidate->args = (Oid *) palloc(sizeof(Oid)); - oper = (Form_pg_operator) GETSTRUCT(tup); if (rightleft == 'r') current_candidate->args[0] = oper->oprleft; else @@ -606,7 +677,7 @@ right_oper(char *op, Oid arg) if (!HeapTupleIsValid(tup)) { /* Try for inexact matches */ - ncandidates = unary_oper_get_candidates(op, arg, &candidates, 'r'); + ncandidates = unary_oper_get_candidates(op, &candidates, 'r'); if (ncandidates == 0) { unary_op_error(op, arg, FALSE); @@ -658,7 +729,7 @@ left_oper(char *op, Oid arg) if (!HeapTupleIsValid(tup)) { /* Try for inexact matches */ - ncandidates = unary_oper_get_candidates(op, arg, &candidates, 'l'); + ncandidates = unary_oper_get_candidates(op, &candidates, 'l'); if (ncandidates == 0) { unary_op_error(op, arg, TRUE); |