diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index a26579270c96b5ac5d3896b98e562257677b8725..6a04417964b2139c31e68cc7e3630e6f8054c32e 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -4,7 +4,7 @@
  *
  * Copyright (c) 1994-5, Regents of the University of California
  *
- *	  $Id: explain.c,v 1.35 1999/04/25 03:19:09 tgl Exp $
+ *	  $Id: explain.c,v 1.36 1999/05/09 23:31:45 tgl Exp $
  *
  */
 #include <stdio.h>
@@ -49,15 +49,18 @@ ExplainQuery(Query *query, bool verbose, CommandDest dest)
 	List	*rewritten;
 	List	*l;
 
+	/* rewriter and planner may not work in aborted state? */
 	if (IsAbortedTransactionBlockState())
 	{
-		char	   *tag = "*ABORT STATE*";
-
-		EndCommand(tag, dest);
-
 		elog(NOTICE, "(transaction aborted): %s",
 			 "queries ignored until END");
+		return;
+	}
 
+	/* rewriter and planner will not cope with utility statements */
+	if (query->commandType == CMD_UTILITY)
+	{
+		elog(NOTICE, "Utility statements have no plan structure");
 		return;
 	}
 
@@ -67,7 +70,7 @@ ExplainQuery(Query *query, bool verbose, CommandDest dest)
 	/* In the case of an INSTEAD NOTHING, tell at least that */
 	if (rewritten == NIL)
 	{
-		elog(NOTICE, "query rewrites to nothing");
+		elog(NOTICE, "Query rewrites to nothing");
 		return;
 	}
 
@@ -88,7 +91,7 @@ ExplainOneQuery(Query *query, bool verbose, CommandDest dest)
 	Plan	   *plan;
 	ExplainState *es;
 
-	/* plan the queries (XXX we've ignored rewrite!!) */
+	/* plan the query */
 	plan = planner(query);
 
 	/* pg_plan could have failed */
@@ -195,7 +198,7 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
 			pname = "Hash";
 			break;
 		default:
-			pname = "";
+			pname = "???";
 			break;
 	}
 
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index a9ff8a0a3b18b7ab3855f088296849ceeb57b5bc..1ba1a5dd56e4a4c399ad3c40e4a82c4bc7d8abf7 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -6,7 +6,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.37 1999/02/22 05:26:46 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.38 1999/05/09 23:31:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -59,8 +59,6 @@ static void modifyAggrefChangeVarnodes(Node **nodePtr, int rt_index, int new_ind
 static void modifyAggrefDropQual(Node **nodePtr, Node *orignode, Expr *expr);
 static SubLink *modifyAggrefMakeSublink(Expr *origexp, Query *parsetree);
 static void modifyAggrefQual(Node **nodePtr, Query *parsetree);
-
-
 static Query *fireRIRrules(Query *parsetree);
 
 
@@ -2634,12 +2632,12 @@ RewritePreprocessQuery(Query *parsetree)
 
 
 /*
- * QueryRewrite -
+ * BasicQueryRewrite -
  *	  rewrite one query via query rewrite system, possibly returning 0
  *	  or many queries
  */
-List *
-QueryRewrite(Query *parsetree)
+static List *
+BasicQueryRewrite(Query *parsetree)
 {
 	List		*querylist;
 	List		*results = NIL;
@@ -2672,10 +2670,57 @@ QueryRewrite(Query *parsetree)
 	}
 	return results;
 }
-/***S*I***/
-/* This function takes two targetlists as arguments and checks if the targetlists are compatible
- * (i.e. both select for the same number of attributes and the types are compatible 
+
+/*
+ * QueryRewrite -
+ *	  Primary entry point to the query rewriter.
+ *	  Rewrite one query via query rewrite system, possibly returning 0
+ *	  or many queries.
+ *
+ * NOTE: The code in QueryRewrite was formerly in pg_parse_and_plan(), and was
+ * moved here so that it would be invoked during EXPLAIN.  The division of
+ * labor between this routine and BasicQueryRewrite is not obviously correct
+ * ... at least not to me ... tgl 5/99.
  */
