aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/plan/planner.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/plan/planner.c')
-rw-r--r--src/backend/optimizer/plan/planner.c261
1 files changed, 144 insertions, 117 deletions
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 9cf0746145a..ec4597961a0 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.35 1998/09/09 03:48:01 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.36 1999/01/18 00:09:47 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -95,20 +95,26 @@ Plan *
union_planner(Query *parse)
{
List *tlist = parse->targetList;
- int tlist_len = length(tlist);
+
+ /***S*H***/
+ /* copy the original tlist, we will need the original one
+ * for the AGG node later on */
+ List *new_tlist = new_unsorted_tlist(tlist);
+
List *rangetable = parse->rtable;
+
Plan *result_plan = (Plan *) NULL;
- Index rt_index;
+ Index rt_index;
if (parse->unionClause)
{
- result_plan = (Plan *) plan_union_queries(parse);
- /* XXX do we need to do this? bjm 12/19/97 */
- tlist = preprocess_targetlist(tlist,
- parse->commandType,
- parse->resultRelation,
- parse->rtable);
+ result_plan = (Plan *) plan_union_queries(parse);
+ /* XXX do we need to do this? bjm 12/19/97 */
+ tlist = preprocess_targetlist(tlist,
+ parse->commandType,
+ parse->resultRelation,
+ parse->rtable);
}
else if ((rt_index =
first_inherit_rt_entry(rangetable)) != -1)
@@ -116,47 +122,65 @@ union_planner(Query *parse)
result_plan = (Plan *) plan_inherit_queries(parse, rt_index);
/* XXX do we need to do this? bjm 12/19/97 */
tlist = preprocess_targetlist(tlist,
- parse->commandType,
- parse->resultRelation,
- parse->rtable);
+ parse->commandType,
+ parse->resultRelation,
+ parse->rtable);
}
else
{
- List **vpm = NULL;
-
- /*
- * check_having_qual_for_vars takes the havingQual and the tlist
- * as arguments and recursively scans the havingQual for VAR nodes
- * that are not contained in tlist yet. If so, it creates a new entry
- * and attaches it to the tlist. Latter, we use tlist_len to
- * truncate tlist - ie restore actual tlist...
- */
- if (parse->hasAggs)
+ List **vpm = NULL;
+
+ /***S*H***/
+ /* This is only necessary if aggregates are in use in queries like:
+ * SELECT sid
+ * FROM part
+ * GROUP BY sid
+ * HAVING MIN(pid) > 1; (pid is used but never selected for!!!)
+ * because the function 'query_planner' creates the plan for the lefttree
+ * of the 'GROUP' node and returns only those attributes contained in 'tlist'.
+ * The original 'tlist' contains only 'sid' here and that's why we have to
+ * to extend it to attributes which are not selected but are used in the
+ * havingQual. */
+
+ /* 'check_having_qual_for_vars' takes the havingQual and the actual 'tlist'
+ * as arguments and recursively scans the havingQual for attributes
+ * (VAR nodes) that are not contained in 'tlist' yet. If so, it creates
+ * a new entry and attaches it to the list 'new_tlist' (consisting of the
+ * VAR node and the RESDOM node as usual with tlists :-) ) */
+ if (parse->hasAggs)
+ {
+ if (parse->havingQual != NULL)
{
- if (parse->havingQual != NULL)
- tlist = check_having_qual_for_vars(parse->havingQual, tlist);
+ new_tlist = check_having_qual_for_vars(parse->havingQual,new_tlist);
}
-
- tlist = preprocess_targetlist(tlist,
- parse->commandType,
- parse->resultRelation,
- parse->rtable);
-
- if (parse->rtable != NULL)
- {
- vpm = (List **) palloc(length(parse->rtable) * sizeof(List *));
- memset(vpm, 0, length(parse->rtable) * sizeof(List *));
- }
- PlannerVarParam = lcons(vpm, PlannerVarParam);
- result_plan = query_planner(parse,
- parse->commandType,
- tlist,
- (List *) parse->qual);
- PlannerVarParam = lnext(PlannerVarParam);
- if (vpm != NULL)
- pfree(vpm);
+ }
+
+ new_tlist = preprocess_targetlist(new_tlist,
+ parse->commandType,
+ parse->resultRelation,
+ parse->rtable);
+
+ /* Here starts the original (pre having) code */
+ tlist = preprocess_targetlist(tlist,
+ parse->commandType,
+ parse->resultRelation,
+ parse->rtable);
+
+ if (parse->rtable != NULL)
+ {
+ vpm = (List **) palloc(length(parse->rtable) * sizeof(List *));
+ memset(vpm, 0, length(parse->rtable) * sizeof(List *));
+ }
+ PlannerVarParam = lcons(vpm, PlannerVarParam);
+ result_plan = query_planner(parse,
+ parse->commandType,
+ new_tlist,
+ (List *) parse->qual);
+ PlannerVarParam = lnext(PlannerVarParam);
+ if (vpm != NULL)
+ pfree(vpm);
}
-
+
/*
* If we have a GROUP BY clause, insert a group node (with the
* appropriate sort node.)
@@ -173,8 +197,10 @@ union_planner(Query *parse)
*/
tuplePerGroup = parse->hasAggs;
+ /***S*H***/
+ /* Use 'new_tlist' instead of 'tlist' */
result_plan =
- make_groupPlan(&tlist,
+ make_groupPlan(&new_tlist,
tuplePerGroup,
parse->groupClause,
result_plan);
@@ -185,6 +211,11 @@ union_planner(Query *parse)
*/
if (parse->hasAggs)
{
+ int old_length=0, new_length=0;
+
+ /* Create the AGG node but use 'tlist' not 'new_tlist' as target list because we
+ * don't want the additional attributes (only used for the havingQual, see above)
+ * to show up in the result */
result_plan = (Plan *) make_agg(tlist, result_plan);
/*
@@ -192,78 +223,74 @@ union_planner(Query *parse)
* the result tuple of the subplans.
*/
((Agg *) result_plan)->aggs =
- set_agg_tlist_references((Agg *) result_plan);
+ set_agg_tlist_references((Agg *) result_plan);
- if (parse->havingQual != NULL)
- {
- List *clause;
- List **vpm = NULL;
-
- /*
- * Restore target list: get rid of Vars added for havingQual.
- * Assumption: tlist_len > 0...
- */
- {
- List *l;
- int tlen = 0;
-
- foreach (l, ((Agg *) result_plan)->plan.targetlist)
- {
- if (++tlen == tlist_len)
- break;
- }
- lnext(l) = NIL;
- }
-
- /*
- * stuff copied from above to handle the use of attributes
- * from outside in subselects
- */
-
- if (parse->rtable != NULL)
- {
- vpm = (List **) palloc(length(parse->rtable) * sizeof(List *));
- memset(vpm, 0, length(parse->rtable) * sizeof(List *));
- }
- PlannerVarParam = lcons(vpm, PlannerVarParam);
-
- /*
- * There is a subselect in the havingQual, so we have to
- * process it using the same function as for a subselect in
- * 'where'
- */
- if (parse->hasSubLinks)
- parse->havingQual = SS_process_sublinks((Node *) parse->havingQual);
-
- /* convert the havingQual to conjunctive normal form (cnf) */
- parse->havingQual = (Node *) cnfify((Expr *) (Node *) parse->havingQual, true);
-
- /*
- * Calculate the opfids from the opnos (=select the correct
- * functions for the used VAR datatypes)
- */
- parse->havingQual = (Node *) fix_opids((List *) parse->havingQual);
-
- ((Agg *) result_plan)->plan.qual = (List *) parse->havingQual;
-
- /*
- * Check every clause of the havingQual for aggregates used
- * and append them to result_plan->aggs
- */
- foreach(clause, ((Agg *) result_plan)->plan.qual)
- {
- ((Agg *) result_plan)->aggs = nconc(((Agg *) result_plan)->aggs,
- check_having_qual_for_aggs((Node *) lfirst(clause),
- ((Agg *) result_plan)->plan.lefttree->targetlist,
- ((List *) parse->groupClause)));
- }
- PlannerVarParam = lnext(PlannerVarParam);
- if (vpm != NULL)
- pfree(vpm);
- }
- }
+ /***S*H***/
+ if(parse->havingQual!=NULL)
+ {
+ List *clause;
+ List **vpm = NULL;
+
+
+ /* stuff copied from above to handle the use of attributes from outside
+ * in subselects */
+ if (parse->rtable != NULL)
+ {
+ vpm = (List **) palloc(length(parse->rtable) * sizeof(List *));
+ memset(vpm, 0, length(parse->rtable) * sizeof(List *));
+ }
+ PlannerVarParam = lcons(vpm, PlannerVarParam);
+
+
+ /* convert the havingQual to conjunctive normal form (cnf) */
+ (List *) parse->havingQual=cnfify((Expr *)(Node *) parse->havingQual,true);
+
+ /* There is a subselect in the havingQual, so we have to process it
+ * using the same function as for a subselect in 'where' */
+ if (parse->hasSubLinks)
+ {
+ (List *) parse->havingQual =
+ (List *) SS_process_sublinks((Node *) parse->havingQual);
+ }
+
+
+ /* Calculate the opfids from the opnos (=select the correct functions for
+ * the used VAR datatypes) */
+ (List *) parse->havingQual=fix_opids((List *) parse->havingQual);
+
+ ((Agg *) result_plan)->plan.qual=(List *) parse->havingQual;
+
+ /* Check every clause of the havingQual for aggregates used and append
+ * them to result_plan->aggs */
+ foreach(clause, ((Agg *) result_plan)->plan.qual)
+ {
+ /* Make sure there are aggregates in the havingQual
+ * if so, the list must be longer after check_having_qual_for_aggs */
+ old_length=length(((Agg *) result_plan)->aggs);
+
+ ((Agg *) result_plan)->aggs = nconc(((Agg *) result_plan)->aggs,
+ check_having_qual_for_aggs((Node *) lfirst(clause),
+ ((Agg *) result_plan)->plan.lefttree->targetlist,
+ ((List *) parse->groupClause)));
+
+ /* Have a look at the length of the returned list. If there is no
+ * difference, no aggregates have been found and that means, that
+ * the Qual belongs to the where clause */
+ if (((new_length=length(((Agg *) result_plan)->aggs)) == old_length) ||
+ (new_length == 0))
+ {
+ elog(ERROR,"This could have been done in a where clause!!");
+ return (Plan *)NIL;
+ }
+ }
+ PlannerVarParam = lnext(PlannerVarParam);
+ if (vpm != NULL)
+ pfree(vpm);
+ }
+ }
+
/*
* For now, before we hand back the plan, check to see if there is a
* user-specified sort that needs to be done. Eventually, this will
@@ -277,14 +304,14 @@ union_planner(Query *parse)
{
Plan *sortplan = make_sortplan(tlist, parse->sortClause, result_plan);
- return (Plan *) make_unique(tlist, sortplan, parse->uniqueFlag);
+ return ((Plan *) make_unique(tlist, sortplan, parse->uniqueFlag));
}
else
{
if (parse->sortClause)
- return make_sortplan(tlist, parse->sortClause, result_plan);
+ return (make_sortplan(tlist, parse->sortClause, result_plan));
else
- return (Plan *) result_plan;
+ return ((Plan *) result_plan);
}
}