mirror of
https://github.com/postgres/postgres.git
synced 2025-11-19 13:42:17 +03:00
Revise union_planner and associated routines to clean up breakage
from EXCEPT/HAVING patch. Cases involving nontrivial GROUP BY expressions now work again. Also, the code is at least somewhat better documented...
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.34 1999/02/21 03:48:49 scrappy Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.35 1999/05/03 00:38:43 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -44,9 +44,6 @@
|
||||
static Plan *subplanner(Query *root, List *flat_tlist, List *qual);
|
||||
static Result *make_result(List *tlist, Node *resconstantqual, Plan *subplan);
|
||||
|
||||
extern Plan *make_groupPlan(List **tlist, bool tuplePerGroup,
|
||||
List *groupClause, Plan *subplan);
|
||||
|
||||
/*
|
||||
* query_planner
|
||||
* Routine to create a query plan. It does so by first creating a
|
||||
@@ -177,18 +174,14 @@ query_planner(Query *root,
|
||||
*/
|
||||
if (constant_qual)
|
||||
{
|
||||
subplan = (Plan *) make_result((!root->hasAggs &&
|
||||
!root->groupClause &&
|
||||
!root->havingQual)
|
||||
? tlist : subplan->targetlist,
|
||||
subplan = (Plan *) make_result(tlist,
|
||||
(Node *) constant_qual,
|
||||
subplan);
|
||||
|
||||
/*
|
||||
* Change all varno's of the Result's node target list.
|
||||
* Fix all varno's of the Result's node target list.
|
||||
*/
|
||||
if (!root->hasAggs && !root->groupClause && !root->havingQual)
|
||||
set_tlist_references(subplan);
|
||||
set_tlist_references(subplan);
|
||||
|
||||
return subplan;
|
||||
}
|
||||
@@ -201,16 +194,15 @@ query_planner(Query *root,
|
||||
* responsibility to optimally push these expressions down the plan
|
||||
* tree. -- Wei
|
||||
*
|
||||
* But now nothing to do if there are GroupBy and/or Aggregates: 1.
|
||||
* make_groupPlan fixes tlist; 2. flatten_tlist_vars does nothing with
|
||||
* aggregates fixing only other entries (i.e. - GroupBy-ed and so
|
||||
* fixed by make_groupPlan). - vadim 04/05/97
|
||||
* Note: formerly there was a test here to skip the flatten call if we
|
||||
* expected union_planner to insert a Group or Agg node above our result.
|
||||
* However, now union_planner tells us exactly what it wants returned,
|
||||
* and we just do it. Much cleaner.
|
||||
*/
|
||||
else
|
||||
{
|
||||
if (!root->hasAggs && !root->groupClause && !root->havingQual)
|
||||
subplan->targetlist = flatten_tlist_vars(tlist,
|
||||
subplan->targetlist);
|
||||
subplan->targetlist = flatten_tlist_vars(tlist,
|
||||
subplan->targetlist);
|
||||
return subplan;
|
||||
}
|
||||
|
||||
@@ -321,201 +313,3 @@ make_result(List *tlist,
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
Plan *
|
||||
make_groupPlan(List **tlist,
|
||||
bool tuplePerGroup,
|
||||
List *groupClause,
|
||||
Plan *subplan)
|
||||
{
|
||||
List *sort_tlist;
|
||||
List *sl,
|
||||
*gl;
|
||||
List *glc = listCopy(groupClause);
|
||||
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;
|
||||
AttrNumber *grpColIdx;
|
||||
int last_resno = 1;
|
||||
|
||||
numCols = length(groupClause);
|
||||
grpColIdx = (AttrNumber *) palloc(sizeof(AttrNumber) * numCols);
|
||||
|
||||
sort_tlist = new_unsorted_tlist(*tlist); /* it's copy */
|
||||
|
||||
/*
|
||||
* Make template TL for subplan, Sort & Group: 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 with
|
||||
* their resdom->resno.
|
||||
*/
|
||||
foreach(sl, sort_tlist)
|
||||
{
|
||||
Resdom *resdom = NULL;
|
||||
TargetEntry *te = (TargetEntry *) lfirst(sl);
|
||||
int keyno = 0;
|
||||
|
||||
foreach(gl, groupClause)
|
||||
{
|
||||
GroupClause *grpcl = (GroupClause *) lfirst(gl);
|
||||
|
||||
keyno++;
|
||||
if (grpcl->entry->resdom->resno == te->resdom->resno)
|
||||
{
|
||||
|
||||
resdom = te->resdom;
|
||||
resdom->reskey = keyno;
|
||||
resdom->reskeyop = get_opcode(grpcl->grpOpoid);
|
||||
resdom->resno = last_resno; /* re-set */
|
||||
grpColIdx[keyno - 1] = last_resno++;
|
||||
glc = lremove(lfirst(gl), glc); /* TLE found for it */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
te->resdom->resno = last_resno++;
|
||||
}
|
||||
}
|
||||
|
||||
if (length(glc) != 0)
|
||||
elog(ERROR, "group attribute disappeared from target list");
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
otlvcnt = length(otlvars);
|
||||
foreach(gl, otlvars)
|
||||
{
|
||||
Var *v = (Var *) lfirst(gl);
|
||||
|
||||
if (tlist_member(v, sort_tlist) == NULL)
|
||||
{
|
||||
sort_tlist = lappend(sort_tlist,
|
||||
create_tl_element(v, last_resno));
|
||||
last_resno++;
|
||||
}
|
||||
else
|
||||
/* already in TL */
|
||||
otlvcnt--;
|
||||
}
|
||||
/* 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);
|
||||
|
||||
subplan->targetlist = new_unsorted_tlist(sl); /* there */
|
||||
|
||||
/*
|
||||
* Make Sort/Group TL : 1. make Var nodes (with varno = 1 and varnoold
|
||||
* = -1) for all functions, 'couse they will be evaluated by subplan;
|
||||
* 2. for real Vars: set varno = 1 and varattno to its resno in
|
||||
* subplan
|
||||
*/
|
||||
foreach(sl, sort_tlist)
|
||||
{
|
||||
TargetEntry *te = (TargetEntry *) lfirst(sl);
|
||||
Resdom *resdom = te->resdom;
|
||||
Node *expr = te->expr;
|
||||
|
||||
if (IsA(expr, Var))
|
||||
{
|
||||
#ifdef NOT_USED /* subplanVar->resdom->resno expected to
|
||||
* be = te->resdom->resno */
|
||||
TargetEntry *subplanVar;
|
||||
|
||||
subplanVar = match_varid((Var *) expr, subplan->targetlist);
|
||||
((Var *) expr)->varattno = subplanVar->resdom->resno;
|
||||
#endif
|
||||
((Var *) expr)->varattno = te->resdom->resno;
|
||||
((Var *) expr)->varno = 1;
|
||||
}
|
||||
else
|
||||
te->expr = (Node *) makeVar(1, resdom->resno,
|
||||
resdom->restype,
|
||||
resdom->restypmod,
|
||||
0, -1, resdom->resno);
|
||||
}
|
||||
|
||||
sortplan = make_sort(sort_tlist,
|
||||
_NONAME_RELATION_ID_,
|
||||
subplan,
|
||||
numCols);
|
||||
sortplan->plan.cost = subplan->cost; /* XXX assume no cost */
|
||||
|
||||
/*
|
||||
* make the Group node
|
||||
*/
|
||||
sort_tlist = copyObject(sort_tlist);
|
||||
grpplan = make_group(sort_tlist, tuplePerGroup, numCols,
|
||||
grpColIdx, sortplan);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
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" */
|
||||
my = copyObject(my);
|
||||
my->resdom->resno = te->resdom->resno; /* order of parent TL */
|
||||
sort_tlist = lappend(sort_tlist, my);
|
||||
continue;
|
||||
}
|
||||
/* else - it's TLE of an non-GroupBy entry */
|
||||
sort_tlist = lappend(sort_tlist, copyObject(te));
|
||||
}
|
||||
|
||||
/*
|
||||
* 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(otlvcnt == length(sl));
|
||||
Assert(length(otles) == 0);
|
||||
|
||||
*tlist = sort_tlist;
|
||||
|
||||
return (Plan *) grpplan;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user