diff options
Diffstat (limited to 'src/backend/optimizer/plan/planner.c')
-rw-r--r-- | src/backend/optimizer/plan/planner.c | 261 |
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); } } |