From 7fd4782504c6bb090261b03a3152193cd8e22439 Mon Sep 17 00:00:00 2001
From: Bruce Momjian <bruce@momjian.us>
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 a22c7e6ffc3..d26e3eb8b49 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 40e9cc50a63..381c609493b 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 b6afa5fcb92..1d0f0963c5a 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 e5346c388d7..7f9645e0f32 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 e2683fc61f7..04363edd03e 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 5040a32b852..8f63f798cb8 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 */
-- 
GitLab