Commit a1fbd470 authored by Vadim B. Mikheev's avatar Vadim B. Mikheev

Fix GroupBy: enable functions over aggregates and GroupBy-ed fields

in target list.
parent f4279c46
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -359,8 +359,9 @@ make_groupPlan(List **tlist,
List *sort_tlist; List *sort_tlist;
List *sl, *gl; List *sl, *gl;
List *glc = listCopy (groupClause); List *glc = listCopy (groupClause);
List *aggvals = NIL; /* list of vars of aggregates */ List *otles = NIL; /* list of removed non-GroupBy entries */
int aggvcnt; List *otlvars = NIL; /* list of var in them */
int otlvcnt;
Sort *sortplan; Sort *sortplan;
Group *grpplan; Group *grpplan;
int numCols; int numCols;
...@@ -375,7 +376,8 @@ make_groupPlan(List **tlist, ...@@ -375,7 +376,8 @@ make_groupPlan(List **tlist,
/* /*
* Make template TL for subplan, Sort & Group: * 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 * 2. Make grpColIdx
* *
* Note: we assume that TLEs in *tlist are ordered in accordance * Note: we assume that TLEs in *tlist are ordered in accordance
...@@ -390,7 +392,7 @@ make_groupPlan(List **tlist, ...@@ -390,7 +392,7 @@ make_groupPlan(List **tlist,
{ {
GroupClause *grpcl = (GroupClause*)lfirst(gl); GroupClause *grpcl = (GroupClause*)lfirst(gl);
if ( grpcl->resdom->resno == te->resdom->resno ) if ( grpcl->entry->resdom->resno == te->resdom->resno )
{ {
resdom = te->resdom; resdom = te->resdom;
...@@ -403,15 +405,20 @@ make_groupPlan(List **tlist, ...@@ -403,15 +405,20 @@ make_groupPlan(List **tlist,
break; break;
} }
} }
if ( resdom == NULL ) /* Not GroupBy-ed entry: remove */ /*
{ /* aggregate(s) from Group/Sort TL */ * Non-GroupBy entry: remove it from Group/Sort TL if there are
if ( IsA (te->expr, Aggreg) ) * aggregates in query - it will be evaluated by Aggregate plan
{ /* save Aggregate' Vars */ */
aggvals = nconc (aggvals, pull_var_clause (te->expr)); if ( resdom == NULL )
sort_tlist = lremove (lfirst (sl), sort_tlist); {
if ( tuplePerGroup )
{
otlvars = nconc (otlvars, pull_var_clause (te->expr));
otles = lcons (te, otles);
sort_tlist = lremove (te, sort_tlist);
} }
else else
resdom->resno = last_resno++; /* re-set */ te->resdom->resno = last_resno++;
} }
} }
...@@ -421,12 +428,12 @@ make_groupPlan(List **tlist, ...@@ -421,12 +428,12 @@ make_groupPlan(List **tlist,
} }
/* /*
* Aggregates were removed from TL - we are to add Vars for them * If non-GroupBy entries were removed from TL - we are to add Vars for
* to the end of TL if there are no such Vars in TL already. * them to the end of TL if there are no such Vars in TL already.
*/ */
aggvcnt = length (aggvals); otlvcnt = length (otlvars);
foreach (gl, aggvals) foreach (gl, otlvars)
{ {
Var *v = (Var*)lfirst (gl); Var *v = (Var*)lfirst (gl);
...@@ -437,9 +444,9 @@ make_groupPlan(List **tlist, ...@@ -437,9 +444,9 @@ make_groupPlan(List **tlist,
last_resno++; last_resno++;
} }
else /* already in TL */ 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 */ /* Make TL for subplan: substitute Vars from subplan TL into new TL */
sl = flatten_tlist_vars (sort_tlist, subplan->targetlist); sl = flatten_tlist_vars (sort_tlist, subplan->targetlist);
...@@ -489,16 +496,27 @@ make_groupPlan(List **tlist, ...@@ -489,16 +496,27 @@ make_groupPlan(List **tlist,
grpColIdx, sortplan); grpColIdx, sortplan);
/* /*
* Make TL for parent: "restore" Aggregates and * Make TL for parent: "restore" non-GroupBy entries (if they
* resno-s of others accordantly. * were removed) and set resno-s of others accordantly.
*/ */
sl = sort_tlist; sl = sort_tlist;
sort_tlist = NIL; /* to be new parent TL */ sort_tlist = NIL; /* to be new parent TL */
foreach (gl, *tlist) foreach (gl, *tlist)
{ {
List *temp = NIL;
TargetEntry *te = (TargetEntry *) lfirst (gl); TargetEntry *te = (TargetEntry *) lfirst (gl);
if ( !IsA (te->expr, Aggreg) ) /* It's "our" TLE - we're to return */ 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 */ { /* it from Sort/Group plans */
TargetEntry *my = (TargetEntry *) lfirst (sl); /* get it */ TargetEntry *my = (TargetEntry *) lfirst (sl); /* get it */
...@@ -508,15 +526,16 @@ make_groupPlan(List **tlist, ...@@ -508,15 +526,16 @@ make_groupPlan(List **tlist,
sort_tlist = lappend (sort_tlist, my); sort_tlist = lappend (sort_tlist, my);
continue; continue;
} }
/* TLE of an aggregate */ /* else - it's TLE of an non-GroupBy entry */
sort_tlist = lappend (sort_tlist, copyObject(te)); 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 * They shouldn't appear in parent TL, all others shouldn't
* disappear. * disappear.
*/ */
Assert ( aggvcnt == length (sl) ); Assert ( otlvcnt == length (sl) );
Assert ( length (otles) == 0 );
*tlist = sort_tlist; *tlist = sort_tlist;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -1552,7 +1552,8 @@ transformGroupClause(ParseState *pstate, List *grouplist, List *targetlist)
if (restarget == NULL) if (restarget == NULL)
elog(WARN,"The field being grouped by must appear in the target list"); 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("<", grpcl->grpOpoid = oprid(oper("<",
resdom->restype, resdom->restype,
resdom->restype,false)); resdom->restype,false));
...@@ -2360,66 +2361,68 @@ contain_agg_clause(Node *clause) ...@@ -2360,66 +2361,68 @@ contain_agg_clause(Node *clause)
} }
/* /*
* tleIsAggOrGroupCol - * exprIsAggOrGroupCol -
* returns true if the TargetEntry is Agg or GroupCol. * returns true if the expression does not contain non-group columns.
*/ */
static bool static bool
tleIsAggOrGroupCol(TargetEntry *tle, List *groupClause) exprIsAggOrGroupCol(Node *expr, List *groupClause)
{ {
Node *expr = tle->expr;
List *gl; List *gl;
if ( expr == NULL || IsA (expr, Const) ) if ( expr == NULL || IsA (expr, Const) || IsA (expr, Aggreg) )
return TRUE; return TRUE;
foreach (gl, groupClause) foreach (gl, groupClause)
{ {
GroupClause *grpcl = lfirst(gl); GroupClause *grpcl = lfirst(gl);
if ( tle->resdom->resno == grpcl->resdom->resno ) if ( equal (expr, grpcl->entry->expr) )
{
if ( IsA (expr, Aggreg) )
elog (WARN, "parser: aggregates not allowed in GROUP BY clause");
return TRUE; return TRUE;
} }
}
if ( IsA (expr, Aggreg) ) if ( IsA (expr, Expr) )
{
List *temp;
foreach (temp, ((Expr*)expr)->args)
if (!exprIsAggOrGroupCol(lfirst(temp),groupClause))
return FALSE;
return TRUE; return TRUE;
}
return FALSE; return FALSE;
} }
#if 0 /* Now GroupBy contains resdom to enable Group By func_results */
/* /*
* exprIsAggOrGroupCol - * tleIsAggOrGroupCol -
* returns true if the expression does not contain non-group columns. * returns true if the TargetEntry is Agg or GroupCol.
*/ */
static bool static bool
exprIsAggOrGroupCol(Node *expr, List *groupClause) tleIsAggOrGroupCol(TargetEntry *tle, List *groupClause)
{ {
if (expr==NULL) Node *expr = tle->expr;
return TRUE;
else if (IsA(expr,Const))
return TRUE;
else if (IsA(expr,Var)) {
List *gl; List *gl;
Var *var = (Var*)expr;
/* if ( expr == NULL || IsA (expr, Const) )
* only group columns are legal return TRUE;
*/
foreach (gl, groupClause) { foreach (gl, groupClause)
{
GroupClause *grpcl = lfirst(gl); GroupClause *grpcl = lfirst(gl);
if ((grpcl->grpAttr->varno == var->varno) &&
(grpcl->grpAttr->varattno == var->varattno)) if ( tle->resdom->resno == grpcl->entry->resdom->resno )
{
if ( contain_agg_clause ((Node*) expr) )
elog (WARN, "parser: aggregates not allowed in GROUP BY clause");
return TRUE; return TRUE;
} }
return FALSE; }
} else if (IsA(expr,Aggreg))
/* aggregates can take group column or non-group column as argument, if ( IsA (expr, Aggreg) )
no further check necessary. */
return TRUE; return TRUE;
else if (IsA(expr,Expr)) {
if ( IsA (expr, Expr) )
{
List *temp; List *temp;
foreach (temp, ((Expr*)expr)->args) foreach (temp, ((Expr*)expr)->args)
...@@ -2430,7 +2433,6 @@ exprIsAggOrGroupCol(Node *expr, List *groupClause) ...@@ -2430,7 +2433,6 @@ exprIsAggOrGroupCol(Node *expr, List *groupClause)
return FALSE; return FALSE;
} }
#endif
/* /*
* parseCheckAggregates - * parseCheckAggregates -
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * 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 { ...@@ -774,7 +774,7 @@ typedef struct SortClause {
*/ */
typedef struct GroupClause { typedef struct GroupClause {
NodeTag type; NodeTag type;
Resdom *resdom; /* attributes to group on */ TargetEntry *entry; /* attributes to group on */
Oid grpOpoid; /* the sort operator to use */ Oid grpOpoid; /* the sort operator to use */
} GroupClause; } GroupClause;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment