From a01b085c78e11838e2058ce032425079ded6edea Mon Sep 17 00:00:00 2001
From: Bruce Momjian <bruce@momjian.us>
Date: Mon, 29 Dec 1997 01:13:37 +0000
Subject: [PATCH] Cleanup of UNION ALL fix.  Manual page updates.

---
 src/backend/optimizer/plan/planner.c   |  14 +-
 src/backend/optimizer/prep/prepunion.c | 382 +++++++++++++++----------
 src/backend/parser/analyze.c           |  75 +----
 src/backend/parser/parse_clause.c      |  28 +-
 src/bin/psql/psqlHelp.h                |   9 +-
 src/include/optimizer/prep.h           |  16 +-
 src/include/parser/parse_clause.h      |   3 +-
 src/man/select.l                       |   9 +-
 8 files changed, 277 insertions(+), 259 deletions(-)

diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 5c5e80f333..bb33f49092 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.17 1997/12/27 06:41:07 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.18 1997/12/29 01:12:45 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -76,14 +76,12 @@ planner(Query *parse)
 	Plan	   *result_plan = (Plan *) NULL;
 
 	List	   *primary_qual;
-	int			rt_index;
+	Index		rt_index;
 	
 
 	if (parse->unionClause)
 	{
-		result_plan = (Plan *) plan_union_queries(  0, /* none */
-													parse,
-													UNION_FLAG);
+		result_plan = (Plan *) plan_union_queries(parse);
 		/* XXX do we need to do this? bjm 12/19/97 */
 		tlist = preprocess_targetlist(tlist,
 									  parse->commandType,
@@ -91,11 +89,9 @@ planner(Query *parse)
 									  parse->rtable);
 	}
 	else if ((rt_index =
-				first_matching_rt_entry(rangetable, INHERITS_FLAG)) != -1)
+				first_inherit_rt_entry(rangetable)) != -1)
 	{
-		result_plan = (Plan *) plan_union_queries((Index) rt_index,
-													parse,
-													INHERITS_FLAG);
+		result_plan = (Plan *) plan_inherit_queries(parse, rt_index);
 		/* XXX do we need to do this? bjm 12/19/97 */
 		tlist = preprocess_targetlist(tlist,
 									  parse->commandType,
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index c0386d2a12..5cb89aac86 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.15 1997/12/27 06:41:17 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.16 1997/12/29 01:12:48 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -34,8 +34,8 @@
 #include "optimizer/planner.h"
 #include "optimizer/planmain.h"
 
-static List *plan_union_query(List *relids, Index rt_index,
-				 RangeTblEntry *rt_entry, Query *parse, UnionFlag flag,
+static List *plan_inherit_query(List *relids, Index rt_index,
+				 RangeTblEntry *rt_entry, Query *parse,
 				 List **union_rtentriesPtr);
 static RangeTblEntry *new_rangetable_entry(Oid new_relid,
 					 RangeTblEntry *old_entry);
@@ -48,83 +48,158 @@ static Append *make_append(List *unionplans, List *unionrts, Index rt_index,
 
 
 /*
- * find-all-inheritors -
- *		Returns a list of relids corresponding to relations that inherit
- *		attributes from any relations listed in either of the argument relid
- *		lists.
+ * plan-union-queries--
+ *
+ *	  Plans the queries for a given UNION.
+ *
+ * Returns a list containing a list of plans and a list of rangetables
  */
-List	   *
-find_all_inheritors(List *unexamined_relids,
-					List *examined_relids)
+Append	   *
+plan_union_queries(Query *parse)
 {
-	List	   *new_inheritors = NIL;
-	List	   *new_examined_relids = NIL;
-	List	   *new_unexamined_relids = NIL;
-
+	List	*union_plans = NIL, *ulist, *unionall_queries, *union_rts,
+			*last_union = NIL;
+	bool	union_all_found = false, union_found = false,
+			last_unionall_flag = false;
+	
 	/*
-	 * Find all relations which inherit from members of
-	 * 'unexamined-relids' and store them in 'new-inheritors'.
+	 *	Do we need to split up our unions because we have UNION
+	 *	and UNION ALL?
+	 *
+	 *	We are checking for the case of:
+	 *		SELECT 1
+	 *		UNION
+	 *		SELECT 2
+	 *		UNION
+	 *		SELECT 3
+	 *		UNION ALL
+	 *		SELECT 4
+	 *		UNION ALL
+	 *		SELECT 5
+	 *
+	 *	where we have to do a DISTINCT on the output of the first three
+	 *	queries, then add the rest.  If they have used UNION and
+	 *	UNION ALL, we grab all queries up to the last UNION query,
+	 *	make them their own UNION with the owner as the first query
+	 *	in the list.  Then, we take the remaining queries, which is UNION
+	 *	ALL, and add them to the list of union queries.
+	 *
+	 *	So the above query becomes:
+	 *
+	 *	Append Node
+	 *	{
+	 *		Sort and Unique
+	 *		{
+	 *			Append Node
+	 *			{
+	 *				SELECT 1				This is really a sub-UNION,
+	 *				unionClause				We run a DISTINCT on these.
+	 *				{
+	 *					SELECT 2			
+	 *					SELECT 3	 		
+	 *				}
+	 *			}
+	 *		}
+	 *		SELECT 4
+	 *		SELECT 5
+	 *	}
+	 *		
 	 */
-	List	   *rels = NIL;
-	List	   *newrels = NIL;
 
-	foreach(rels, unexamined_relids)
+	foreach(ulist, parse->unionClause)
 	{
-		newrels = (List *) LispUnioni(find_inheritance_children(lfirsti(rels)),
-									  newrels);
-	}
-	new_inheritors = newrels;
+		Query	*union_query = lfirst(ulist);
 
-	new_examined_relids = (List *) LispUnioni(examined_relids, unexamined_relids);
-	new_unexamined_relids = set_differencei(new_inheritors,
-											new_examined_relids);
+		if (union_query->unionall)
+			union_all_found = true;
+		else
+		{
+			union_found = true;
+			last_union = ulist;
+		}
+		last_unionall_flag = union_query->unionall;
+	}
 
-	if (new_unexamined_relids == NULL)
+	/* Is this a simple one */
+	if (!union_all_found ||
+		!union_found ||
+		/*	A trailing UNION negates the affect of earlier UNION ALLs */
+		!last_unionall_flag)
 	{
-		return (new_examined_relids);
+		List *hold_unionClause = parse->unionClause;
+
+		parse->unionClause = NIL;	/* prevent recursion */
+		union_plans = lcons(planner(parse), NIL);
+		union_rts = lcons(parse->rtable, NIL);
+
+		foreach(ulist, hold_unionClause)
+		{
+			Query *union_query = lfirst(ulist);
+
+			union_plans = lappend(union_plans, planner(union_query));
+			union_rts = lappend(union_rts, union_query->rtable);
+		}
 	}
 	else
 	{
-		return (find_all_inheritors(new_unexamined_relids,
-									new_examined_relids));
-	}
-}
+		/*
+		 *	We have mixed unions and non-unions
+		 *
+		 *	We need to restructure this to put the UNIONs on their own
+		 *	so we can do a DISTINCT.
+		 */
 
-/*
- * first-matching-rt-entry -
- *		Given a rangetable, find the first rangetable entry that represents
- *		the appropriate special case.
- *
- *		Returns a rangetable index.,  Returns -1 if no matches
- */
-int
-first_matching_rt_entry(List *rangetable, UnionFlag flag)
-{
-	int			count = 0;
-	List	   *temp = NIL;
+		 /* save off everthing past the last UNION */
+		unionall_queries = lnext(last_union);
 
-	foreach(temp, rangetable)
-	{
-		RangeTblEntry *rt_entry = lfirst(temp);
+		/* clip off the list to remove the trailing UNION ALLs */
+		lnext(last_union) = NIL;
+
+		/*
+		 *	Recursion, but UNION only.
+		 *	The last one is a UNION, so it will not come here in recursion,
+		 */
+		union_plans = lcons(planner(parse), NIL);
+		union_rts = lcons(parse->rtable, NIL);
 
-		switch (flag)
+		/* Append the remainging UNION ALLs */
+		foreach(ulist, unionall_queries)
 		{
-			case INHERITS_FLAG:
-				if (rt_entry->inh)
-					return count + 1;
-				break;
-			default:
-				break;
+			Query	*unionall_query = lfirst(ulist);
+
+			union_plans = lappend(union_plans, planner(unionall_query));
+			union_rts = lappend(union_rts, unionall_query->rtable);
 		}
-		count++;
 	}
+		
+	/* We have already split UNION and UNION ALL and we made it consistent */
+	if (!last_unionall_flag)
+	{
+		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 (-1);
+	return (make_append(union_plans,
+						union_rts,
+						0,
+						NULL,
+						((Plan *) lfirst(union_plans))->targetlist));
 }
 
 
 /*
- * plan-union-queries--
+ * plan-inherit-queries--
  *
  *	  Plans the queries for a given parent relation.
  *
@@ -133,122 +208,45 @@ first_matching_rt_entry(List *rangetable, UnionFlag flag)
  * XXX - what exactly does this mean, look for make_append
  */
 Append	   *
-plan_union_queries(Index rt_index,
-				   Query *parse,
-				   UnionFlag flag)
+plan_inherit_queries(Query *parse, Index rt_index)
 {
 	List	   *union_plans = NIL;
 
-	switch (flag)
-	{
-		case INHERITS_FLAG:
-			{
-				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, *union_rts;
-
-				hold_union = parse->unionClause;
-				parse->unionClause = NULL; /* prevent looping */
+	List	   *rangetable = parse->rtable;
+	RangeTblEntry *rt_entry = rt_fetch(rt_index, rangetable);
+	List	   *union_rt_entries = NIL;
+	List	   *union_relids = NIL;
 
-				union_plans = lcons(planner(parse), NIL);
-				union_rts = lcons(parse->rtable, NIL);
-				foreach(ulist, hold_union)
-				{
-					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;
+	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
+	 */
+	rt_fetch(rt_index, rangetable)->inh = false;
 
-				return (make_append(union_plans, union_rts,
-									rt_index /* is 0, none */, NULL,
-							((Plan *) lfirst(union_plans))->targetlist));
-			}
-			break;
+	union_plans = plan_inherit_query(union_relids, rt_index, rt_entry,
+								   parse, &union_rt_entries);
 
-#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 */
+	return (make_append(union_plans,
+						NULL,
+						rt_index,
+						union_rt_entries,
+						((Plan *) lfirst(union_plans))->targetlist));
 }
 
-
 /*
- * plan-union-query--
+ * plan-inherit-query--
  *	  Returns a list of plans for 'relids' and a list of range table entries
  *	  in union_rtentries.
  */
 static List *
-plan_union_query(List *relids,
+plan_inherit_query(List *relids,
 				 Index rt_index,
 				 RangeTblEntry *rt_entry,
 				 Query *root,
-				 UnionFlag flag,
 				 List **union_rtentriesPtr)
 {
 	List	   *i;
@@ -291,6 +289,74 @@ plan_union_query(List *relids,
 	return (union_plans);
 }
 
+/*
+ * find-all-inheritors -
+ *		Returns a list of relids corresponding to relations that inherit
+ *		attributes from any relations listed in either of the argument relid
+ *		lists.
+ */
+List	   *
+find_all_inheritors(List *unexamined_relids,
+					List *examined_relids)
+{
+	List	   *new_inheritors = NIL;
+	List	   *new_examined_relids = NIL;
+	List	   *new_unexamined_relids = NIL;
+
+	/*
+	 * Find all relations which inherit from members of
+	 * 'unexamined-relids' and store them in 'new-inheritors'.
+	 */
+	List	   *rels = NIL;
+	List	   *newrels = NIL;
+
+	foreach(rels, unexamined_relids)
+	{
+		newrels = (List *) LispUnioni(find_inheritance_children(lfirsti(rels)),
+									  newrels);
+	}
+	new_inheritors = newrels;
+
+	new_examined_relids = (List *) LispUnioni(examined_relids, unexamined_relids);
+	new_unexamined_relids = set_differencei(new_inheritors,
+											new_examined_relids);
+
+	if (new_unexamined_relids == NULL)
+	{
+		return (new_examined_relids);
+	}
+	else
+	{
+		return (find_all_inheritors(new_unexamined_relids,
+									new_examined_relids));
+	}
+}
+
+/*
+ * first-inherit-rt-entry -
+ *		Given a rangetable, find the first rangetable entry that represents
+ *		the appropriate special case.
+ *
+ *		Returns a rangetable index.,  Returns -1 if no matches
+ */
+int
+first_inherit_rt_entry(List *rangetable)
+{
+	int			count = 0;
+	List	   *temp = NIL;
+
+	foreach(temp, rangetable)
+	{
+		RangeTblEntry *rt_entry = lfirst(temp);
+
+		if (rt_entry->inh)
+			return count + 1;
+		count++;
+	}
+
+	return -1;
+}
+
 /*
  * new-rangetable-entry -
  *		Replaces the name and relid of 'old-entry' with the values for
@@ -367,8 +433,6 @@ fix_parsetree_attnums_nodes(Index rt_index,
 				Oid			old_typeid,
 							new_typeid;
 
-/*			old_typeid = RelationIdGetTypeId(old_relid);*/
-/*			new_typeid = RelationIdGetTypeId(new_relid);*/
 				old_typeid = old_relid;
 				new_typeid = new_relid;
 
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index edc9ae2be6..0d1d3dcb24 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.57 1997/12/27 06:41:26 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.58 1997/12/29 01:12:55 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -840,77 +840,10 @@ transformSelectStmt(ParseState *pstate, RetrieveStmt *stmt)
 		finalizeAggregates(pstate, qry);
 
 	qry->unionall = stmt->unionall;	/* in child, so unionClause may be false */
-	
-	if (stmt->unionClause)
-	{
-		List *ulist = NIL;
-		QueryTreeList *qlist;
-		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++)
-		{
-			if (qlist->qtrees[i]->unionall)
-				union_all_found = true;
-			else
-			{
-				union_found = true;
-				last_union = i;
-			}
-		}
+	qry->unionClause = transformUnionClause(stmt->unionClause, qry->targetList);
 
-		/*	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;
+	if (qry->unionClause && stmt->sortClause)
+		elog(WARN, "You can not use ORDER BY with UNION", NULL);
 
 	return (Query *) qry;
 }
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index ad40222ba6..5368dc2e26 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.3 1997/11/26 03:42:39 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.4 1997/12/29 01:12:58 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,6 +18,7 @@
 #include "postgres.h"
 #include "access/heapam.h"
 #include "catalog/pg_type.h"
+#include "parser/analyze.h"
 #include "parser/parse_clause.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_node.h"
@@ -371,3 +372,28 @@ transformSortClause(ParseState *pstate,
 
 	return sortlist;
 }
+
+/*
+ * transformUnionClause -
+ *	  transform a Union clause
+ *
+ */
+List *
+transformUnionClause(List *unionClause, List *targetlist)
+{
+	List *union_list = NIL;
+	QueryTreeList *qlist;
+	int i;
+TargetEntry
+	if (unionClause)
+	{
+		qlist = parse_analyze(unionClause);
+
+		for (i=0; i < qlist->len; i++)
+			union_list = lappend(union_list, qlist->qtrees[i]);
+		/* we need to check return types are consistent here */
+		return union_list;
+	}
+	else
+		return NIL;
+}
diff --git a/src/bin/psql/psqlHelp.h b/src/bin/psql/psqlHelp.h
index 27f820d26e..397e6979ad 100644
--- a/src/bin/psql/psqlHelp.h
+++ b/src/bin/psql/psqlHelp.h
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: psqlHelp.h,v 1.34 1997/12/04 00:27:37 scrappy Exp $
+ * $Id: psqlHelp.h,v 1.35 1997/12/29 01:13:16 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -179,7 +179,12 @@ static struct _helpStruct QL_HELP[] = {
 	"rollback [transaction|work]"},
 	{"select",
 		"retrieve tuples",
-	"select [distinct on <attr>] <expr1> [as <attr1>], ... <exprN> [as <attrN>]\n\t[into table <class_name>] [from <from_list>]\n\t[where <qual>]\n\t[order by <attr1>\n\t\t[using <op1>],..<attrN> [[using <opN>] | ASC | DESC]];"},
+	"select [distinct on <attr>] <expr1> [as <attr1>], ... <exprN> [as <attrN>]\n\
+\t[into table <class_name>]\n\
+\t[from <from_list>]\n\
+\t[where <qual>]\n\
+\t[order by <attr1> [ASC | DESC] [using <op1>], ... <attrN> ]\n\
+\t[union [all] select ...];"},
 	{"set",
 		"set run-time environment",
 	"set DateStyle to {'ISO' | 'SQL' | 'Postgres' | 'European' | 'US' | 'NonEuropean'}\nset GEQO to {'ON[=#]' | 'OFF'}\nset R_PLANS to {'ON' | 'OFF'}"},
diff --git a/src/include/optimizer/prep.h b/src/include/optimizer/prep.h
index 7b22bb5f39..91e6d18993 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.10 1997/12/24 06:06:58 momjian Exp $
+ * $Id: prep.h,v 1.11 1997/12/29 01:13:23 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -27,18 +27,10 @@ extern List *cnfify(Expr *qual, bool removeAndFlag);
 extern List *preprocess_targetlist(List *tlist, int command_type,
 					  Index result_relation, List *range_table);
 
-/*
- * prototypes for prepunion.h
- */
-typedef enum UnionFlag
-{
-	INHERITS_FLAG, UNION_FLAG, VERSION_FLAG
-} UnionFlag;
-
 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,
-				   UnionFlag flag);
+extern int	first_inherit_rt_entry(List *rangetable);
+extern Append *plan_union_queries(Query *parse);
+extern Append *plan_inherit_queries(Query *parse, Index rt_index);
 
 #endif							/* PREP_H */
diff --git a/src/include/parser/parse_clause.h b/src/include/parser/parse_clause.h
index 272bbc17b5..d402faeb11 100644
--- a/src/include/parser/parse_clause.h
+++ b/src/include/parser/parse_clause.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parse_clause.h,v 1.3 1997/11/26 03:43:09 momjian Exp $
+ * $Id: parse_clause.h,v 1.4 1997/12/29 01:13:28 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -26,6 +26,7 @@ extern List *transformGroupClause(ParseState *pstate, List *grouplist,
 extern List *transformSortClause(ParseState *pstate,
 					List *orderlist, List *targetlist,
 					char *uniqueFlag);
+extern List *transformUnionClause(List *unionClause, List *targetlist);
 
 #endif							/* PARSE_CLAUSE_H */
 
diff --git a/src/man/select.l b/src/man/select.l
index c4ac5b8eec..cc36b2b5ac 100644
--- a/src/man/select.l
+++ b/src/man/select.l
@@ -1,6 +1,6 @@
 .\" This is -*-nroff-*-
 .\" XXX standard disclaimer belongs here....
-.\" $Header: /cvsroot/pgsql/src/man/Attic/select.l,v 1.2 1996/12/11 00:28:09 momjian Exp $
+.\" $Header: /cvsroot/pgsql/src/man/Attic/select.l,v 1.3 1997/12/29 01:13:37 momjian Exp $
 .TH SELECT SQL 11/05/95 PostgreSQL PostgreSQL
 .SH NAME
 select \(em retrieve instances from a class
@@ -12,9 +12,10 @@ select \(em retrieve instances from a class
     [\fBinto\fR \fBtable\fR classname]
     [\fBfrom\fR from-list]
     [\fBwhere\fR where-clause]    
-    [\fBgroup by\fR attr_name1 {, attr_name-i....}
-    [\fBorder by\fR attr_name1
-	[\fBusing op1\fR] {, attr_namei [\fBusing opi\fR] }
+    [\fBgroup by\fR attr_name1 {, attr_name-i....}]
+    [\fBorder by\fR attr_name1 [\fBasc\fR | \fBdesc\fR] [\fBusing op1\fR] {, attr_namei...}]
+[\fBunion {all} select\fR ...]
+
 .fi
 .SH DESCRIPTION
 .BR Select
-- 
2.50.1