Commit da5f1dd7 authored by Tom Lane's avatar Tom Lane

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...
parent 605d8494
......@@ -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;
}
This diff is collapsed.
This diff is collapsed.
......@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.17 1999/02/22 05:26:27 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.18 1999/05/03 00:38:44 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -68,54 +68,56 @@ pull_varnos(Node *me)
/*
* contain_var_clause
* Recursively find var nodes from a clause by pulling vars from the
* left and right operands of the clause.
* Recursively scan a clause to discover whether it contains any Var nodes.
*
* Returns true if any varnode found.
*/
bool
contain_var_clause(Node *clause)
{
List *temp;
if (clause == NULL)
return FALSE;
else if (IsA(clause, Var))
return TRUE;
else if (IsA(clause, Iter))
return contain_var_clause(((Iter *) clause)->iterexpr);
else if (single_node(clause))
return FALSE;
else if (or_clause(clause) || and_clause(clause) || is_funcclause(clause))
else if (IsA(clause, Iter))
return contain_var_clause(((Iter *) clause)->iterexpr);
else if (is_subplan(clause))
{
List *temp;
foreach(temp, ((Expr *) clause)->args)
{
if (contain_var_clause(lfirst(temp)))
return TRUE;
}
/* Also check left sides of Oper-s */
foreach(temp, ((SubPlan *) ((Expr *) clause)->oper)->sublink->oper)
{
if (contain_var_clause(lfirst(((Expr *) lfirst(temp))->args)))
return TRUE;
}
return FALSE;
}
else if (is_subplan(clause))
else if (IsA(clause, Expr))
{
List *temp;
/*
* Recursively scan the arguments of an expression.
* NOTE: this must come after is_subplan() case since
* subplan is a kind of Expr node.
*/
foreach(temp, ((Expr *) clause)->args)
{
if (contain_var_clause(lfirst(temp)))
return TRUE;
}
/* Ok - check left sides of Oper-s */
foreach(temp, ((SubPlan *) ((Expr *) clause)->oper)->sublink->oper)
{
if (contain_var_clause(lfirst(((Expr *) lfirst(temp))->args)))
return TRUE;
}
return FALSE;
}
else if (IsA(clause, Aggref))
return contain_var_clause(((Aggref *) clause)->target);
else if (IsA(clause, ArrayRef))
{
List *temp;
foreach(temp, ((ArrayRef *) clause)->refupperindexpr)
{
if (contain_var_clause(lfirst(temp)))
......@@ -132,19 +134,11 @@ contain_var_clause(Node *clause)
return TRUE;
return FALSE;
}
else if (not_clause(clause))
return contain_var_clause((Node *) get_notclausearg((Expr *) clause));
else if (is_opclause(clause))
return (contain_var_clause((Node *) get_leftop((Expr *) clause)) ||
contain_var_clause((Node *) get_rightop((Expr *) clause)));
else if (case_clause(clause))
{
List *args;
CaseWhen *when;
foreach(args, ((CaseExpr *) clause)->args)
foreach(temp, ((CaseExpr *) clause)->args)
{
when = lfirst(args);
CaseWhen *when = (CaseWhen *) lfirst(temp);
if (contain_var_clause(when->expr))
return TRUE;
if (contain_var_clause(when->result))
......@@ -152,6 +146,11 @@ contain_var_clause(Node *clause)
}
return (contain_var_clause(((CaseExpr *) clause)->defresult));
}
else
{
elog(ERROR, "contain_var_clause: Cannot handle node type %d",
nodeTag(clause));
}
return FALSE;
}
......@@ -161,45 +160,46 @@ contain_var_clause(Node *clause)
* Recursively pulls all var nodes from a clause by pulling vars from the
* left and right operands of the clause.
*
* Returns list of varnodes found.
* Returns list of varnodes found. Note the varnodes themselves are not
* copied, only referenced.
*/
List *
pull_var_clause(Node *clause)
{
List *retval = NIL;
List *temp;
if (clause == NULL)
return NIL;
else if (IsA(clause, Var))
retval = lcons(clause, NIL);
else if (IsA(clause, Iter))
retval = pull_var_clause(((Iter *) clause)->iterexpr);
else if (single_node(clause))
retval = NIL;
else if (or_clause(clause) || and_clause(clause) || is_funcclause(clause))
{
List *temp;
foreach(temp, ((Expr *) clause)->args)
retval = nconc(retval, pull_var_clause(lfirst(temp)));
}
else if (IsA(clause, Iter))
retval = pull_var_clause(((Iter *) clause)->iterexpr);
else if (is_subplan(clause))
{
List *temp;
foreach(temp, ((Expr *) clause)->args)
retval = nconc(retval, pull_var_clause(lfirst(temp)));
/* Ok - get Var-s from left sides of Oper-s */
/* Also get Var-s from left sides of Oper-s */
foreach(temp, ((SubPlan *) ((Expr *) clause)->oper)->sublink->oper)
retval = nconc(retval,
pull_var_clause(lfirst(((Expr *) lfirst(temp))->args)));
}
else if (IsA(clause, Expr))
{
/*
* Recursively scan the arguments of an expression.
* NOTE: this must come after is_subplan() case since
* subplan is a kind of Expr node.
*/
foreach(temp, ((Expr *) clause)->args)
retval = nconc(retval, pull_var_clause(lfirst(temp)));
}
else if (IsA(clause, Aggref))
retval = pull_var_clause(((Aggref *) clause)->target);
else if (IsA(clause, ArrayRef))
{
List *temp;
foreach(temp, ((ArrayRef *) clause)->refupperindexpr)
retval = nconc(retval, pull_var_clause(lfirst(temp)));
foreach(temp, ((ArrayRef *) clause)->reflowerindexpr)
......@@ -209,25 +209,21 @@ pull_var_clause(Node *clause)
retval = nconc(retval,
pull_var_clause(((ArrayRef *) clause)->refassgnexpr));
}
else if (not_clause(clause))
retval = pull_var_clause((Node *) get_notclausearg((Expr *) clause));
else if (is_opclause(clause))
retval = nconc(pull_var_clause((Node *) get_leftop((Expr *) clause)),
pull_var_clause((Node *) get_rightop((Expr *) clause)));
else if (case_clause(clause))
{
List *temp;
foreach(temp, ((CaseExpr *) clause)->args)
{
retval = nconc(retval, pull_var_clause(((CaseWhen *) lfirst(temp))->expr));
retval = nconc(retval, pull_var_clause(((CaseWhen *) lfirst(temp))->result));
CaseWhen *when = (CaseWhen *) lfirst(temp);
retval = nconc(retval, pull_var_clause(when->expr));
retval = nconc(retval, pull_var_clause(when->result));
}
retval = nconc(retval, pull_var_clause(((CaseExpr *) clause)->defresult));
}
else
retval = NIL;
{
elog(ERROR, "pull_var_clause: Cannot handle node type %d",
nodeTag(clause));
}
return retval;
}
......
......@@ -6,7 +6,7 @@
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: planmain.h,v 1.23 1999/04/19 01:43:10 tgl Exp $
* $Id: planmain.h,v 1.24 1999/05/03 00:38:42 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -54,9 +54,14 @@ extern List *join_references(List *clauses, List *outer_tlist,
List *inner_tlist);
extern List *index_outerjoin_references(List *inner_indxqual,
List *outer_tlist, Index inner_relid);
extern void replace_tlist_with_subplan_refs(List *tlist,
Index subvarno,
List *subplanTargetList);
extern void replace_vars_with_subplan_refs(Node *clause,
Index subvarno,
List *subplanTargetList);
extern bool set_agg_tlist_references(Agg *aggNode);
extern void del_agg_tlist_references(List *tlist);
extern List *check_having_qual_for_vars(Node *clause, List *targetlist_so_far);
extern void check_having_for_ungrouped_vars(Node *clause, List *groupClause);
extern void transformKeySetQuery(Query *origNode);
......
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