diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c
index 3c073101275edd573767bb3c77d0ed3882aa02a3..cdc0e56a1b7042d8d246e8901087c306ba9c853e 100644
--- a/src/backend/executor/nodeAppend.c
+++ b/src/backend/executor/nodeAppend.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.9 1997/09/08 21:43:10 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.10 1997/12/27 06:40:50 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -34,7 +34,7 @@
  *			  nil	nil		 ...	...    ...
  *								 subplans
  *
- *		Append nodes are currently used to support inheritance
+ *		Append nodes are currently used to unions, and to support inheritance
  *		queries, where several relations need to be scanned.
  *		For example, in our standard person/student/employee/student-emp
  *		example, where student and employee inherit from person
@@ -85,6 +85,7 @@ exec_append_initialize_next(Append *node)
 
 	int			whichplan;
 	int			nplans;
+	List	   *rts;
 	List	   *rtentries;
 	ResTarget  *rtentry;
 
@@ -101,6 +102,7 @@ exec_append_initialize_next(Append *node)
 
 	whichplan = unionstate->as_whichplan;
 	nplans = unionstate->as_nplans;
+	rts = node->unionrts;
 	rtentries = node->unionrtentries;
 
 	if (whichplan < 0)
@@ -140,27 +142,28 @@ exec_append_initialize_next(Append *node)
 		if (node->unionrelid > 0)
 		{
 			rtentry = nth(whichplan, rtentries);
-			if (rtentry == NULL)
-				elog(DEBUG, "exec_append_initialize_next: rtentry is nil");
+			Assert(rtentry != NULL);
 
 			unionrelid = node->unionrelid;
 
 			rt_store(unionrelid, rangeTable, rtentry);
-
-			if (unionstate->as_junkFilter_list)
-			{
-				estate->es_junkFilter =
-					(JunkFilter *) nth(whichplan,
-									   unionstate->as_junkFilter_list);
-			}
-			if (unionstate->as_result_relation_info_list)
-			{
-				estate->es_result_relation_info =
-					(RelationInfo *) nth(whichplan,
-							   unionstate->as_result_relation_info_list);
-			}
-			result_slot->ttc_whichplan = whichplan;
 		}
+		else
+			estate->es_range_table = nth(whichplan, rts);
+		
+		if (unionstate->as_junkFilter_list)
+		{
+			estate->es_junkFilter =
+				(JunkFilter *) nth(whichplan,
+								   unionstate->as_junkFilter_list);
+		}
+		if (unionstate->as_result_relation_info_list)
+		{
+			estate->es_result_relation_info =
+				(RelationInfo *) nth(whichplan,
+						   unionstate->as_result_relation_info_list);
+		}
+		result_slot->ttc_whichplan = whichplan;
 
 		return TRUE;
 	}
@@ -439,8 +442,7 @@ ExecProcAppend(Append *node)
 		if (exec_append_initialize_next(node))
 		{
 			ExecSetSlotDescriptorIsNew(result_slot, true);
-			return
-				ExecProcAppend(node);
+			return ExecProcAppend(node);
 		}
 		else
 			return ExecClearTuple(result_slot);
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 7b4bfc61e3154f1e17907ca4457fb78112d6509a..a7fa85d31f821bb87f133899dbb9ee82bc3b7557 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.13 1997/12/23 19:50:54 thomas Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.14 1997/12/27 06:40:54 momjian Exp $
  *
  * NOTES
  *	  Every (plan) node in POSTGRES has an associated "out" routine which
@@ -194,7 +194,7 @@ _outQuery(StringInfo str, Query *node)
 	sprintf(buf, " :qual ");
 	appendStringInfo(str, buf);
 	_outNode(str, node->qual);
-
+	/* how are we handling aggregates, sort, and group by? bjm 1997/12/26 */
 }
 
 /*
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 2fd639aaf48e166050a3bc8717c2acd5b699eca4..8f1e6ff2655717da9c0c6bd948928687249269c5 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.11 1997/12/18 12:53:59 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.12 1997/12/27 06:40:59 momjian Exp $
  *
  * NOTES
  *	  Most of the read functions for plan nodes are tested. (In fact, they
@@ -119,6 +119,7 @@ _readQuery()
 
 	token = lsptok(NULL, &length);		/* skip :qual */
 	local_node->qual = nodeRead(true);
