]> granicus.if.org Git - postgresql/commitdiff
Fix aggregates on inherited tables.
authorBruce Momjian <bruce@momjian.us>
Sat, 20 Dec 1997 07:59:44 +0000 (07:59 +0000)
committerBruce Momjian <bruce@momjian.us>
Sat, 20 Dec 1997 07:59:44 +0000 (07:59 +0000)
src/backend/optimizer/plan/planmain.c
src/backend/optimizer/plan/planner.c
src/backend/optimizer/plan/setrefs.c
src/backend/optimizer/prep/prepunion.c
src/include/optimizer/planmain.h
src/include/optimizer/prep.h

index a22c7e6ffc3267c7ca3fbffa2434bc8a8e3c1ed9..d26e3eb8b49962126ba55f913c60a1b0f4f37bc4 100644 (file)
@@ -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,
index 40e9cc50a63f5cd9e4c414825c2e93f771581751..381c609493b278b29362f3b1c245a5fbafb38b16 100644 (file)
@@ -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
index b6afa5fcb924bcb6e2dc318362b97afc4e4646c5..1d0f0963c5ac26cd47109bc841f2b806980aeaa6 100644 (file)
@@ -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;
+}
index e5346c388d78dc2ec041b41ffb9fa60da9814cff..7f9645e0f32a736a4a560062aa1beec9f5bbe7fc 100644 (file)
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
 #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,
index e2683fc61f7a84876c5b10595e7d0930fb58bb37..04363edd03e94627eba276f47f0bb1c42eb8b330 100644 (file)
@@ -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 */
index 5040a32b8527792ba572f39ad44bf0162a744fa9..8f63f798cb8dafbfc1102ca223571b814ad33174 100644 (file)
@@ -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 */