+List *
+QueryRewrite(Query *parsetree)
+{
+	List	   *rewritten,
+			   *rewritten_item;
+
+	/***S*I***/
+	/* Rewrite Union, Intersect and Except Queries
+	 * to normal Union Queries using IN and NOT IN subselects */
+	if (parsetree->intersectClause)
+		parsetree = Except_Intersect_Rewrite(parsetree);
+
+	/* Rewrite basic queries (retrieve, append, delete, replace) */
+	rewritten = BasicQueryRewrite(parsetree);
+
+	/*
+	 * Rewrite the UNIONS.
+	 */
+	foreach (rewritten_item, rewritten)
+	{
+		Query	   *qry = (Query *) lfirst(rewritten_item);
+		List	   *union_result = NIL;
+		List	   *union_item;
+
+		foreach (union_item, qry->unionClause)
+		{
+			union_result = nconc(union_result,
+							BasicQueryRewrite((Query *) lfirst(union_item)));
+		}
+		qry->unionClause = union_result;
+	}
+
+	return rewritten;
+}
+
+/***S*I***/
+/* This function takes two targetlists as arguments and checks if the
+ * targetlists are compatible (i.e. both select for the same number of
+ * attributes and the types are compatible */
 void check_targetlists_are_compatible(List *prev_target, List *current_target)
 {
   List *next_target;
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index f196e51eaf0de775777151a6178bc0d8f5fadf49..24b2303ee9dbf17146615e194e02e49da13b4457 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.110 1999/05/03 19:09:54 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.111 1999/05/09 23:31:47 tgl Exp $
  *
  * NOTES
  *	  this is the "main" module of the postgres backend and
@@ -399,6 +399,49 @@ pg_parse_and_plan(char *query_string,	/* string to execute */
 	List	   *rewritten = NIL;
 	Query	   *querytree;
 
+	if (DebugPrintQuery)
+	{
+		if (DebugPrintQuery > 3)
+		{			  
+			/* Print the query string as is if query debug level > 3 */
+			TPRINTF(TRACE_QUERY, "query: %s", query_string); 
+		}
+		else
+		{
+			/* Print condensed query string to fit in one log line */
+			char		buff[MAX_QUERY_SIZE + 1];
+			char		c,
+						*s,
+						*d;
+			int			n,
+						is_space = 1;
+
+			for (s = query_string, d = buff, n = 0; (c = *s) && (n < MAX_QUERY_SIZE); s++)
+			{
+				switch (c)
+				{
+					case '\r':
+					case '\n':
+					case '\t':
+						c = ' ';
+						/* fall through */
+					case ' ':
+						if (is_space)
+							continue;
+						is_space = 1;
+						break;
+					default:
+						is_space = 0;
+						break;
+				}
+				*d++ = c;
+				n++;
+			}
+			*d = '\0';
+			TPRINTF(TRACE_QUERY, "query: %s", buff);
+		}
+	}
+
 	/* ----------------
 	 *	(1) parse the request string into a list of parse trees
 	 * ----------------
@@ -421,84 +464,30 @@ pg_parse_and_plan(char *query_string,	/* string to execute */
 
 	/* ----------------
 	 *	(2) rewrite the queries, as necessary
+	 *
+	 *  j counts queries output into new_list; the number of rewritten
+	 *  queries can be different from the original number.
 	 * ----------------
 	 */
-	j = 0;						/* counter for the new_list, new_list can
-								 * be longer than old list as a result of
-								 * rewrites */
+	j = 0;
 	for (i = 0; i < querytree_list->len; i++)
 	{
-		List	   *union_result,
-				   *union_list,
-				   *rewritten_list;
-
 		querytree = querytree_list->qtrees[i];
 
- 		/***S*I***/
- 		/* Rewrite Union, Intersect and Except Queries
- 		 * to normal Union Queries using IN and NOT IN subselects */
- 		if(querytree->intersectClause != NIL) 
- 		  {	  
- 		    querytree = Except_Intersect_Rewrite(querytree);
- 		  }
-
-		if (DebugPrintQuery)
+		if (DebugPrintParse)
 		{
-			if (DebugPrintQuery > 3)
-			{			  
-			  /* Print the query string as is if query debug level > 3 */
-			  TPRINTF(TRACE_QUERY, "query: %s", query_string); 
-			}
-			else
-			{
-				/* Print condensed query string to fit in one log line */
-				char		buff[MAX_QUERY_SIZE + 1];
-				char		c,
-						   *s,
-						   *d;
-				int			n,
-							is_space = 1;
-
-				for (s = query_string, d = buff, n = 0; (c = *s) && (n < MAX_QUERY_SIZE); s++)
-				{
-					switch (c)
-					{
-						case '\r':
-						case '\n':
-						case '\t':
-							c = ' ';
-							/* fall through */
-						case ' ':
-							if (is_space)
-								continue;
-							is_space = 1;
-							break;
-						default:
-							is_space = 0;
-							break;
-					}
-					*d++ = c;
-					n++;
-				}
-				*d = '\0';
-				TPRINTF(TRACE_QUERY, "query: %s", buff);
-			}
+			TPRINTF(TRACE_PARSE, "parser outputs:");
+			nodeDisplay(querytree);
 		}
 
-		/* don't rewrite utilites */
+		/* don't rewrite utilites, just dump 'em into new_list */
 		if (querytree->commandType == CMD_UTILITY)
 		{
 			new_list->qtrees[j++] = querytree;
 			continue;
 		}
 
-		if (DebugPrintParse)
-		{
-			TPRINTF(TRACE_PARSE, "parser outputs:");
-			nodeDisplay(querytree);
-		}
-
-		/* rewrite queries (retrieve, append, delete, replace) */
+		/* rewrite regular queries */
 		rewritten = QueryRewrite(querytree);
 
 		if (rewritten != NIL)
@@ -506,19 +495,6 @@ pg_parse_and_plan(char *query_string,	/* string to execute */
 			int			len,
 						k;
 
-			/*
-			 * Rewrite the UNIONS.
-			 */
-			foreach(rewritten_list, rewritten)
-			{
-				Query	   *qry = (Query *) lfirst(rewritten_list);
-
-				union_result = NIL;
-				foreach(union_list, qry->unionClause)
-					union_result = nconc(union_result, QueryRewrite((Query *) lfirst(union_list)));
-				qry->unionClause = union_result;
-			}
-
 			len = length(rewritten);
 			if (len == 1)
 				new_list->qtrees[j++] = (Query *) lfirst(rewritten);
@@ -530,19 +506,14 @@ pg_parse_and_plan(char *query_string,	/* string to execute */
 												 * we allocated one space
 												 * for the query */
 				new_list->qtrees = realloc(new_list->qtrees,
-										new_list->len * sizeof(Query *));
+										   new_list->len * sizeof(Query *));
 				for (k = 0; k < len; k++)
 					new_list->qtrees[j++] = (Query *) nth(k, rewritten);
 			}
 		}
 	}
 
-	/* ----------
-	 * Due to rewriting, the new list could also have been
-	 * shrunk (do instead nothing). Forget obsolete queries
-	 * at the end.
-	 * ----------
-	 */
+	/* Update new_list with correct final length */
 	new_list->len = j;
 
 	/* we're done with the original lists, free it */
@@ -657,7 +628,7 @@ pg_parse_and_plan(char *query_string,	/* string to execute */
 	}
 
 	/* ----------
-	 * Check if the rewriting had thrown away anything
+	 * Check if the rewriting had thrown away everything
 	 * ----------
 	 */
 	if (querytree_list->len == 0)
@@ -1539,7 +1510,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
 	if (!IsUnderPostmaster)
 	{
 		puts("\nPOSTGRES backend interactive interface ");
-		puts("$Revision: 1.110 $ $Date: 1999/05/03 19:09:54 $\n");
+		puts("$Revision: 1.111 $ $Date: 1999/05/09 23:31:47 $\n");
 	}
 
 	/* ----------------