Fix aggregates on inherited tables.
authorBruce Momjian
Sat, 20 Dec 1997 07:59:44 +0000 (07:59 +0000)
committerBruce Momjian
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 */