diff options
author | Thomas G. Lockhart <lockhart@fourpalms.org> | 1998-05-29 14:00:24 +0000 |
---|---|---|
committer | Thomas G. Lockhart <lockhart@fourpalms.org> | 1998-05-29 14:00:24 +0000 |
commit | 8536c962614a55d33baa283a7901bb167a43978a (patch) | |
tree | d674201859f82cf92296a5fc079b5bfcaf1c4f8b /src/backend/parser/parse_oper.c | |
parent | 329083a97e2b5de1191f50451a253c224c833605 (diff) | |
download | postgresql-8536c962614a55d33baa283a7901bb167a43978a.tar.gz postgresql-8536c962614a55d33baa283a7901bb167a43978a.zip |
Do type conversion to match columns in UNION clauses.
Currently force the type to match the _first_ select in the union.
Move oper_select_candidate() from parse_func.c to parse_oper.c.
Throw error inside of oper_inexact() if no match for binary operators.
Check more carefully that types can be coerced
even if there is only one candidate operator in oper_inexact().
Fix up error messages for more uniform look.
Remove unused code.
Fix up comments.
Diffstat (limited to 'src/backend/parser/parse_oper.c')
-rw-r--r-- | src/backend/parser/parse_oper.c | 787 |
1 files changed, 430 insertions, 357 deletions
diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c index 2e43b1380fc..7042e4740fc 100644 --- a/src/backend/parser/parse_oper.c +++ b/src/backend/parser/parse_oper.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.11 1998/05/09 23:29:53 thomas Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.12 1998/05/29 14:00:22 thomas Exp $ * *------------------------------------------------------------------------- */ @@ -21,37 +21,27 @@ #include "catalog/pg_operator.h" #include "catalog/pg_type.h" #include "fmgr.h" +#include "parser/parse_func.h" #include "parser/parse_oper.h" #include "parser/parse_type.h" #include "parser/parse_coerce.h" #include "storage/bufmgr.h" #include "utils/syscache.h" -extern -Oid * -func_select_candidate(int nargs, Oid *input_typeids, CandidateList candidates); - -extern Oid * oper_select_candidate(int nargs, Oid *input_typeids, CandidateList candidates); - static int binary_oper_get_candidates(char *opname, Oid leftTypeId, Oid rightTypeId, CandidateList *candidates); -static CandidateList -binary_oper_select_candidate(Oid arg1, - Oid arg2, - CandidateList candidates); -static bool equivalentOpersAfterPromotion(CandidateList candidates); -static void op_error(char *op, Oid arg1, Oid arg2); static int unary_oper_get_candidates(char *op, Oid typeId, CandidateList *candidates, char rightleft); - +static void +op_error(char *op, Oid arg1, Oid arg2); Oid any_ordering_op(int restype) @@ -59,7 +49,13 @@ any_ordering_op(int restype) Operator order_op; Oid order_opid; - order_op = oper("<", restype, restype, false); + order_op = oper("<", restype, restype, TRUE); + if (!HeapTupleIsValid(order_op)) + { + elog(ERROR, "Unable to find an ordering operator '%s' for type %s." + "\n\tUse an explicit ordering operator or modify the query.", + "<", typeidTypeName(restype)); + } order_opid = oprid(order_op); return order_opid; @@ -107,44 +103,12 @@ binary_oper_get_candidates(char *opname, F_CHAREQ, CharGetDatum('b')); -#if FALSE - if (leftTypeId == UNKNOWNOID) - { - if (rightTypeId == UNKNOWNOID) - { - nkeys = 2; - } - else - { - nkeys = 3; - - ScanKeyEntryInitialize(&opKey[2], 0, - Anum_pg_operator_oprright, - ObjectIdEqualRegProcedure, - ObjectIdGetDatum(rightTypeId)); - } - } - else if (rightTypeId == UNKNOWNOID) - { - nkeys = 3; - - ScanKeyEntryInitialize(&opKey[2], 0, - Anum_pg_operator_oprleft, - ObjectIdEqualRegProcedure, - ObjectIdGetDatum(leftTypeId)); - } - else - { - /* currently only "unknown" can be coerced */ - return 0; -#endif - nkeys = 2; pg_operator_desc = heap_openr(OperatorRelationName); pg_operator_scan = heap_beginscan(pg_operator_desc, 0, - true, + TRUE, nkeys, opKey); @@ -173,288 +137,400 @@ binary_oper_get_candidates(char *opname, } /* binary_oper_get_candidates() */ -#if FALSE -/* BinaryOperCandidates() - * Given opname, leftTypeId and rightTypeId, - * find all possible (arg1, arg2) pairs for which an operator named - * opname exists, such that leftTypeId can be coerced to arg1 and - * rightTypeId can be coerced to arg2. +/* 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, + * otherwise returns NULL. + * + * 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 coersions 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 int -BinaryOperCandidates(char *opname, - Oid lTypeId, - Oid rTypeId, - CandidateList *candidates) +Oid * +oper_select_candidate(int nargs, + Oid *input_typeids, + CandidateList candidates) { - CandidateList current_candidate; - Relation pg_operator_desc; - HeapScanDesc pg_operator_scan; - HeapTuple tup; - OperatorTupleForm oper; - Buffer buffer; - int nkeys; - int ncandidates = 0; - ScanKeyData opKey[3]; + CandidateList current_candidate; + CandidateList last_candidate; + Oid *current_typeids; + int unknownOids; + int i; - /* Can we promote the lesser type and find a match? */ - lCandidateTypeId = lTypeId; - rCandidateTypeId = rTypeId; - higherTypeId = PromoteLowerType(&lCandidateTypeId, &rCandidateTypeId); - if (lTypeId != higherTypeId) - lowerTypeId = lTypeId; - else - lowerTypeId = rTypeId; - - while (lCandidateTypeId != rCandidateTypeId) - if ((lCandidateTypeId == InvalidOid) || (rCandidateTypeId == InvalidOid)) - break; - - tup = SearchSysCacheTuple(OPRNAME, - PointerGetDatum(op), - ObjectIdGetDatum(lCandidateTypeId), - ObjectIdGetDatum(rCandidateTypeId), - Int8GetDatum('b')); - if (HeapTupleIsValid(tup)) - return ((Operator) tup); + int ncandidates; + int nbestMatch, + nmatch; - PromoteLowerType(&lCandidateTypeId, &rCandidateTypeId); - } + CATEGORY slot_category, + current_category; + Oid slot_type, + current_type; - /* Can we promote the lesser type directly to the other? */ - if (can_coerce_type(lowerTypeId, higherTypeId)) +/* + * Run through all candidates and keep those with the most matches + * on explicit 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) { - tup = SearchSysCacheTuple(OPRNAME, - PointerGetDatum(op), - ObjectIdGetDatum(higherTypeId), - ObjectIdGetDatum(higherTypeId), - Int8GetDatum('b')); - if (HeapTupleIsValid(tup)) - return ((Operator) tup); - } - - - *candidates = NULL; - - ScanKeyEntryInitialize(&opKey[0], 0, - Anum_pg_operator_oprname, - NameEqualRegProcedure, - NameGetDatum(opname)); - - ScanKeyEntryInitialize(&opKey[1], 0, - Anum_pg_operator_oprkind, - CharacterEqualRegProcedure, - CharGetDatum('b')); + 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++; + } + } -#if FALSE - if (leftTypeId == UNKNOWNOID) - { - if (rightTypeId == UNKNOWNOID) +#ifdef PARSEDEBUG +printf("oper_select_candidate- candidate has %d matches\n", nmatch); +#endif + if ((nmatch > nbestMatch) || (last_candidate == NULL)) + { + nbestMatch = nmatch; + candidates = current_candidate; + last_candidate = current_candidate; + ncandidates = 1; +#ifdef PARSEDEBUG +printf("oper_select_candidate- choose candidate as best match\n"); +#endif + } + else if (nmatch == nbestMatch) { - nkeys = 2; + last_candidate->next = current_candidate; + last_candidate = current_candidate; + ncandidates++; +#ifdef PARSEDEBUG +printf("oper_select_candidate- choose candidate as possible match\n"); +#endif } else { - nkeys = 3; - - ScanKeyEntryInitialize(&opKey[2], 0, - Anum_pg_operator_oprright, - F_OIDEQ, - ObjectIdGetDatum(rightTypeId)); + last_candidate->next = NULL; +#ifdef PARSEDEBUG +printf("oper_select_candidate- reject candidate as possible match\n"); +#endif } } - else if (rightTypeId == UNKNOWNOID) - { - nkeys = 3; - ScanKeyEntryInitialize(&opKey[2], 0, - Anum_pg_operator_oprleft, - F_OIDEQ, - ObjectIdGetDatum(leftTypeId)); - } - else + if (ncandidates <= 1) { - /* currently only "unknown" can be coerced */ - return 0; -#endif - - nkeys = 2; - - pg_operator_desc = heap_openr(OperatorRelationName); - pg_operator_scan = heap_beginscan(pg_operator_desc, - 0, - true, - nkeys, - opKey); + if (!can_coerce_type(1, &input_typeids[0], &candidates->args[0]) + || !can_coerce_type(1, &input_typeids[1], &candidates->args[1])) + { + ncandidates = 0; + } + return ((ncandidates == 1)? candidates->args: NULL); + } - do +/* + * Still too many candidates? + * Now look for candidates which allow coersion and are preferred 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) { - tup = heap_getnext(pg_operator_scan, 0, &buffer); - if (HeapTupleIsValid(tup)) + current_typeids = current_candidate->args; + nmatch = 0; + for (i = 0; i < nargs; i++) { - current_candidate = (CandidateList) palloc(sizeof(struct _CandidateList)); - current_candidate->args = (Oid *) palloc(2 * sizeof(Oid)); + current_category = TypeCategory(current_typeids[i]); + if (input_typeids[i] != UNKNOWNOID) + { + 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])) + { + nmatch++; + } + } + } - oper = (OperatorTupleForm) GETSTRUCT(tup); - current_candidate->args[0] = oper->oprleft; - current_candidate->args[1] = oper->oprright; - current_candidate->next = *candidates; - *candidates = current_candidate; +#ifdef PARSEDEBUG +printf("oper_select_candidate- candidate has %d matches\n", nmatch); +#endif + if ((nmatch > nbestMatch) || (last_candidate == NULL)) + { + nbestMatch = nmatch; + candidates = current_candidate; + last_candidate = current_candidate; + ncandidates = 1; +#ifdef PARSEDEBUG +printf("oper_select_candidate- choose candidate as best match\n"); +#endif + } + else if (nmatch == nbestMatch) + { + last_candidate->next = current_candidate; + last_candidate = current_candidate; ncandidates++; - ReleaseBuffer(buffer); +#ifdef PARSEDEBUG +printf("oper_select_candidate- choose candidate as possible match\n"); +#endif } - } while (HeapTupleIsValid(tup)); - - heap_endscan(pg_operator_scan); - heap_close(pg_operator_desc); - - return ncandidates; -} /* BinaryOperCandidates() */ + else + { + last_candidate->next = NULL; +#ifdef PARSEDEBUG +printf("oper_select_candidate- reject candidate as possible match\n"); #endif + } + } + if (ncandidates <= 1) + { + if (!can_coerce_type(1, &input_typeids[0], &candidates->args[0]) + || !can_coerce_type(1, &input_typeids[1], &candidates->args[1])) + { + ncandidates = 0; +#ifdef PARSEDEBUG +printf("oper_select_candidate- unable to coerce preferred candidate\n"); +#endif + } + return ((ncandidates == 1)? candidates->args: NULL); + } /* - * equivalentOpersAfterPromotion - - * checks if a list of candidate operators obtained from - * binary_oper_get_candidates() contain equivalent operators. If - * this routine is called, we have more than 1 candidate and need to - * decided whether to pick one of them. This routine returns true if - * all the candidates operate on the same data types after - * promotion (int2, int4, float4 -> float8). + * Still too many candidates? + * Try assigning types for the unknown columns. */ -static bool -equivalentOpersAfterPromotion(CandidateList candidates) -{ - CandidateList result; - CandidateList promotedCandidates = NULL; - Oid leftarg, - rightarg; + 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; + } + } - for (result = candidates; result != NULL; result = result->next) + if (unknownOids && (current_type != UNKNOWNOID)) { - CandidateList c; + for (current_candidate = candidates; + current_candidate != NULL; + current_candidate = current_candidate->next) + { + nmatch = 0; + for (i = 0; i < nargs; i++) + { + current_typeids = current_candidate->args; + if ((current_type == current_typeids[i]) + || IS_BINARY_COMPATIBLE(current_type, current_typeids[i])) + nmatch++; + } + if (nmatch == nargs) + return (candidates->args); + } + } - c = (CandidateList) palloc(sizeof(*c)); - c->args = (Oid *) palloc(2 * sizeof(Oid)); - switch (result->args[0]) + for (i = 0; i < nargs; i++) + { + if (input_typeids[i] == UNKNOWNOID) { - case FLOAT4OID: - case INT4OID: - case INT2OID: - case CASHOID: - c->args[0] = FLOAT8OID; - break; - default: - c->args[0] = result->args[0]; - break; + slot_category = INVALID_TYPE; + slot_type = InvalidOid; + 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_typeids[i]); + if (slot_category == InvalidOid) + { + slot_category = current_category; + slot_type = current_type; +#ifdef PARSEDEBUG +printf("oper_select_candidate- assign column #%d first candidate slot type %s\n", + i, typeidTypeName(current_type)); +#endif + } + else if (current_category != slot_category) + { +#ifdef PARSEDEBUG +printf("oper_select_candidate- multiple possible types for column #%d; unable to choose candidate\n", i); +#endif + return NULL; + } + else if (current_type != slot_type) + { + if (IsPreferredType(slot_category, current_type)) + { + slot_type = current_type; + candidates = current_candidate; +#ifdef PARSEDEBUG +printf("oper_select_candidate- column #%d found preferred candidate type %s\n", + i, typeidTypeName(slot_type)); +#endif + } + else + { +#ifdef PARSEDEBUG +printf("oper_select_candidate- column #%d found possible candidate type %s\n", + i, typeidTypeName(current_type)); +#endif + } + } + } + + if (slot_type != InvalidOid) + { + input_typeids[i] = slot_type; +#ifdef PARSEDEBUG +printf("oper_select_candidate- assign column #%d slot type %s\n", + i, typeidTypeName(input_typeids[i])); +#endif + } } - switch (result->args[1]) + else { - case FLOAT4OID: - case INT4OID: - case INT2OID: - case CASHOID: - c->args[1] = FLOAT8OID; - break; - default: - c->args[1] = result->args[1]; - break; +#ifdef PARSEDEBUG +printf("oper_select_candidate- column #%d input type is %s\n", + i, typeidTypeName(input_typeids[i])); +#endif } - c->next = promotedCandidates; - promotedCandidates = c; } - /* - * if we get called, we have more than 1 candidates so we can do the - * following safely - */ - leftarg = promotedCandidates->args[0]; - rightarg = promotedCandidates->args[1]; - - for (result = promotedCandidates->next; result != NULL; result = result->next) + ncandidates = 0; + for (current_candidate = candidates; + current_candidate != NULL; + current_candidate = current_candidate->next) { - if (result->args[0] != leftarg || result->args[1] != rightarg) - - /* - * this list contains operators that operate on different data - * types even after promotion. Hence we can't decide on which - * one to pick. The user must do explicit type casting. - */ - return FALSE; + if (can_coerce_type(1, &input_typeids[0], ¤t_candidate->args[0]) + && can_coerce_type(1, &input_typeids[1], ¤t_candidate->args[1])) + ncandidates++; } - /* - * all the candidates are equivalent in the following sense: they - * operate on equivalent data types and picking any one of them is as - * good. - */ - return TRUE; -} + return ((ncandidates == 1)? candidates->args: NULL); +} /* oper_select_candidate() */ -/* binary_oper_select_candidate() - * Given a choice of argument type pairs for a binary operator, - * try to choose a default pair. - * - * 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 +/* oper_exact() + * Given operator, and arguments, return oper struct. + * Inputs: + * arg1, arg2: Type IDs */ -static CandidateList -binary_oper_select_candidate(Oid arg1, - Oid arg2, - CandidateList candidates) +Operator +oper_exact(char *op, Oid arg1, Oid arg2, Node **ltree, Node **rtree, bool noWarnings) { - CandidateList result; + HeapTuple tup; + Node *tree; - /* - * If both are "unknown", there is no way to select a candidate - */ - if (arg1 == UNKNOWNOID && arg2 == UNKNOWNOID) - return (NULL); + /* Unspecified type for one of the arguments? then use the other */ + if ((arg1 == UNKNOWNOID) && (arg2 != InvalidOid)) arg1 = arg2; + else if ((arg2 == UNKNOWNOID) && (arg1 != InvalidOid)) arg2 = arg1; - if (!equivalentOpersAfterPromotion(candidates)) - return NULL; + tup = SearchSysCacheTuple(OPRNAME, + PointerGetDatum(op), + ObjectIdGetDatum(arg1), + ObjectIdGetDatum(arg2), + Int8GetDatum('b')); - /* - * if we get here, any one will do but we're more picky and require - * both operands be the same. - */ - for (result = candidates; result != NULL; result = result->next) + /* Did not find anything? then try flipping arguments on a commutative operator... */ + if (!HeapTupleIsValid(tup) && (arg1 != arg2)) { - if (result->args[0] == result->args[1]) - return result; + tup = SearchSysCacheTuple(OPRNAME, + PointerGetDatum(op), + ObjectIdGetDatum(arg2), + ObjectIdGetDatum(arg1), + Int8GetDatum('b')); + + if (HeapTupleIsValid(tup)) + { + OperatorTupleForm opform; + +#if PARSEDEBUG +printf("oper_exact: found possible commutative operator candidate\n"); +#endif + opform = (OperatorTupleForm) GETSTRUCT(tup); + if (opform->oprcom == tup->t_oid) + { +#if PARSEDEBUG +printf("oper_exact: commutative operator found\n"); +#endif + if ((ltree != NULL) && (rtree != NULL)) + { + tree = *ltree; + *ltree = *rtree; + *rtree = tree; + } + } + /* disable for now... - thomas 1998-05-14 */ + else + { + tup = NULL; + } + } + if (!HeapTupleIsValid(tup) && (!noWarnings)) + { + op_error(op, arg1, arg2); + } } - return (NULL); -} + return tup; +} /* oper_exact() */ -/* oper() + +/* oper_inexact() * Given operator, types of arg1, and arg2, return oper struct. * Inputs: * arg1, arg2: Type IDs */ Operator -oper(char *op, Oid arg1, Oid arg2, bool noWarnings) +oper_inexact(char *op, Oid arg1, Oid arg2, Node **ltree, Node **rtree, bool noWarnings) { HeapTuple tup; CandidateList candidates; @@ -468,78 +544,96 @@ oper(char *op, Oid arg1, Oid arg2, bool noWarnings) if (arg1 == InvalidOid) arg1 = arg2; - tup = SearchSysCacheTuple(OPRNAME, - PointerGetDatum(op), - ObjectIdGetDatum(arg1), - ObjectIdGetDatum(arg2), - Int8GetDatum('b')); + ncandidates = binary_oper_get_candidates(op, arg1, arg2, &candidates); - /* Did not find anything? then look more carefully... */ - if (!HeapTupleIsValid(tup)) + /* No operators found? Then throw error or return null... */ + if (ncandidates == 0) { - ncandidates = binary_oper_get_candidates(op, arg1, arg2, &candidates); + if (!noWarnings) + op_error(op, arg1, arg2); + return (NULL); + } - /* No operators found? Then throw error or return null... */ - if (ncandidates == 0) - { - if (!noWarnings) - op_error(op, arg1, arg2); - return (NULL); - } + /* Or found exactly one? Then proceed... */ + else if (ncandidates == 1) + { + tup = SearchSysCacheTuple(OPRNAME, + PointerGetDatum(op), + ObjectIdGetDatum(candidates->args[0]), + ObjectIdGetDatum(candidates->args[1]), + Int8GetDatum('b')); + Assert(HeapTupleIsValid(tup)); - /* Or found exactly one? Then proceed... */ - else if (ncandidates == 1) +#if PARSEDEBUG +printf("oper_inexact: found single candidate\n"); +#endif + + } + + /* Otherwise, multiple operators of the desired types found... */ + else + { + inputOids[0] = arg1; + inputOids[1] = arg2; + targetOids = oper_select_candidate(2, inputOids, candidates); + if (targetOids != NULL) { +#if PARSEDEBUG +printf("oper_inexact: found candidate\n"); +#endif tup = SearchSysCacheTuple(OPRNAME, PointerGetDatum(op), - ObjectIdGetDatum(candidates->args[0]), - ObjectIdGetDatum(candidates->args[1]), + ObjectIdGetDatum(targetOids[0]), + ObjectIdGetDatum(targetOids[1]), Int8GetDatum('b')); - Assert(HeapTupleIsValid(tup)); - } - /* Otherwise, multiple operators of the desired types found... */ + } else { -#if FALSE - candidates = binary_oper_select_candidate(arg1, arg2, candidates); -#endif - inputOids[0] = arg1; - inputOids[1] = arg2; - targetOids = oper_select_candidate(2, inputOids, candidates); -#if FALSE - targetOids = func_select_candidate(2, inputOids, candidates); -#endif - if (targetOids != NULL) - { -#if PARSEDEBUG -printf("oper: found candidate\n"); -#endif - tup = SearchSysCacheTuple(OPRNAME, - PointerGetDatum(op), - ObjectIdGetDatum(targetOids[0]), - ObjectIdGetDatum(targetOids[1]), - Int8GetDatum('b')); - } - else - { - tup = NULL; - } + tup = NULL; + } - /* Could not choose one, for whatever reason... */ - if (!HeapTupleIsValid(tup)) + /* Could not choose one, for whatever reason... */ + if (!HeapTupleIsValid(tup)) + { + if (!noWarnings) { - if (!noWarnings) - { - elog(ERROR, "There is more than one operator '%s' for types '%s' and '%s'" - "\n\tYou will have to retype this query using an explicit cast", - op, typeTypeName(typeidType(arg1)), typeTypeName(typeidType(arg2))); - } - return (NULL); + elog(ERROR, "There is more than one possible operator '%s' for types '%s' and '%s'" + "\n\tYou will have to retype this query using an explicit cast", + op, typeTypeName(typeidType(arg1)), typeTypeName(typeidType(arg2))); } + return (NULL); } } return ((Operator) tup); +} /* oper_inexact() */ + + +/* oper() + * Given operator, types of arg1, and arg2, return oper struct. + * Inputs: + * arg1, arg2: Type IDs + */ +Operator +oper(char *opname, Oid ltypeId, Oid rtypeId, bool noWarnings) +{ + HeapTuple tup; + + /* check for exact match on this operator... */ + if (HeapTupleIsValid(tup = oper_exact(opname, ltypeId, rtypeId, NULL, NULL, TRUE))) + { + } + /* try to find a match on likely candidates... */ + else if (HeapTupleIsValid(tup = oper_inexact(opname, ltypeId, rtypeId, NULL, NULL, TRUE))) + { + } + else if (!noWarnings) + { + elog(ERROR, "Unable to find binary operator '%s' for types %s and %s", + opname, typeTypeName(typeidType(ltypeId)), typeTypeName(typeidType(rtypeId))); + } + + return ((Operator) tup); } /* oper() */ @@ -573,26 +667,13 @@ unary_oper_get_candidates(char *op, fmgr_info(F_CHAREQ, (FmgrInfo *) &opKey[1].sk_func); opKey[1].sk_argument = CharGetDatum(rightleft); -#if FALSE - /* currently, only "unknown" can be coerced */ - - /* - * but we should allow types that are internally the same to be - * "coerced" - */ - if (typeId != UNKNOWNOID) - { - return 0; - } -#endif - #ifdef PARSEDEBUG printf("unary_oper_get_candidates: start scan for '%s'\n", op); #endif pg_operator_desc = heap_openr(OperatorRelationName); pg_operator_scan = heap_beginscan(pg_operator_desc, 0, - true, + TRUE, 2, opKey); @@ -658,17 +739,13 @@ right_oper(char *op, Oid arg) { tup = SearchSysCacheTuple(OPRNAME, PointerGetDatum(op), - ObjectIdGetDatum(candidates->args[0]), + ObjectIdGetDatum(candidates->args[0]), ObjectIdGetDatum(InvalidOid), Int8GetDatum('r')); Assert(HeapTupleIsValid(tup)); } else { -#if FALSE - elog(ERROR, "There is more than one right operator %s" - "\n\tYou will have to retype this query using an explicit cast", op); -#endif targetOid = func_select_candidate(1, &arg, candidates); if (targetOid != NULL) @@ -735,10 +812,6 @@ printf("left_oper: searched cache for single left oper candidate '%s %s'\n", } else { -#if FALSE - elog(ERROR, "There is more than one left operator %s" - "\n\tYou will have to retype this query using an explicit cast", op); -#endif targetOid = func_select_candidate(1, &arg, candidates); tup = SearchSysCacheTuple(OPRNAME, PointerGetDatum(op), @@ -779,7 +852,7 @@ op_error(char *op, Oid arg1, Oid arg2) else { elog(ERROR, "Left hand side of operator '%s' has an unknown type" - "\n\tProbably a bad attribute name", op); + "\n\tProbably a bad attribute name", op); } if (typeidIsValid(arg2)) @@ -789,11 +862,11 @@ op_error(char *op, Oid arg1, Oid arg2) else { elog(ERROR, "Right hand side of operator %s has an unknown type" - "\n\tProbably a bad attribute name", op); + "\n\tProbably a bad attribute name", op); } elog(ERROR, "There is no operator '%s' for types '%s' and '%s'" "\n\tYou will either have to retype this query using an explicit cast," - "\n\tor you will have to define the operator using CREATE OPERATOR", + "\n\tor you will have to define the operator using CREATE OPERATOR", op, typeTypeName(tp1), typeTypeName(tp2)); } |