diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index b58e386535f31cd53352ee7cc7549cc6d8b8d939..e691e8cfc5b0789a732b6fb769e381e46d3c5139 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.13 1997/09/08 21:44:44 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.14 1997/12/21 05:18:18 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -44,7 +44,7 @@ int32		_use_geqo_rels_ = GEQO_RELS;
 
 
 static void find_rel_paths(Query *root, List *rels);
-static List *find_join_paths(Query *root, List *outer_rels, int levels_left);
+static List *find_join_paths(Query *root, List *outer_rels, int levels_needed);
 
 /*
  * find-paths--
@@ -56,14 +56,14 @@ static List *find_join_paths(Query *root, List *outer_rels, int levels_left);
 List	   *
 find_paths(Query *root, List *rels)
 {
-	int			levels_left;
+	int			levels_needed;
 
 	/*
 	 * Set the number of join (not nesting) levels yet to be processed.
 	 */
-	levels_left = length(rels);
+	levels_needed = length(rels);
 
-	if (levels_left <= 0)
+	if (levels_needed <= 0)
 		return NIL;
 
 	/*
@@ -71,13 +71,13 @@ find_paths(Query *root, List *rels)
 	 */
 	find_rel_paths(root, rels);
 
-	if (levels_left <= 1)
+	if (levels_needed <= 1)
 	{
 
 		/*
 		 * Unsorted single relation, no more processing is required.
 		 */
-		return (rels);
+		return rels;
 	}
 	else
 	{
@@ -88,7 +88,7 @@ find_paths(Query *root, List *rels)
 		 */
 		set_rest_relselec(root, rels);
 
-		return (find_join_paths(root, rels, levels_left - 1));
+		return find_join_paths(root, rels, levels_needed);
 	}
 }
 
@@ -165,17 +165,16 @@ find_rel_paths(Query *root, List *rels)
  * 'outer-rels' is the current list of relations for which join paths
  *				are to be found, i.e., he current list of relations that
  *				have already been derived.
- * 'levels-left' is the current join level being processed, where '1' is
- *				the "last" level
+ * 'levels-needed' is the number of iterations needed
  *
  * Returns the final level of join relations, i.e., the relation that is
- * the result of joining all the original relations togehter.
+ * the result of joining all the original relations together.
  */
 static List *