+	/* how are we handling aggregates, sort, and group by? bjm 1997/12/26 */
 
 	return (local_node);
 }
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index cc3d9dfd7f83784bcde00eb9186bf0b5992d219f..5c5e80f333d23617b0645058c6463b987bd285c2 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.16 1997/12/24 06:06:01 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.17 1997/12/27 06:41:07 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -72,8 +72,6 @@ planner(Query *parse)
 {
 	List	   *tlist = parse->targetList;
 	List	   *rangetable = parse->rtable;
-	char	   *uniqueflag = parse->uniqueFlag;
-	List	   *sortclause = parse->sortClause;
 
 	Plan	   *result_plan = (Plan *) NULL;
 
@@ -83,7 +81,7 @@ planner(Query *parse)
 
 	if (parse->unionClause)
 	{
-		result_plan = (Plan *) plan_union_queries(0, /* none */
+		result_plan = (Plan *) plan_union_queries(  0, /* none */
 													parse,
 													UNION_FLAG);
 		/* XXX do we need to do this? bjm 12/19/97 */
@@ -173,16 +171,16 @@ planner(Query *parse)
 	 * the optimization step later.
 	 */
 
-	if (uniqueflag)
+	if (parse->uniqueFlag)
 	{
-		Plan	   *sortplan = make_sortplan(tlist, sortclause, result_plan);
+		Plan	   *sortplan = make_sortplan(tlist, parse->sortClause, result_plan);
 
-		return ((Plan *) make_unique(tlist, sortplan, uniqueflag));
+		return ((Plan *) make_unique(tlist, sortplan, parse->uniqueFlag));
 	}
 	else
 	{
-		if (sortclause)
-			return (make_sortplan(tlist, sortclause, result_plan));
+		if (parse->sortClause)
+			return (make_sortplan(tlist, parse->sortClause, result_plan));
 		else
 			return ((Plan *) result_plan);
 	}
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index 91d4f777092b1ee8d28a6037243697162edaedd3..c0386d2a126ad7b14d18bc5c56e05fde9f1b1c09 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.14 1997/12/26 06:02:26 vadim Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.15 1997/12/27 06:41:17 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -23,6 +23,7 @@
 #include "nodes/relation.h"
 
 #include "parser/parsetree.h"
+#include "parser/parse_clause.h"
 
 #include "utils/elog.h"
 #include "utils/lsyscache.h"
@@ -42,7 +43,7 @@ static Query *subst_rangetable(Query *root, Index index,
 				 RangeTblEntry *new_entry);
 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, List *unionrts, Index rt_index,
 			List *union_rt_entries, List *tlist);
 
 
@@ -136,73 +137,102 @@ plan_union_queries(Index rt_index,
 				   Query *parse,
 				   UnionFlag flag)
 {
-	List	   *rangetable = parse->rtable;
-	RangeTblEntry *rt_entry = rt_fetch(rt_index, rangetable);
-	List	   *union_relids = NIL;
 	List	   *union_plans = NIL;
-	List	   *union_rt_entries = NIL;
 
 	switch (flag)
 	{
 		case INHERITS_FLAG:
-			union_relids =
-				find_all_inheritors(lconsi(rt_entry->relid,
-										   NIL),
-									NIL);
-			/*
-			 * Remove the flag for this relation, since we're about to handle it
-			 * (do it before recursing!). XXX destructive parse tree change
-			 */
-			switch (flag)
 			{
-				case INHERITS_FLAG:
-					rt_fetch(rt_index, rangetable)->inh = false;
-					break;
-				default:
-					break;
-			}
-		
-			/*
-			 * XXX - can't find any reason to sort union-relids as paul did, so
-			 * we're leaving it out for now (maybe forever) - jeff & lp
-			 *
-			 * [maybe so. btw, jeff & lp did the lisp conversion, according to Paul.
-			 * -- ay 10/94.]
-			 */
-			union_plans = plan_union_query(union_relids, rt_index, rt_entry,
-										   parse, flag, &union_rt_entries);
-		
-			return (make_append(union_plans,
-								rt_index,
-								union_rt_entries,
-								((Plan *) lfirst(union_plans))->targetlist));
-			break;
+				List	   *rangetable = parse->rtable;
+				RangeTblEntry *rt_entry = rt_fetch(rt_index, rangetable);
+				List	   *union_rt_entries = NIL;
+				List	   *union_relids = NIL;
+	
+				union_relids =
+					find_all_inheritors(lconsi(rt_entry->relid,
+											   NIL),
+										NIL);
+				/*
+				 * Remove the flag for this relation, since we're about to handle it
+				 * (do it before recursing!). XXX destructive parse tree change
+				 */
+				switch (flag)
+				{
+					case INHERITS_FLAG:
+						rt_fetch(rt_index, rangetable)->inh = false;
+						break;
+					default:
+						break;
+				}
 			
+				/*
+				 * XXX - can't find any reason to sort union-relids as paul did, so
+				 * we're leaving it out for now (maybe forever) - jeff & lp
+				 *
+				 * [maybe so. btw, jeff & lp did the lisp conversion, according to Paul.
+				 * -- ay 10/94.]
+				 */
+				union_plans = plan_union_query(union_relids, rt_index, rt_entry,
+											   parse, flag, &union_rt_entries);
+	
+				return (make_append(union_plans,
+									NULL,
+									rt_index,
+									union_rt_entries,
+									((Plan *) lfirst(union_plans))->targetlist));
+				break;
+			}			
 		case UNION_FLAG:
 			{
-				List *ulist, *hold_union, *union_plans;
+				List *ulist, *hold_union, *union_plans, *union_rts;
 
 				hold_union = parse->unionClause;
 				parse->unionClause = NULL; /* prevent looping */
 
 				union_plans = lcons(planner(parse), NIL);
-				
+				union_rts = lcons(parse->rtable, NIL);
 				foreach(ulist, hold_union)
-					union_plans = lappend(union_plans, planner(lfirst(ulist)));
-				return (make_append(union_plans,
-									rt_index, rangetable,
+				{
+					Query *u = lfirst(ulist);
+
+					union_plans = lappend(union_plans, planner(u));
+					union_rts = lappend(union_rts, u->rtable);
+				}
+
+				/* We have already split UNION and UNION ALL */
+				if (!((Query *)lfirst(hold_union))->unionall)
+				{
+					parse->uniqueFlag = "*";
+					parse->sortClause = transformSortClause(NULL, NIL,
+						((Plan *)lfirst(union_plans))->targetlist, "*");
+				}
+				else
+				{
+				/* needed so we don't take the flag from the first query */
+					parse->uniqueFlag = NULL;
+					parse->sortClause = NIL;
+				}
+
+				parse->havingQual = NULL;
+				parse->qry_numAgg = 0;
+				parse->qry_aggs = NULL;
+
+				return (make_append(union_plans, union_rts,
+									rt_index /* is 0, none */, NULL,
 							((Plan *) lfirst(union_plans))->targetlist));
 			}
 			break;
 
+#ifdef NOT_USED
 		case VERSION_FLAG:
 			union_relids = VersionGetParents(rt_entry->relid);
 			break;
-
+#endif
 		default:
 			/* do nothing */
 			break;
 	}
+	return NULL;
 	
 	return ((Append*)NULL);		/* to make gcc happy */
 }
@@ -392,6 +422,7 @@ fix_parsetree_attnums(Index rt_index,
 
 static Append *
 make_append(List *unionplans,
+			List *unionrts,
 			Index rt_index,
 			List *union_rt_entries,
 			List *tlist)
@@ -399,6 +430,7 @@ make_append(List *unionplans,
 	Append	   *node = makeNode(Append);
 
 	node->unionplans = unionplans;
+	node->unionrts = unionrts;
 	node->unionrelid = rt_index;
 	node->unionrtentries = union_rt_entries;
 	node->plan.cost = 0.0;
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 05a1ecf3352b49ffa2f09ec1696fb4910ea6499b..edc9ae2be6b71a988f739a30f9b0f2eec5b6055a 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.56 1997/12/24 06:06:18 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.57 1997/12/27 06:41:26 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -839,16 +839,75 @@ transformSelectStmt(ParseState *pstate, RetrieveStmt *stmt)
 	if (pstate->p_numAgg > 0)
 		finalizeAggregates(pstate, qry);
 
+	qry->unionall = stmt->unionall;	/* in child, so unionClause may be false */
+	
 	if (stmt->unionClause)
 	{
 		List *ulist = NIL;
 		QueryTreeList *qlist;
-		int i;
-		
+		int i, last_union = -1;
+		bool union_all_found = false, union_found = false;
+
 		qlist = parse_analyze(stmt->unionClause);
+
+		/*
+		 *	Do we need to split up our unions because we have UNION
+		 *	and UNION ALL?
+		 */
 		for (i=0; i < qlist->len; i++)
-			ulist = lappend(ulist, qlist->qtrees[i]);
-		qry->unionClause = ulist;
+		{
+			if (qlist->qtrees[i]->unionall)
+				union_all_found = true;
+			else
+			{
+				union_found = true;
+				last_union = i;
+			}
+		}
+
+		/*	A trailing UNION negates the affect of earlier UNION ALLs */
+		if (!union_all_found ||
+			!union_found ||
+			/* last entry is a UNION */
+			!qlist->qtrees[qlist->len-1]->unionall)
+		{
+			for (i=0; i < qlist->len; i++)
+				ulist = lappend(ulist, qlist->qtrees[i]);
+			qry->unionClause = ulist;
+		}
+		else
+		{
+			List *union_list = NIL;
+			Query *hold_qry;
+
+			/*
+			 *	We have mixed unions and non-unions, so we concentrate on
+			 *	the last UNION in the list.
+			 */
+			for (i=0; i <= last_union; i++)
+			{
+				qlist->qtrees[i]->unionall = false;	/*make queries consistent*/
+				union_list = lappend(union_list, qlist->qtrees[i]);
+			}
+
+			/*
+			 *	Make the first UNION ALL after the last UNION our new
+			 *	top query
+			 */
+			hold_qry = qry;
+			qry = qlist->qtrees[last_union + 1];
+			qry->unionClause = lcons(hold_qry, NIL); /* UNION queries */
+			hold_qry->unionall = true;  /* UNION ALL this into other queries */
+			hold_qry->unionClause = union_list;
+			
+			/*
+			 *	The first UNION ALL after the last UNION is our anchor,
+			 *	we skip it.
+			 */
+			for (i=last_union + 2; i < qlist->len; i++)
+				/* all queries are UNION ALL */
+				qry->unionClause = lappend(qry->unionClause, qlist->qtrees[i]);
+		}
 	}
 	else
 	    qry->unionClause = NULL;
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index a6b9a400ea559a6f98b6e9a706dee13b6bbdc139..d288d66aa364df26bb86d8491a4188ee2c06a72b 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parsenodes.h,v 1.39 1997/12/24 06:06:53 momjian Exp $
+ * $Id: parsenodes.h,v 1.40 1997/12/27 06:41:39 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -43,7 +43,8 @@ typedef struct Query
 	char	   *into;			/* portal (cursor) name */
 	bool		isPortal;		/* is this a retrieve into portal? */
 	bool		isBinary;		/* binary portal? */
-
+	bool		unionall;		/* union without unique sort */
+	
 	char	   *uniqueFlag;		/* NULL, '*', or Unique attribute name */
 	List	   *sortClause;		/* a list of SortClause's */
 
@@ -636,7 +637,7 @@ typedef struct RetrieveStmt
 	Node	   *havingClause;	/* having conditional-expression */
 	List	   *unionClause;	/* union subselect parameters */
 	List	   *sortClause;		/* sort clause (a list of SortGroupBy's) */
-	int			unionall;		/* union without unique sort */
+	bool		unionall;		/* union without unique sort */
 } RetrieveStmt;
 
 
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index 63447c936922a6be1208b8d31d182cfcde9895a8..2dc464c2a7af104299a498bca52bc7f9ba707129 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: plannodes.h,v 1.11 1997/12/18 12:54:37 momjian Exp $
+ * $Id: plannodes.h,v 1.12 1997/12/27 06:41:41 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -119,6 +119,7 @@ typedef struct Append
 {
 	Plan		plan;
 	List	   *unionplans;
+	List	   *unionrts;
 	Index		unionrelid;
 	List	   *unionrtentries;
 	AppendState *unionstate;