diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2002-11-29 21:39:12 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2002-11-29 21:39:12 +0000 |
commit | f68f11928d5c791873073c882775dae10283ff49 (patch) | |
tree | 628e4491fe33cdafb0e205d73e29b154ef68f94b /src/backend/parser/parse_oper.c | |
parent | 851a4c48fd468b15ef988d5d2c79a44246dd478d (diff) | |
download | postgresql-f68f11928d5c791873073c882775dae10283ff49.tar.gz postgresql-f68f11928d5c791873073c882775dae10283ff49.zip |
Tighten selection of equality and ordering operators for grouping
operations: make sure we use operators that are compatible, as determined
by a mergejoin link in pg_operator. Also, add code to planner to ensure
we don't try to use hashed grouping when the grouping operators aren't
marked hashable.
Diffstat (limited to 'src/backend/parser/parse_oper.c')
-rw-r--r-- | src/backend/parser/parse_oper.c | 138 |
1 files changed, 105 insertions, 33 deletions
diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c index 776acc78bfa..eeb8f6aa8bb 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.60 2002/09/18 21:35:22 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.61 2002/11/29 21:39:11 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -130,22 +130,116 @@ LookupOperNameTypeNames(List *opername, TypeName *oprleft, return operoid; } +/* + * equality_oper - identify a suitable equality operator for a datatype + * + * On failure, return NULL if noError, else report a standard error + */ +Operator +equality_oper(Oid argtype, bool noError) +{ + Operator optup; -/* Select an ordering operator for the given datatype */ -Oid -any_ordering_op(Oid argtype) + /* + * Look for an "=" operator for the datatype. We require it to be + * an exact or binary-compatible match, since most callers are not + * prepared to cope with adding any run-time type coercion steps. + */ + optup = compatible_oper(makeList1(makeString("=")), + argtype, argtype, true); + if (optup != NULL) + { + /* + * Only believe that it's equality if it's mergejoinable, + * hashjoinable, or uses eqsel() as oprrest. + */ + Form_pg_operator pgopform = (Form_pg_operator) GETSTRUCT(optup); + + if (OidIsValid(pgopform->oprlsortop) || + pgopform->oprcanhash || + pgopform->oprrest == F_EQSEL) + return optup; + + ReleaseSysCache(optup); + } + if (!noError) + elog(ERROR, "Unable to identify an equality operator for type %s", + format_type_be(argtype)); + return NULL; +} + +/* + * ordering_oper - identify a suitable sorting operator ("<") for a datatype + * + * On failure, return NULL if noError, else report a standard error + */ +Operator +ordering_oper(Oid argtype, bool noError) { - Oid order_opid; + Operator optup; - order_opid = compatible_oper_opid(makeList1(makeString("<")), - argtype, argtype, true); - if (!OidIsValid(order_opid)) - elog(ERROR, "Unable to identify an ordering operator '%s' for type '%s'" + /* + * Find the type's equality operator, and use its lsortop (it *must* + * be mergejoinable). We use this definition because for sorting and + * grouping purposes, it's important that the equality and ordering + * operators are consistent. + */ + optup = equality_oper(argtype, noError); + if (optup != NULL) + { + Oid lsortop = ((Form_pg_operator) GETSTRUCT(optup))->oprlsortop; + + ReleaseSysCache(optup); + + if (OidIsValid(lsortop)) + { + optup = SearchSysCache(OPEROID, + ObjectIdGetDatum(lsortop), + 0, 0, 0); + if (optup != NULL) + return optup; + } + } + if (!noError) + elog(ERROR, "Unable to identify an ordering operator for type %s" "\n\tUse an explicit ordering operator or modify the query", - "<", format_type_be(argtype)); - return order_opid; + format_type_be(argtype)); + return NULL; +} + +/* + * equality_oper_funcid - convenience routine for oprfuncid(equality_oper()) + */ +Oid +equality_oper_funcid(Oid argtype) +{ + Operator optup; + Oid result; + + optup = equality_oper(argtype, false); + result = oprfuncid(optup); + ReleaseSysCache(optup); + return result; +} + +/* + * ordering_oper_opid - convenience routine for oprid(ordering_oper()) + * + * This was formerly called any_ordering_op() + */ +Oid +ordering_oper_opid(Oid argtype) +{ + Operator optup; + Oid result; + + optup = ordering_oper(argtype, false); + result = oprid(optup); + ReleaseSysCache(optup); + return result; } + /* given operator tuple, return the operator OID */ Oid oprid(Operator op) @@ -731,28 +825,6 @@ compatible_oper_opid(List *op, Oid arg1, Oid arg2, bool noError) return InvalidOid; } -/* compatible_oper_funcid() -- get OID of a binary operator's function - * - * This is a convenience routine that extracts only the function OID - * from the result of compatible_oper(). InvalidOid is returned if the - * lookup fails and noError is true. - */ -Oid -compatible_oper_funcid(List *op, Oid arg1, Oid arg2, bool noError) -{ - Operator optup; - Oid result; - - optup = compatible_oper(op, arg1, arg2, noError); - if (optup != NULL) - { - result = oprfuncid(optup); - ReleaseSysCache(optup); - return result; - } - return InvalidOid; -} - /* right_oper() -- search for a unary right operator (operator on right) * Given operator name and type of arg, return oper struct. |