From 7fd4782504c6bb090261b03a3152193cd8e22439 Mon Sep 17 00:00:00 2001 From: Bruce Momjian Date: Sat, 20 Dec 1997 07:59:44 +0000 Subject: [PATCH] Fix aggregates on inherited tables. --- src/backend/optimizer/plan/planmain.c | 69 +----------------- src/backend/optimizer/plan/planner.c | 94 +++++++++++++++++++++---- src/backend/optimizer/plan/setrefs.c | 96 +++++++++++++++++++++++++- src/backend/optimizer/prep/prepunion.c | 19 ++--- src/include/optimizer/planmain.h | 3 +- src/include/optimizer/prep.h | 11 ++- 6 files changed, 193 insertions(+), 99 deletions(-) diff --git a/src/backend/optimizer/plan/planmain.c b/src/backend/optimizer/plan/planmain.c index a22c7e6ffc..d26e3eb8b4 100644 --- a/src/backend/optimizer/plan/planmain.c +++ b/src/backend/optimizer/plan/planmain.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.11 1997/12/18 12:54:09 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.12 1997/12/20 07:59:25 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -41,7 +41,7 @@ static Plan *subplanner(Query *root, List *flat_tlist, List *qual); static Result *make_result(List *tlist, Node *resconstantqual, Plan *subplan); -static Plan * +extern Plan * make_groupPlan(List **tlist, bool tuplePerGroup, List *groupClause, Plan *subplan); @@ -72,7 +72,6 @@ query_planner(Query *root, List *flattened_tlist = NIL; List *level_tlist = NIL; Plan *subplan = (Plan *) NULL; - Agg *aggplan = NULL; /* * A command without a target list or qualification is an error, @@ -174,49 +173,6 @@ query_planner(Query *root, set_tlist_references(subplan); - /* - * If we have a GROUP BY clause, insert a group node (with the - * appropriate sort node.) - */ - if (root->groupClause != NULL) - { - bool tuplePerGroup; - - /* - * decide whether how many tuples per group the Group node needs - * to return. (Needs only one tuple per group if no aggregate is - * present. Otherwise, need every tuple from the group to do the - * aggregation.) - */ - tuplePerGroup = (root->qry_aggs) ? TRUE : FALSE; - - subplan = - make_groupPlan(&tlist, tuplePerGroup, root->groupClause, subplan); - - } - - /* - * If aggregate is present, insert the agg node - */ - if (root->qry_aggs) - { - aggplan = make_agg(tlist, root->qry_numAgg, root->qry_aggs, subplan); - - /* - * set the varno/attno entries to the appropriate references to - * the result tuple of the subplans. (We need to set those in the - * array of aggreg's in the Agg node also. Even though they're - * pointers, after a few dozen's of copying, they're not the same - * as those in the target list.) - */ - set_agg_tlist_references(aggplan); - set_agg_agglist_references(aggplan); - - subplan = (Plan *) aggplan; - - tlist = aggplan->plan.targetlist; - } - /* * Build a result node linking the plan if we have constant quals */ @@ -236,25 +192,6 @@ query_planner(Query *root, return (plan); } - /* - * fix up the flattened target list of the plan root node so that - * expressions are evaluated. this forces expression evaluations that - * may involve expensive function calls to be delayed to the very last - * stage of query execution. this could be bad. but it is joey's - * 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 - */ - if (root->groupClause == NULL && aggplan == NULL) - { - subplan->targetlist = flatten_tlist_vars(tlist, - subplan->targetlist); - } - /* * Destructively modify the query plan's targetlist to add fjoin lists * to flatten functions that return sets of base types @@ -380,7 +317,7 @@ make_result(List *tlist, * *****************************************************************************/ -static Plan * +Plan * make_groupPlan(List **tlist, bool tuplePerGroup, List *groupClause, diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 40e9cc50a6..381c609493 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.13 1997/12/18 19:41:44 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.14 1997/12/20 07:59:27 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -47,6 +47,8 @@ #include "executor/executor.h" static Plan *make_sortplan(List *tlist, List *sortcls, Plan *plannode); +extern Plan *make_groupPlan(List **tlist, bool tuplePerGroup, + List *groupClause, Plan *subplan); /***************************************************************************** * @@ -72,13 +74,13 @@ planner(Query *parse) List *rangetable = parse->rtable; char *uniqueflag = parse->uniqueFlag; List *sortclause = parse->sortClause; - Plan *special_plans = (Plan *) NULL; + Agg *aggplan = NULL; Plan *result_plan = (Plan *) NULL; - List *preprocessed_tlist = NIL; List *primary_qual; int rt_index; + /* * plan inheritance @@ -86,28 +88,96 @@ planner(Query *parse) rt_index = first_matching_rt_entry(rangetable, INHERITS_FLAG); if (rt_index != -1) { - special_plans = (Plan *) plan_union_queries((Index) rt_index, + result_plan = (Plan *) plan_union_queries((Index) rt_index, parse, INHERITS_FLAG); + /* XXX do we need to do this? bjm 12/19/97 */ + tlist = preprocess_targetlist(tlist, + parse->commandType, + parse->resultRelation, + parse->rtable); } - - if (special_plans) - result_plan = special_plans; else { - preprocessed_tlist = preprocess_targetlist(tlist, - parse->commandType, - parse->resultRelation, - parse->rtable); + tlist = preprocess_targetlist(tlist, + parse->commandType, + parse->resultRelation, + parse->rtable); primary_qual = cnfify((Expr *) parse->qual, true); result_plan = query_planner(parse, parse->commandType, - preprocessed_tlist, + tlist, primary_qual); } + /* + * If we have a GROUP BY clause, insert a group node (with the + * appropriate sort node.) + */ + if (parse->groupClause != NULL) + { + bool tuplePerGroup; + + /* + * decide whether how many tuples per group the Group node needs + * to return. (Needs only one tuple per group if no aggregate is + * present. Otherwise, need every tuple from the group to do the + * aggregation.) + */ + tuplePerGroup = (parse->qry_aggs) ? TRUE : FALSE; + + result_plan = + make_groupPlan( &tlist, + tuplePerGroup, + parse->groupClause, + result_plan); + + } + + /* + * If aggregate is present, insert the agg node + */ + if (parse->qry_aggs) + { + aggplan = make_agg(tlist, + parse->qry_numAgg, + parse->qry_aggs, + result_plan); + + /* + * set the varno/attno entries to the appropriate references to + * the result tuple of the subplans. (We need to set those in the + * array of aggreg's in the Agg node also. Even though they're + * pointers, after a few dozen's of copying, they're not the same + * as those in the target list.) + */ + set_agg_tlist_references(aggplan); + set_agg_agglist_references(aggplan); + + result_plan = (Plan *) aggplan; + } + + /* + * fix up the flattened target list of the plan root node so that + * expressions are evaluated. this forces expression evaluations that + * may involve expensive function calls to be delayed to the very last + * stage of query execution. this could be bad. but it is joey's + * 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 + */ + if (parse->groupClause == NULL && aggplan == NULL) + { + result_plan->targetlist = flatten_tlist_vars(tlist, + result_plan->targetlist); + } + /* * 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 diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index b6afa5fcb9..1d0f0963c5 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.8 1997/09/08 21:45:28 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.9 1997/12/20 07:59:28 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -47,6 +47,7 @@ static List *tlist_temp_references(Oid tempid, List *tlist); static void replace_result_clause(List *clause, List *subplanTargetList); static bool OperandIsInner(Node *opnd, int inner_relid); static void replace_agg_clause(Node *expr, List *targetlist); +static Node *del_agg_clause(Node *clause); /***************************************************************************** * @@ -803,3 +804,96 @@ replace_agg_clause(Node *clause, List *subplanTargetList) } } + +/* + * del_agg_tlist_references + * Remove the Agg nodes from the target list + * We do this so inheritance only does aggregates in the upper node + */ +void del_agg_tlist_references(List *tlist) +{ + List *tl; + + foreach(tl, tlist) + { + TargetEntry *tle = lfirst(tl); + + tle->expr = del_agg_clause(tle->expr); + } +} + +static Node * +del_agg_clause(Node *clause) +{ + List *t; + + if (IsA(clause, Var)) + { + return clause; + } + else if (is_funcclause(clause)) + { + /* + * This is a function. Recursively call this routine for its + * arguments... + */ + foreach(t, ((Expr *) clause)->args) + { + lfirst(t) = del_agg_clause(lfirst(t)); + } + } + else if (IsA(clause, Aggreg)) + { + + /* here is the real action, to remove the Agg node */ + return del_agg_clause(((Aggreg *) clause)->target); + + } + else if (IsA(clause, ArrayRef)) + { + ArrayRef *aref = (ArrayRef *) clause; + + /* + * This is an arrayref. Recursively call this routine for its + * expression and its index expression... + */ + foreach(t, aref->refupperindexpr) + { + lfirst(t) = del_agg_clause(lfirst(t)); + } + foreach(t, aref->reflowerindexpr) + { + lfirst(t) = del_agg_clause(lfirst(t)); + } + aref->refexpr = del_agg_clause(aref->refexpr); + aref->refassgnexpr = del_agg_clause(aref->refassgnexpr); + } + else if (is_opclause(clause)) + { + + /* + * This is an operator. Recursively call this routine for both its + * left and right operands + */ + Node *left = (Node *) get_leftop((Expr *) clause); + Node *right = (Node *) get_rightop((Expr *) clause); + + if (left != (Node *) NULL) + left = del_agg_clause(left); + if (right != (Node *) NULL) + right = del_agg_clause(right); + } + else if (IsA(clause, Param) ||IsA(clause, Const)) + { + return clause; + } + else + { + + /* + * Ooops! we can not handle that! + */ + elog(WARN, "del_agg_clause: Can not handle this tlist!\n"); + } + return NULL; +} diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c index e5346c388d..7f9645e0f3 100644 --- a/src/backend/optimizer/prep/prepunion.c +++ b/src/backend/optimizer/prep/prepunion.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.10 1997/12/18 03:03:41 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.11 1997/12/20 07:59:33 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -33,21 +33,16 @@ #include "optimizer/planner.h" #include "optimizer/prep.h" -static List * -plan_union_query(List *relids, Index rt_index, +static List *plan_union_query(List *relids, Index rt_index, RangeTblEntry *rt_entry, Query *parse, UnionFlag flag, List **union_rtentriesPtr); -static RangeTblEntry * -new_rangetable_entry(Oid new_relid, +static RangeTblEntry *new_rangetable_entry(Oid new_relid, RangeTblEntry *old_entry); -static Query * -subst_rangetable(Query *root, Index index, +static Query *subst_rangetable(Query *root, Index index, RangeTblEntry *new_entry); -static void -fix_parsetree_attnums(Index rt_index, Oid old_relid, +static void fix_parsetree_attnums(Index rt_index, Oid old_relid, Oid new_relid, Query *parsetree); -static Append * -make_append(List *unionplans, Index rt_index, +static Append *make_append(List *unionplans, Index rt_index, List *union_rt_entries, List *tlist); @@ -238,12 +233,12 @@ plan_union_query(List *relids, * reset the uniqueflag and sortclause in parse tree root, so that * sorting will only be done once after append */ -/* new_root->uniqueFlag = false; */ new_root->uniqueFlag = NULL; new_root->sortClause = NULL; new_root->groupClause = NULL; new_root->qry_numAgg = 0; new_root->qry_aggs = NULL; + del_agg_tlist_references(new_root->targetList); fix_parsetree_attnums(rt_index, rt_entry->relid, relid, diff --git a/src/include/optimizer/planmain.h b/src/include/optimizer/planmain.h index e2683fc61f..04363edd03 100644 --- a/src/include/optimizer/planmain.h +++ b/src/include/optimizer/planmain.h @@ -6,7 +6,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: planmain.h,v 1.8 1997/12/18 12:54:41 momjian Exp $ + * $Id: planmain.h,v 1.9 1997/12/20 07:59:43 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -57,6 +57,7 @@ extern List *index_outerjoin_references(List *inner_indxqual, extern void set_result_tlist_references(Result *resultNode); extern void set_agg_tlist_references(Agg *aggNode); extern void set_agg_agglist_references(Agg *aggNode); +extern void del_agg_tlist_references(List *tlist); #endif /* PLANMAIN_H */ diff --git a/src/include/optimizer/prep.h b/src/include/optimizer/prep.h index 5040a32b85..8f63f798cb 100644 --- a/src/include/optimizer/prep.h +++ b/src/include/optimizer/prep.h @@ -6,7 +6,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: prep.h,v 1.8 1997/12/18 12:54:45 momjian Exp $ + * $Id: prep.h,v 1.9 1997/12/20 07:59:44 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -24,8 +24,7 @@ extern List *cnfify(Expr *qual, bool removeAndFlag); /* * prototypes for preptlist.h */ -extern List * -preprocess_targetlist(List *tlist, int command_type, +extern List *preprocess_targetlist(List *tlist, int command_type, Index result_relation, List *range_table); /* @@ -36,12 +35,10 @@ typedef enum UnionFlag INHERITS_FLAG, VERSION_FLAG } UnionFlag; -extern List * -find_all_inheritors(List *unexamined_relids, +extern List *find_all_inheritors(List *unexamined_relids, List *examined_relids); extern int first_matching_rt_entry(List *rangetable, UnionFlag flag); -extern Append * -plan_union_queries(Index rt_index, Query *parse, +extern Append *plan_union_queries(Index rt_index, Query *parse, UnionFlag flag); #endif /* PREP_H */ -- 2.40.0