mirror of
https://github.com/postgres/postgres.git
synced 2025-08-06 18:42:54 +03:00
Changes for GROUP BY func_results.
This commit is contained in:
@@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.2 1996/10/31 10:59:14 scrappy Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.3 1997/04/05 06:37:37 vadim Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -19,6 +19,7 @@
|
|||||||
#include "nodes/plannodes.h"
|
#include "nodes/plannodes.h"
|
||||||
#include "nodes/parsenodes.h"
|
#include "nodes/parsenodes.h"
|
||||||
#include "nodes/relation.h"
|
#include "nodes/relation.h"
|
||||||
|
#include "nodes/makefuncs.h"
|
||||||
|
|
||||||
#include "optimizer/planmain.h"
|
#include "optimizer/planmain.h"
|
||||||
#include "optimizer/internal.h"
|
#include "optimizer/internal.h"
|
||||||
@@ -26,6 +27,7 @@
|
|||||||
#include "optimizer/clauses.h"
|
#include "optimizer/clauses.h"
|
||||||
#include "optimizer/keys.h"
|
#include "optimizer/keys.h"
|
||||||
#include "optimizer/tlist.h"
|
#include "optimizer/tlist.h"
|
||||||
|
#include "optimizer/var.h"
|
||||||
#include "optimizer/xfunc.h"
|
#include "optimizer/xfunc.h"
|
||||||
#include "optimizer/cost.h"
|
#include "optimizer/cost.h"
|
||||||
|
|
||||||
@@ -39,7 +41,7 @@
|
|||||||
static Plan *subplanner(Query *root, List *flat_tlist, List *qual);
|
static Plan *subplanner(Query *root, List *flat_tlist, List *qual);
|
||||||
static Result *make_result(List *tlist, Node *resconstantqual, Plan *subplan);
|
static Result *make_result(List *tlist, Node *resconstantqual, Plan *subplan);
|
||||||
|
|
||||||
static Plan *make_groupPlan(List *tlist, bool tuplePerGroup,
|
static Plan *make_groupPlan(List **tlist, bool tuplePerGroup,
|
||||||
List *groupClause, Plan *subplan);
|
List *groupClause, Plan *subplan);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -110,20 +112,6 @@ query_planner(Query *root,
|
|||||||
level_tlist = tlist;
|
level_tlist = tlist;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Needs to add the group attribute(s) to the target list so that they
|
|
||||||
* are available to either the Group node or the Agg node. (The target
|
|
||||||
* list may not contain the group attribute(s).)
|
|
||||||
*/
|
|
||||||
if (root->groupClause) {
|
|
||||||
AddGroupAttrToTlist(level_tlist, root->groupClause);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (root->qry_aggs) {
|
|
||||||
aggplan = make_agg(tlist, root->qry_numAgg, root->qry_aggs);
|
|
||||||
tlist = level_tlist;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A query may have a non-variable target list and a non-variable
|
* A query may have a non-variable target list and a non-variable
|
||||||
* qualification only under certain conditions:
|
* qualification only under certain conditions:
|
||||||
@@ -184,23 +172,20 @@ query_planner(Query *root,
|
|||||||
* present. Otherwise, need every tuple from the group to do the
|
* present. Otherwise, need every tuple from the group to do the
|
||||||
* aggregation.)
|
* aggregation.)
|
||||||
*/
|
*/
|
||||||
tuplePerGroup = (aggplan == NULL) ? FALSE : TRUE;
|
tuplePerGroup = ( root->qry_aggs ) ? TRUE : FALSE;
|
||||||
|
|
||||||
subplan =
|
subplan =
|
||||||
make_groupPlan(tlist, tuplePerGroup, root->groupClause, subplan);
|
make_groupPlan(&tlist, tuplePerGroup, root->groupClause, subplan);
|
||||||
|
|
||||||
/* XXX fake it: this works for the Group node too! very very ugly,
|
|
||||||
please change me -ay 2/95 */
|
|
||||||
set_agg_tlist_references((Agg*)subplan);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If aggregate is present, insert the agg node
|
* If aggregate is present, insert the agg node
|
||||||
*/
|
*/
|
||||||
if (aggplan != NULL) {
|
if ( root->qry_aggs )
|
||||||
|
{
|
||||||
|
aggplan = make_agg(tlist, root->qry_numAgg, root->qry_aggs);
|
||||||
aggplan->plan.lefttree = subplan;
|
aggplan->plan.lefttree = subplan;
|
||||||
subplan = (Plan*)aggplan;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* set the varno/attno entries to the appropriate references to
|
* set the varno/attno entries to the appropriate references to
|
||||||
* the result tuple of the subplans. (We need to set those in the
|
* the result tuple of the subplans. (We need to set those in the
|
||||||
@@ -208,8 +193,10 @@ query_planner(Query *root,
|
|||||||
* pointers, after a few dozen's of copying, they're not the same as
|
* pointers, after a few dozen's of copying, they're not the same as
|
||||||
* those in the target list.)
|
* those in the target list.)
|
||||||
*/
|
*/
|
||||||
set_agg_tlist_references((Agg*)subplan);
|
set_agg_tlist_references (aggplan);
|
||||||
set_agg_agglist_references((Agg*)subplan);
|
set_agg_agglist_references (aggplan);
|
||||||
|
|
||||||
|
subplan = (Plan*)aggplan;
|
||||||
|
|
||||||
tlist = aggplan->plan.targetlist;
|
tlist = aggplan->plan.targetlist;
|
||||||
}
|
}
|
||||||
@@ -238,9 +225,17 @@ query_planner(Query *root,
|
|||||||
* the very last stage of query execution. this could be bad.
|
* the very last stage of query execution. this could be bad.
|
||||||
* but it is joey's responsibility to optimally push these
|
* but it is joey's responsibility to optimally push these
|
||||||
* expressions down the plan tree. -- Wei
|
* 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
|
||||||
*/
|
*/
|
||||||
|
if ( root->groupClause == NULL && aggplan == NULL )
|
||||||
|
{
|
||||||
subplan->targetlist = flatten_tlist_vars(tlist,
|
subplan->targetlist = flatten_tlist_vars(tlist,
|
||||||
subplan->targetlist);
|
subplan->targetlist);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Destructively modify the query plan's targetlist to add fjoin
|
* Destructively modify the query plan's targetlist to add fjoin
|
||||||
@@ -356,58 +351,130 @@ make_result(List *tlist,
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
static Plan *
|
static Plan *
|
||||||
make_groupPlan(List *tlist,
|
make_groupPlan(List **tlist,
|
||||||
bool tuplePerGroup,
|
bool tuplePerGroup,
|
||||||
List *groupClause,
|
List *groupClause,
|
||||||
Plan *subplan)
|
Plan *subplan)
|
||||||
{
|
{
|
||||||
List *sort_tlist;
|
List *sort_tlist;
|
||||||
List *gl;
|
List *sl, *gl;
|
||||||
int keyno;
|
List *glc = listCopy (groupClause);
|
||||||
|
List *aggvals = NIL; /* list of vars of aggregates */
|
||||||
|
int aggvcnt;
|
||||||
Sort *sortplan;
|
Sort *sortplan;
|
||||||
Group *grpplan;
|
Group *grpplan;
|
||||||
int numCols;
|
int numCols;
|
||||||
AttrNumber *grpColIdx;
|
AttrNumber *grpColIdx;
|
||||||
|
int keyno = 1;
|
||||||
|
int last_resno = 1;
|
||||||
|
|
||||||
numCols = length(groupClause);
|
numCols = length(groupClause);
|
||||||
grpColIdx = (AttrNumber *)palloc(sizeof(AttrNumber)*numCols);
|
grpColIdx = (AttrNumber *)palloc(sizeof(AttrNumber)*numCols);
|
||||||
|
|
||||||
/*
|
sort_tlist = new_unsorted_tlist(*tlist); /* it's copy */
|
||||||
* first, make a sort node. Group node expects the tuples it gets
|
|
||||||
* from the subplan is in the order as specified by the group columns.
|
|
||||||
*/
|
|
||||||
keyno = 1;
|
|
||||||
sort_tlist = new_unsorted_tlist(subplan->targetlist);
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make template TL for subplan, Sort & Group:
|
||||||
|
* 1. Take away Aggregates 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)
|
||||||
{
|
{
|
||||||
/* if this is a mergejoin node, varno could be OUTER/INNER */
|
Resdom *resdom = NULL;
|
||||||
List *l;
|
TargetEntry *te = (TargetEntry *) lfirst (sl);
|
||||||
foreach(l, sort_tlist) {
|
|
||||||
TargetEntry *tle;
|
|
||||||
tle = lfirst(l);
|
|
||||||
((Var*)tle->expr)->varno = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (gl, groupClause) {
|
foreach (gl, glc)
|
||||||
|
{
|
||||||
GroupClause *grpcl = (GroupClause*)lfirst(gl);
|
GroupClause *grpcl = (GroupClause*)lfirst(gl);
|
||||||
TargetEntry *tle;
|
|
||||||
|
|
||||||
tle = match_varid(grpcl->grpAttr, sort_tlist);
|
if ( grpcl->resdom->resno == te->resdom->resno )
|
||||||
/*
|
{
|
||||||
* the parser should have checked to make sure the group attribute
|
|
||||||
* is valid but the optimizer might have screwed up and hence we
|
resdom = te->resdom;
|
||||||
* check again.
|
resdom->reskey = keyno;
|
||||||
*/
|
resdom->reskeyop = get_opcode (grpcl->grpOpoid);
|
||||||
if (tle==NULL) {
|
resdom->resno = last_resno; /* re-set */
|
||||||
|
grpColIdx[keyno-1] = last_resno++;
|
||||||
|
keyno++;
|
||||||
|
glc = lremove (lfirst (gl), glc); /* TLE found for it */
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
resdom->resno = last_resno++; /* re-set */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( length (glc) != 0 )
|
||||||
|
{
|
||||||
elog(WARN, "group attribute disappeared from target list");
|
elog(WARN, "group attribute disappeared from target list");
|
||||||
}
|
}
|
||||||
tle->resdom->reskey = keyno;
|
|
||||||
tle->resdom->reskeyop = get_opcode(grpcl->grpOpoid);
|
|
||||||
|
|
||||||
grpColIdx[keyno-1] = tle->resdom->resno;
|
/*
|
||||||
keyno++;
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
aggvcnt = length (aggvals);
|
||||||
|
foreach (gl, aggvals)
|
||||||
|
{
|
||||||
|
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 */
|
||||||
|
aggvcnt--;
|
||||||
|
}
|
||||||
|
/* Now aggvcnt is number of Vars added in TL for Aggregates */
|
||||||
|
|
||||||
|
/* 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) )
|
||||||
|
{
|
||||||
|
#if 0 /* 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,
|
||||||
|
-1, resdom->resno);
|
||||||
|
}
|
||||||
|
|
||||||
sortplan = make_sort(sort_tlist,
|
sortplan = make_sort(sort_tlist,
|
||||||
_TEMP_RELATION_ID_,
|
_TEMP_RELATION_ID_,
|
||||||
subplan,
|
subplan,
|
||||||
@@ -417,8 +484,41 @@ make_groupPlan(List *tlist,
|
|||||||
/*
|
/*
|
||||||
* make the Group node
|
* make the Group node
|
||||||
*/
|
*/
|
||||||
tlist = copyObject(tlist); /* make a copy */
|
sort_tlist = copyObject (sort_tlist);
|
||||||
grpplan = make_group(tlist, tuplePerGroup, numCols, grpColIdx, sortplan);
|
grpplan = make_group(sort_tlist, tuplePerGroup, numCols,
|
||||||
|
grpColIdx, sortplan);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make TL for parent: "restore" Aggregates and
|
||||||
|
* resno-s of others accordantly.
|
||||||
|
*/
|
||||||
|
sl = sort_tlist;
|
||||||
|
sort_tlist = NIL; /* to be new parent TL */
|
||||||
|
foreach (gl, *tlist)
|
||||||
|
{
|
||||||
|
TargetEntry *te = (TargetEntry *) lfirst (gl);
|
||||||
|
|
||||||
|
if ( !IsA (te->expr, Aggreg) ) /* 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;
|
||||||
|
}
|
||||||
|
/* TLE of an aggregate */
|
||||||
|
sort_tlist = lappend (sort_tlist, copyObject(te));
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Pure aggregates Vars were at the end of Group' TL.
|
||||||
|
* They shouldn't appear in parent TL, all others shouldn't
|
||||||
|
* disappear.
|
||||||
|
*/
|
||||||
|
Assert ( aggvcnt == length (sl) );
|
||||||
|
|
||||||
|
*tlist = sort_tlist;
|
||||||
|
|
||||||
return (Plan*)grpplan;
|
return (Plan*)grpplan;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user