diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2008-08-02 21:32:01 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2008-08-02 21:32:01 +0000 |
commit | 951130475221562b44b0da575fac8470adb5b555 (patch) | |
tree | 5dc2ac24a5381a2ff1c2f25e1d14430b66558c02 /src/backend/parser/parse_oper.c | |
parent | 49f001d81ed635747c4439f38ae1fc6090887452 (diff) | |
download | postgresql-951130475221562b44b0da575fac8470adb5b555.tar.gz postgresql-951130475221562b44b0da575fac8470adb5b555.zip |
Rearrange the querytree representation of ORDER BY/GROUP BY/DISTINCT items
as per my recent proposal:
1. Fold SortClause and GroupClause into a single node type SortGroupClause.
We were already relying on them to be struct-equivalent, so using two node
tags wasn't accomplishing much except to get in the way of comparing items
with equal().
2. Add an "eqop" field to SortGroupClause to carry the associated equality
operator. This is cheap for the parser to get at the same time it's looking
up the sort operator, and storing it eliminates the need for repeated
not-so-cheap lookups during planning. In future this will also let us
represent GROUP/DISTINCT operations on datatypes that have hash opclasses
but no btree opclasses (ie, they have equality but no natural sort order).
The previous representation simply didn't work for that, since its only
indicator of comparison semantics was a sort operator.
3. Add a hasDistinctOn boolean to struct Query to explicitly record whether
the distinctClause came from DISTINCT or DISTINCT ON. This allows removing
some complicated and not 100% bulletproof code that attempted to figure
that out from the distinctClause alone.
This patch doesn't in itself create any new capability, but it's necessary
infrastructure for future attempts to use hash-based grouping for DISTINCT
and UNION/INTERSECT/EXCEPT.
Diffstat (limited to 'src/backend/parser/parse_oper.c')
-rw-r--r-- | src/backend/parser/parse_oper.c | 264 |
1 files changed, 59 insertions, 205 deletions
diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c index 54fb63f959d..055574ff982 100644 --- a/src/backend/parser/parse_oper.c +++ b/src/backend/parser/parse_oper.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_oper.c,v 1.102 2008/04/22 01:34:34 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_oper.c,v 1.103 2008/08/02 21:32:00 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -160,239 +160,93 @@ LookupOperNameTypeNames(ParseState *pstate, List *opername, } /* - * equality_oper - identify a suitable equality operator for a datatype + * get_sort_group_operators - get default sorting/grouping operators for type * - * On failure, return NULL if noError, else report a standard error - */ -Operator -equality_oper(Oid argtype, bool noError) -{ - TypeCacheEntry *typentry; - Oid oproid; - Operator optup; - - /* - * 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. - */ - typentry = lookup_type_cache(argtype, TYPECACHE_EQ_OPR); - oproid = typentry->eq_opr; - - /* - * If the datatype is an array, then we can use array_eq ... but only if - * there is a suitable equality operator for the element type. (This check - * is not in the raw typcache.c code ... should it be?) - */ - if (oproid == ARRAY_EQ_OP) - { - Oid elem_type = get_element_type(argtype); - - if (OidIsValid(elem_type)) - { - optup = equality_oper(elem_type, true); - if (optup != NULL) - ReleaseSysCache(optup); - else - oproid = InvalidOid; /* element type has no "=" */ - } - else - oproid = InvalidOid; /* bogus array type? */ - } - - if (OidIsValid(oproid)) - { - optup = SearchSysCache(OPEROID, - ObjectIdGetDatum(oproid), - 0, 0, 0); - if (optup == NULL) /* should not fail */ - elog(ERROR, "cache lookup failed for operator %u", oproid); - return optup; - } - - if (!noError) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_FUNCTION), - errmsg("could not identify an equality operator for type %s", - format_type_be(argtype)))); - return NULL; -} - -/* - * ordering_oper - identify a suitable sorting operator ("<") for a datatype + * We fetch the "<", "=", and ">" operators all at once to reduce lookup + * overhead (knowing that most callers will be interested in at least two). + * However, a given datatype might have only an "=" operator, if it is + * hashable but not sortable. (Other combinations of present and missing + * operators shouldn't happen, unless the system catalogs are messed up.) + * + * If an operator is missing and the corresponding needXX flag is true, + * throw a standard error message, else return InvalidOid. + * + * Callers can pass NULL pointers for any results they don't care to get. * - * On failure, return NULL if noError, else report a standard error + * Note: the results are guaranteed to be exact or binary-compatible matches, + * since most callers are not prepared to cope with adding any run-time type + * coercion steps. */ -Operator -ordering_oper(Oid argtype, bool noError) +void +get_sort_group_operators(Oid argtype, + bool needLT, bool needEQ, bool needGT, + Oid *ltOpr, Oid *eqOpr, Oid *gtOpr) { TypeCacheEntry *typentry; - Oid oproid; - Operator optup; + Oid lt_opr; + Oid eq_opr; + Oid gt_opr; /* - * Look for a "<" 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. + * Look up the operators using the type cache. * - * Note: the search algorithm used by typcache.c ensures that if a "<" - * operator is returned, it will be consistent with the "=" operator - * returned by equality_oper. This is critical for sorting and grouping - * purposes. + * Note: the search algorithm used by typcache.c ensures that the results + * are consistent, ie all from the same opclass. */ - typentry = lookup_type_cache(argtype, TYPECACHE_LT_OPR); - oproid = typentry->lt_opr; + typentry = lookup_type_cache(argtype, + TYPECACHE_LT_OPR | TYPECACHE_EQ_OPR | TYPECACHE_GT_OPR); + lt_opr = typentry->lt_opr; + eq_opr = typentry->eq_opr; + gt_opr = typentry->gt_opr; /* - * If the datatype is an array, then we can use array_lt ... but only if - * there is a suitable less-than operator for the element type. (This - * check is not in the raw typcache.c code ... should it be?) + * If the datatype is an array, then we can use array_lt and friends ... + * but only if there are suitable operators for the element type. (This + * check is not in the raw typcache.c code ... should it be?) Testing + * all three operator IDs here should be redundant. */ - if (oproid == ARRAY_LT_OP) + if (lt_opr == ARRAY_LT_OP || + eq_opr == ARRAY_EQ_OP || + gt_opr == ARRAY_GT_OP) { Oid elem_type = get_element_type(argtype); if (OidIsValid(elem_type)) { - optup = ordering_oper(elem_type, true); - if (optup != NULL) - ReleaseSysCache(optup); - else - oproid = InvalidOid; /* element type has no "<" */ + typentry = lookup_type_cache(elem_type, + TYPECACHE_LT_OPR | TYPECACHE_EQ_OPR | TYPECACHE_GT_OPR); + if (!OidIsValid(typentry->lt_opr)) + lt_opr = InvalidOid; /* element type has no "<" */ + if (!OidIsValid(typentry->eq_opr)) + eq_opr = InvalidOid; /* element type has no "=" */ + if (!OidIsValid(typentry->gt_opr)) + gt_opr = InvalidOid; /* element type has no ">" */ } else - oproid = InvalidOid; /* bogus array type? */ - } - - if (OidIsValid(oproid)) - { - optup = SearchSysCache(OPEROID, - ObjectIdGetDatum(oproid), - 0, 0, 0); - if (optup == NULL) /* should not fail */ - elog(ERROR, "cache lookup failed for operator %u", oproid); - return optup; + lt_opr = eq_opr = gt_opr = InvalidOid; /* bogus array type? */ } - if (!noError) + /* Report errors if needed */ + if ((needLT && !OidIsValid(lt_opr)) || + (needGT && !OidIsValid(gt_opr))) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("could not identify an ordering operator for type %s", format_type_be(argtype)), errhint("Use an explicit ordering operator or modify the query."))); - return NULL; -} - -/* - * reverse_ordering_oper - identify DESC sort operator (">") for a datatype - * - * On failure, return NULL if noError, else report a standard error - */ -Operator -reverse_ordering_oper(Oid argtype, bool noError) -{ - TypeCacheEntry *typentry; - Oid oproid; - Operator optup; - - /* - * Look for a ">" 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. - * - * Note: the search algorithm used by typcache.c ensures that if a ">" - * operator is returned, it will be consistent with the "=" operator - * returned by equality_oper. This is critical for sorting and grouping - * purposes. - */ - typentry = lookup_type_cache(argtype, TYPECACHE_GT_OPR); - oproid = typentry->gt_opr; - - /* - * If the datatype is an array, then we can use array_gt ... but only if - * there is a suitable greater-than operator for the element type. (This - * check is not in the raw typcache.c code ... should it be?) - */ - if (oproid == ARRAY_GT_OP) - { - Oid elem_type = get_element_type(argtype); - - if (OidIsValid(elem_type)) - { - optup = reverse_ordering_oper(elem_type, true); - if (optup != NULL) - ReleaseSysCache(optup); - else - oproid = InvalidOid; /* element type has no ">" */ - } - else - oproid = InvalidOid; /* bogus array type? */ - } - - if (OidIsValid(oproid)) - { - optup = SearchSysCache(OPEROID, - ObjectIdGetDatum(oproid), - 0, 0, 0); - if (optup == NULL) /* should not fail */ - elog(ERROR, "cache lookup failed for operator %u", oproid); - return optup; - } - - if (!noError) + if (needEQ && !OidIsValid(eq_opr)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), - errmsg("could not identify an ordering operator for type %s", - format_type_be(argtype)), - errhint("Use an explicit ordering operator or modify the query."))); - 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; -} - -/* - * reverse_ordering_oper_opid - convenience routine for oprid(reverse_ordering_oper()) - */ -Oid -reverse_ordering_oper_opid(Oid argtype) -{ - Operator optup; - Oid result; + errmsg("could not identify an equality operator for type %s", + format_type_be(argtype)))); - optup = reverse_ordering_oper(argtype, false); - result = oprid(optup); - ReleaseSysCache(optup); - return result; + /* Return results as needed */ + if (ltOpr) + *ltOpr = lt_opr; + if (eqOpr) + *eqOpr = eq_opr; + if (gtOpr) + *gtOpr = gt_opr; } |