-find_join_paths(Query *root, List *outer_rels, int levels_left)
+find_join_paths(Query *root, List *outer_rels, int levels_needed)
 {
 	List	   *x;
-	List	   *new_rels;
+	List	   *new_rels = NIL;
 	Rel		   *rel;
 
 	/*******************************************
@@ -190,89 +189,84 @@ find_join_paths(Query *root, List *outer_rels, int levels_left)
 	 * rest will be deprecated in case of GEQO *
 	 *******************************************/
 
-	/*
-	 * Determine all possible pairs of relations to be joined at this
-	 * level. Determine paths for joining these relation pairs and modify
-	 * 'new-rels' accordingly, then eliminate redundant join relations.
-	 */
-	new_rels = find_join_rels(root, outer_rels);
-
-	find_all_join_paths(root, new_rels);
-
-	new_rels = prune_joinrels(new_rels);
-
+	 while (--levels_needed)
+	 {
+		/*
+		 * Determine all possible pairs of relations to be joined at this
+		 * level. Determine paths for joining these relation pairs and modify
+		 * 'new-rels' accordingly, then eliminate redundant join relations.
+		 */
+		new_rels = find_join_rels(root, outer_rels);
+	
+		find_all_join_paths(root, new_rels);
+	
+		prune_joinrels(new_rels);
+	
 #if 0
-
-	/*
-	 * * for each expensive predicate in each path in each distinct rel, *
-	 * consider doing pullup  -- JMH
-	 */
-	if (XfuncMode != XFUNC_NOPULL && XfuncMode != XFUNC_OFF)
-		foreach(x, new_rels)
-			xfunc_trypullup((Rel *) lfirst(x));
-#endif
-
-	prune_rel_paths(new_rels);
-
-	if (BushyPlanFlag)
-	{
-
+	
 		/*
-		 * In case of bushy trees if there is still a join between a join
-		 * relation and another relation, add a new joininfo that involves
-		 * the join relation to the joininfo list of the other relation
+		 * * for each expensive predicate in each path in each distinct rel, *
+		 * consider doing pullup  -- JMH
 		 */
-		add_new_joininfos(root, new_rels, outer_rels);
-	}
-
-	foreach(x, new_rels)
-	{
-		rel = (Rel *) lfirst(x);
-		if (rel->size <= 0)
-			rel->size = compute_rel_size(rel);
-		rel->width = compute_rel_width(rel);
-
-/*#define OPTIMIZER_DEBUG*/
+		if (XfuncMode != XFUNC_NOPULL && XfuncMode != XFUNC_OFF)
+			foreach(x, new_rels)
+				xfunc_trypullup((Rel *) lfirst(x));
+#endif
+	
+		prune_rel_paths(new_rels);
+	
+		if (BushyPlanFlag)
+		{
+	
+			/*
+			 * In case of bushy trees if there is still a join between a join
+			 * relation and another relation, add a new joininfo that involves
+			 * the join relation to the joininfo list of the other relation
+			 */
+			add_new_joininfos(root, new_rels, outer_rels);
+		}
+	
+		foreach(x, new_rels)
+		{
+			rel = (Rel *) lfirst(x);
+			if (rel->size <= 0)
+				rel->size = compute_rel_size(rel);
+			rel->width = compute_rel_width(rel);
+	
+	/*#define OPTIMIZER_DEBUG*/
 #ifdef OPTIMIZER_DEBUG
-		printf("levels left: %d\n", levels_left);
-		debug_print_rel(root, rel);
+			printf("levels left: %d\n", levels_left);
+			debug_print_rel(root, rel);
 #endif
-	}
-
-	if (BushyPlanFlag)
-	{
-
-		/*
-		 * prune rels that have been completely incorporated into new join
-		 * rels
-		 */
-		outer_rels = prune_oldrels(outer_rels);
-
-		/*
-		 * merge join rels if then contain the same list of base rels
-		 */
-		outer_rels = merge_joinrels(new_rels, outer_rels);
-		root->join_relation_list_ = outer_rels;
-	}
-	else
-	{
-		root->join_relation_list_ = new_rels;
-	}
-
-	if (levels_left == 1)
-	{
+		}
+	
 		if (BushyPlanFlag)
-			return (final_join_rels(outer_rels));
+		{
+	
+			/*
+			 * prune rels that have been completely incorporated into new join
+			 * rels
+			 */
+			outer_rels = prune_oldrels(outer_rels);
+	
+			/*
+			 * merge join rels if then contain the same list of base rels
+			 */
+			outer_rels = merge_joinrels(new_rels, outer_rels);
+			root->join_relation_list_ = outer_rels;
+		}
 		else
-			return (new_rels);
+		{
+			root->join_relation_list_ = new_rels;
+		}
+		if (!BushyPlanFlag)
+			outer_rels = new_rels;
 	}
+
+	if (BushyPlanFlag)
+		return final_join_rels(outer_rels);
 	else
-	{
-		if (BushyPlanFlag)
-			return (find_join_paths(root, outer_rels, levels_left - 1));
-		else
-			return (find_join_paths(root, new_rels, levels_left - 1));
-	}
+		return new_rels;
 }
 
 /*****************************************************************************
diff --git a/src/backend/optimizer/path/prune.c b/src/backend/optimizer/path/prune.c
index d6064ab8e6850ec88b8cddc891ebcaee9844eaf1..26bd559696360fdb0154976b82ea609941e2c072 100644
--- a/src/backend/optimizer/path/prune.c
+++ b/src/backend/optimizer/path/prune.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/prune.c,v 1.6 1997/09/08 21:45:08 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/prune.c,v 1.7 1997/12/21 05:18:21 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -29,23 +29,21 @@ static List *prune_joinrel(Rel *rel, List *other_rels);
 /*
  * prune-joinrels--
  *	  Removes any redundant relation entries from a list of rel nodes
- *	  'rel-list'.
+ *	  'rel-list'.  Obviosly, the first relation can't be a duplicate.
  *
  * Returns the resulting list.
  *
  */
-List	   *
+void
 prune_joinrels(List *rel_list)
 {
-	List	   *temp_list = NIL;
+	List	   *i;
 
-	if (rel_list != NIL)
-	{
-		temp_list = lcons(lfirst(rel_list),
-				   prune_joinrels(prune_joinrel((Rel *) lfirst(rel_list),
-												lnext(rel_list))));
-	}
-	return (temp_list);
+	/*
+	 *	rel_list can shorten while running as duplicate relations are deleted
+	 */
+	foreach(i, rel_list)
+		lnext(i) = prune_joinrel((Rel *) lfirst(i), lnext(i));
 }
 
 /*
@@ -62,28 +60,39 @@ prune_joinrels(List *rel_list)
 static List *
 prune_joinrel(Rel *rel, List *other_rels)
 {
-	List	   *i = NIL;
-	List	   *t_list = NIL;
-	List	   *temp_node = NIL;
-	Rel		   *other_rel = (Rel *) NULL;
+	List	*cur = NIL;
+	List	*return_list = NIL;
 
-	foreach(i, other_rels)
+	/* find first relation that doesn't match */
+	foreach(cur, other_rels)
 	{
-		other_rel = (Rel *) lfirst(i);
-		if (same(rel->relids, other_rel->relids))
-		{
-			rel->pathlist = add_pathlist(rel,
-										 rel->pathlist,
-										 other_rel->pathlist);
-			t_list = nconc(t_list, NIL);		/* XXX is this right ? */
-		}
-		else
+		Rel	*other_rel = (Rel *) lfirst(cur);
+
+		if (!same(rel->relids, other_rel->relids))
+			break;
+	}
+
+	/* we now know cur doesn't match, or is NIL */
+	return_list = cur;
+	
+	/* remove relations that do match, we use lnext so we can remove easily */
+	if (cur != NIL)
+	{
+		while (lnext(cur) != NIL)
 		{
-			temp_node = lcons(other_rel, NIL);
-			t_list = nconc(t_list, temp_node);
+			Rel	*other_rel = (Rel *) lfirst(lnext(cur));
+
+			if (same(rel->relids, other_rel->relids))
+			{
+				rel->pathlist = add_pathlist(rel,
+											 rel->pathlist,
+											 other_rel->pathlist);
+				lnext(cur) = lnext(lnext(cur)); /* delete it */
+			}
+			cur = lnext(cur);
 		}
 	}
-	return (t_list);
+	return return_list;
 }
 
 /*
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index 7f9645e0f32a736a4a560062aa1beec9f5bbe7fc..11e9489942ed5db2ca950bd6e0e4ca252e5e3f3d 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.11 1997/12/20 07:59:33 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.12 1997/12/21 05:18:28 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -236,9 +236,13 @@ plan_union_query(List *relids,
 		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);
+		if (new_root->qry_numAgg != 0)
+		{
+			new_root->qry_numAgg = 0;
+			pfree(new_root->qry_aggs);
+			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/paths.h b/src/include/optimizer/paths.h
index b7a56ef65363f027e1c564c0e7dbbe342fedea90..42491d76053d1acc5d3ca6cdc8b6ca54fe0329b3 100644
--- a/src/include/optimizer/paths.h
+++ b/src/include/optimizer/paths.h
@@ -7,7 +7,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: paths.h,v 1.5 1997/11/26 01:13:47 momjian Exp $
+ * $Id: paths.h,v 1.6 1997/12/21 05:18:48 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -92,7 +92,7 @@ extern List *final_join_rels(List *join_rel_list);
 /*
  * prototypes for path/prune.c
  */
-extern List *prune_joinrels(List *rel_list);
+extern void prune_joinrels(List *rel_list);
 extern void prune_rel_paths(List *rel_list);
 extern Path *prune_rel_path(Rel *rel, Path *unorderedpath);
 extern List *merge_joinrels(List *rel_list1, List *rel_list2);