From a1fbd470a9ae934bf2316740c06b0cf88607e6e8 Mon Sep 17 00:00:00 2001 From: "Vadim B. Mikheev" Date: Tue, 29 Apr 1997 04:32:50 +0000 Subject: [PATCH] Fix GroupBy: enable functions over aggregates and GroupBy-ed fields in target list. --- src/backend/optimizer/plan/planmain.c | 71 +++++++++++++++++++------------ src/backend/parser/analyze.c | 78 ++++++++++++++++++----------------- src/include/nodes/parsenodes.h | 4 +- 3 files changed, 87 insertions(+), 66 deletions(-) diff --git a/src/backend/optimizer/plan/planmain.c b/src/backend/optimizer/plan/planmain.c index f94552d372..7f70d76ac6 100644 --- a/src/backend/optimizer/plan/planmain.c +++ b/src/backend/optimizer/plan/planmain.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.3 1997/04/05 06:37:37 vadim Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.4 1997/04/29 04:32:50 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -359,8 +359,9 @@ make_groupPlan(List **tlist, List *sort_tlist; List *sl, *gl; List *glc = listCopy (groupClause); - List *aggvals = NIL; /* list of vars of aggregates */ - int aggvcnt; + List *otles = NIL; /* list of removed non-GroupBy entries */ + List *otlvars = NIL; /* list of var in them */ + int otlvcnt; Sort *sortplan; Group *grpplan; int numCols; @@ -375,7 +376,8 @@ make_groupPlan(List **tlist, /* * Make template TL for subplan, Sort & Group: - * 1. Take away Aggregates and re-set resno-s accordantly. + * 1. If there are aggregates (tuplePerGroup is true) then take + * away non-GroupBy entries and re-set resno-s accordantly. * 2. Make grpColIdx * * Note: we assume that TLEs in *tlist are ordered in accordance @@ -390,7 +392,7 @@ make_groupPlan(List **tlist, { GroupClause *grpcl = (GroupClause*)lfirst(gl); - if ( grpcl->resdom->resno == te->resdom->resno ) + if ( grpcl->entry->resdom->resno == te->resdom->resno ) { resdom = te->resdom; @@ -403,15 +405,20 @@ make_groupPlan(List **tlist, break; } } - if ( resdom == NULL ) /* Not GroupBy-ed entry: remove */ - { /* aggregate(s) from Group/Sort TL */ - if ( IsA (te->expr, Aggreg) ) - { /* save Aggregate' Vars */ - aggvals = nconc (aggvals, pull_var_clause (te->expr)); - sort_tlist = lremove (lfirst (sl), sort_tlist); + /* + * Non-GroupBy entry: remove it from Group/Sort TL if there are + * aggregates in query - it will be evaluated by Aggregate plan + */ + if ( resdom == NULL ) + { + if ( tuplePerGroup ) + { + otlvars = nconc (otlvars, pull_var_clause (te->expr)); + otles = lcons (te, otles); + sort_tlist = lremove (te, sort_tlist); } else - resdom->resno = last_resno++; /* re-set */ + te->resdom->resno = last_resno++; } } @@ -421,12 +428,12 @@ make_groupPlan(List **tlist, } /* - * Aggregates were removed from TL - we are to add Vars for them - * to the end of TL if there are no such Vars in TL already. + * If non-GroupBy entries were removed from TL - we are to add Vars for + * them to the end of TL if there are no such Vars in TL already. */ - aggvcnt = length (aggvals); - foreach (gl, aggvals) + otlvcnt = length (otlvars); + foreach (gl, otlvars) { Var *v = (Var*)lfirst (gl); @@ -437,9 +444,9 @@ make_groupPlan(List **tlist, last_resno++; } else /* already in TL */ - aggvcnt--; + otlvcnt--; } - /* Now aggvcnt is number of Vars added in TL for Aggregates */ + /* Now otlvcnt is number of Vars added in TL for non-GroupBy entries */ /* Make TL for subplan: substitute Vars from subplan TL into new TL */ sl = flatten_tlist_vars (sort_tlist, subplan->targetlist); @@ -489,17 +496,28 @@ make_groupPlan(List **tlist, grpColIdx, sortplan); /* - * Make TL for parent: "restore" Aggregates and - * resno-s of others accordantly. + * Make TL for parent: "restore" non-GroupBy entries (if they + * were removed) and set resno-s of others accordantly. */ sl = sort_tlist; sort_tlist = NIL; /* to be new parent TL */ foreach (gl, *tlist) { + List *temp = NIL; TargetEntry *te = (TargetEntry *) lfirst (gl); - - if ( !IsA (te->expr, Aggreg) ) /* It's "our" TLE - we're to return */ - { /* it from Sort/Group plans */ + + foreach (temp, otles) /* Is it removed non-GroupBy entry ? */ + { + TargetEntry *ote = (TargetEntry *) lfirst (temp); + + if ( ote->resdom->resno == te->resdom->resno ) + { + otles = lremove (ote, otles); + break; + } + } + if ( temp == NIL ) /* It's "our" TLE - we're to return */ + { /* it from Sort/Group plans */ TargetEntry *my = (TargetEntry *) lfirst (sl); /* get it */ sl = sl->next; /* prepare for the next "our" */ @@ -508,15 +526,16 @@ make_groupPlan(List **tlist, sort_tlist = lappend (sort_tlist, my); continue; } - /* TLE of an aggregate */ + /* else - it's TLE of an non-GroupBy entry */ sort_tlist = lappend (sort_tlist, copyObject(te)); } /* - * Pure aggregates Vars were at the end of Group' TL. + * Pure non-GroupBy entries Vars were at the end of Group' TL. * They shouldn't appear in parent TL, all others shouldn't * disappear. */ - Assert ( aggvcnt == length (sl) ); + Assert ( otlvcnt == length (sl) ); + Assert ( length (otles) == 0 ); *tlist = sort_tlist; diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index 8fc78d3aca..1bc64047d6 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.26 1997/04/27 19:16:44 thomas Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.27 1997/04/29 04:32:26 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -1552,7 +1552,8 @@ transformGroupClause(ParseState *pstate, List *grouplist, List *targetlist) if (restarget == NULL) elog(WARN,"The field being grouped by must appear in the target list"); - grpcl->resdom = resdom = restarget->resdom; + grpcl->entry = restarget; + resdom = restarget->resdom; grpcl->grpOpoid = oprid(oper("<", resdom->restype, resdom->restype,false)); @@ -2360,6 +2361,39 @@ contain_agg_clause(Node *clause) } /* + * exprIsAggOrGroupCol - + * returns true if the expression does not contain non-group columns. + */ +static bool +exprIsAggOrGroupCol(Node *expr, List *groupClause) +{ + List *gl; + + if ( expr == NULL || IsA (expr, Const) || IsA (expr, Aggreg) ) + return TRUE; + + foreach (gl, groupClause) + { + GroupClause *grpcl = lfirst(gl); + + if ( equal (expr, grpcl->entry->expr) ) + return TRUE; + } + + if ( IsA (expr, Expr) ) + { + List *temp; + + foreach (temp, ((Expr*)expr)->args) + if (!exprIsAggOrGroupCol(lfirst(temp),groupClause)) + return FALSE; + return TRUE; + } + + return FALSE; +} + +/* * tleIsAggOrGroupCol - * returns true if the TargetEntry is Agg or GroupCol. */ @@ -2376,9 +2410,9 @@ tleIsAggOrGroupCol(TargetEntry *tle, List *groupClause) { GroupClause *grpcl = lfirst(gl); - if ( tle->resdom->resno == grpcl->resdom->resno ) + if ( tle->resdom->resno == grpcl->entry->resdom->resno ) { - if ( IsA (expr, Aggreg) ) + if ( contain_agg_clause ((Node*) expr) ) elog (WARN, "parser: aggregates not allowed in GROUP BY clause"); return TRUE; } @@ -2387,39 +2421,8 @@ tleIsAggOrGroupCol(TargetEntry *tle, List *groupClause) if ( IsA (expr, Aggreg) ) return TRUE; - return FALSE; -} - -#if 0 /* Now GroupBy contains resdom to enable Group By func_results */ -/* - * exprIsAggOrGroupCol - - * returns true if the expression does not contain non-group columns. - */ -static bool -exprIsAggOrGroupCol(Node *expr, List *groupClause) -{ - if (expr==NULL) - return TRUE; - else if (IsA(expr,Const)) - return TRUE; - else if (IsA(expr,Var)) { - List *gl; - Var *var = (Var*)expr; - /* - * only group columns are legal - */ - foreach (gl, groupClause) { - GroupClause *grpcl = lfirst(gl); - if ((grpcl->grpAttr->varno == var->varno) && - (grpcl->grpAttr->varattno == var->varattno)) - return TRUE; - } - return FALSE; - } else if (IsA(expr,Aggreg)) - /* aggregates can take group column or non-group column as argument, - no further check necessary. */ - return TRUE; - else if (IsA(expr,Expr)) { + if ( IsA (expr, Expr) ) + { List *temp; foreach (temp, ((Expr*)expr)->args) @@ -2430,7 +2433,6 @@ exprIsAggOrGroupCol(Node *expr, List *groupClause) return FALSE; } -#endif /* * parseCheckAggregates - diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 7ae2cd6e98..d29e66bcf5 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -6,7 +6,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: parsenodes.h,v 1.14 1997/04/23 05:58:06 vadim Exp $ + * $Id: parsenodes.h,v 1.15 1997/04/29 04:28:59 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -774,7 +774,7 @@ typedef struct SortClause { */ typedef struct GroupClause { NodeTag type; - Resdom *resdom; /* attributes to group on */ + TargetEntry *entry; /* attributes to group on */ Oid grpOpoid; /* the sort operator to use */ } GroupClause; -- 2.11.0