summaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_clause.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser/parse_clause.c')
-rw-r--r--src/backend/parser/parse_clause.c41
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;