diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2003-06-15 16:42:08 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2003-06-15 16:42:08 +0000 |
commit | 996fdb9af1e298ae1ce3729429d2416e41344086 (patch) | |
tree | 32cf3e674e9eb5ab60d925f1408eea7b7c7bae6c /src/backend/parser/parse_clause.c | |
parent | da78e3e2eba4e1f54769eecebaf560f14e2711ea (diff) |
Cause GROUP BY clause to adopt ordering operators from ORDER BY when
both clauses specify the same targets, rather than always using the
default ordering operator. This allows 'GROUP BY foo ORDER BY foo DESC'
to be done with only one sort step.
Diffstat (limited to 'src/backend/parser/parse_clause.c')
-rw-r--r-- | src/backend/parser/parse_clause.c | 41 |
1 files changed, 31 insertions, 10 deletions
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c index a29eb007fb7..2e2beabddcb 100644 --- a/src/backend/parser/parse_clause.c +++ b/src/backend/parser/parse_clause.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.114 2003/06/06 15:04:02 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.115 2003/06/15 16:42:07 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1124,7 +1124,8 @@ findTargetlistEntry(ParseState *pstate, Node *node, List *tlist, int clause) * transform a GROUP BY clause */ List * -transformGroupClause(ParseState *pstate, List *grouplist, List *targetlist) +transformGroupClause(ParseState *pstate, List *grouplist, + List *targetlist, List *sortClause) { List *glist = NIL, *gl; @@ -1132,21 +1133,41 @@ transformGroupClause(ParseState *pstate, List *grouplist, List *targetlist) foreach(gl, grouplist) { TargetEntry *tle; + Oid ordering_op; + GroupClause *grpcl; tle = findTargetlistEntry(pstate, lfirst(gl), targetlist, GROUP_CLAUSE); /* avoid making duplicate grouplist entries */ - if (!targetIsInSortList(tle, glist)) - { - GroupClause *grpcl = makeNode(GroupClause); - - grpcl->tleSortGroupRef = assignSortGroupRef(tle, targetlist); - - grpcl->sortop = ordering_oper_opid(tle->resdom->restype); + if (targetIsInSortList(tle, glist)) + continue; - glist = lappend(glist, grpcl); + /* + * If the GROUP BY clause matches the ORDER BY clause, we want to + * adopt the ordering operators from the latter rather than using + * the default ops. This allows "GROUP BY foo ORDER BY foo DESC" to + * be done with only one sort step. Note we are assuming that any + * user-supplied ordering operator will bring equal values together, + * which is all that GROUP BY needs. + */ + if (sortClause && + ((SortClause *) lfirst(sortClause))->tleSortGroupRef == + tle->resdom->ressortgroupref) + { + ordering_op = ((SortClause *) lfirst(sortClause))->sortop; + sortClause = lnext(sortClause); } + else + { + ordering_op = ordering_oper_opid(tle->resdom->restype); + sortClause = NIL; /* disregard ORDER BY once match fails */ + } + + grpcl = makeNode(GroupClause); + grpcl->tleSortGroupRef = assignSortGroupRef(tle, targetlist); + grpcl->sortop = ordering_op; + glist = lappend(glist, grpcl); } return glist; |