diff --git a/doc/src/sgml/rules.sgml b/doc/src/sgml/rules.sgml
index 493f2f05b82b36f82b9c7944565f7e08e642e21f..50bcf3a4538e928fe16ca2acecf875a4aaeeafb0 100644
--- a/doc/src/sgml/rules.sgml
+++ b/doc/src/sgml/rules.sgml
@@ -1,4 +1,4 @@
-<!-- $Header: /cvsroot/pgsql/doc/src/sgml/rules.sgml,v 1.24 2002/09/21 18:32:53 petere Exp $ -->
+<!-- $Header: /cvsroot/pgsql/doc/src/sgml/rules.sgml,v 1.25 2002/10/14 22:14:34 tgl Exp $ -->
 
 <Chapter Id="rules">
 <Title>The Rule System</Title>
@@ -189,7 +189,10 @@
         In INSERT queries the target list describes the new rows that
 	should go into the result relation. It is the expressions in the VALUES
 	clause or the ones from the SELECT clause in INSERT ... SELECT.
-	Missing columns of the result relation will be filled in by the
+	The first step of the rewrite process adds target list entries
+	for any columns that were not assigned to by the original query
+	and have defaults.  Any remaining columns (with neither a given
+	value nor a default) will be filled in by the
 	planner with a constant NULL expression.
     </Para>
 
@@ -197,7 +200,7 @@
         In UPDATE queries, the target list describes the new rows that should
 	replace the old ones. In the rule system, it contains just the
 	expressions from the SET attribute = expression part of the query.
-	The planner will add missing columns by inserting expressions that
+	The planner will handle missing columns by inserting expressions that
 	copy the values from the old row into the new one. And it will add
 	the special <acronym>CTID</> entry just as for DELETE too.
     </Para>
@@ -278,8 +281,8 @@
 
 <Para>
     Views in <ProductName>PostgreSQL</ProductName> are implemented
-    using the rule system. In fact there is absolutely no difference
-    between a
+    using the rule system. In fact there is essentially no difference
+    between
 
 <ProgramListing>
 CREATE VIEW myview AS SELECT * FROM mytab;
@@ -1133,7 +1136,7 @@ int4ne(NEW.sl_avail, OLD.sl_avail)
 <ProgramListing>
 INSERT INTO shoelace_log VALUES(
        *NEW*.sl_name, *NEW*.sl_avail,
-       current_user, current_timestamp
+       current_user, current_timestamp)
   FROM shoelace_data *NEW*, shoelace_data *OLD*;
 </ProgramListing>
 
@@ -1153,7 +1156,7 @@ INSERT INTO shoelace_log VALUES(
 <ProgramListing>
 INSERT INTO shoelace_log VALUES(
        *NEW*.sl_name, *NEW*.sl_avail,
-       current_user, current_timestamp
+       current_user, current_timestamp)
   FROM shoelace_data *NEW*, shoelace_data *OLD*,
        <emphasis>shoelace_data shoelace_data</emphasis>;
 </ProgramListing>
@@ -1164,7 +1167,7 @@ INSERT INTO shoelace_log VALUES(
 <ProgramListing>
 INSERT INTO shoelace_log VALUES(
        *NEW*.sl_name, *NEW*.sl_avail,
-       current_user, current_timestamp
+       current_user, current_timestamp)
   FROM shoelace_data *NEW*, shoelace_data *OLD*,
        shoelace_data shoelace_data
  <emphasis>WHERE int4ne(*NEW*.sl_avail, *OLD*.sl_avail)</emphasis>;
@@ -1174,7 +1177,9 @@ INSERT INTO shoelace_log VALUES(
     a WHERE clause either, but the planner and executor will have no
     difficulty with it.  They need to support this same functionality
     anyway for INSERT ... SELECT.
+   </para>
 
+   <para>
     In step 3 the original parse tree's qualification is added,
     restricting the result set further to only the rows touched
     by the original parse tree.
@@ -1182,21 +1187,21 @@ INSERT INTO shoelace_log VALUES(
 <ProgramListing>
 INSERT INTO shoelace_log VALUES(
        *NEW*.sl_name, *NEW*.sl_avail,
-       current_user, current_timestamp
+       current_user, current_timestamp)
   FROM shoelace_data *NEW*, shoelace_data *OLD*,
        shoelace_data shoelace_data
  WHERE int4ne(*NEW*.sl_avail, *OLD*.sl_avail)
    <emphasis>AND bpchareq(shoelace_data.sl_name, 'sl7')</emphasis>;
 </ProgramListing>
 
-    Step 4 substitutes NEW references by the target list entries from the
-    original parse tree or with the matching variable references
+    Step 4 replaces NEW references by the target list entries from the
+    original parse tree or by the matching variable references
     from the result relation.
 
 <ProgramListing>
 INSERT INTO shoelace_log VALUES(
        <emphasis>shoelace_data.sl_name</emphasis>, <emphasis>6</emphasis>,
-       current_user, current_timestamp
+       current_user, current_timestamp)
   FROM shoelace_data *NEW*, shoelace_data *OLD*,
        shoelace_data shoelace_data
  WHERE int4ne(<emphasis>6</emphasis>, *OLD*.sl_avail)
@@ -1208,7 +1213,7 @@ INSERT INTO shoelace_log VALUES(
 <ProgramListing>
 INSERT INTO shoelace_log VALUES(
        shoelace_data.sl_name, 6,
-       current_user, current_timestamp
+       current_user, current_timestamp)
   FROM shoelace_data *NEW*, shoelace_data *OLD*,
        shoelace_data shoelace_data
  WHERE int4ne(6, <emphasis>shoelace_data.sl_avail</emphasis>)
@@ -1222,7 +1227,7 @@ INSERT INTO shoelace_log VALUES(
 <ProgramListing>
 INSERT INTO shoelace_log VALUES(
        shoelace_data.sl_name, 6,
-       current_user, current_timestamp
+       current_user, current_timestamp)
   FROM shoelace_data
  WHERE 6 != shoelace_data.sl_avail
    AND shoelace_data.sl_name = 'sl7';
@@ -1317,18 +1322,6 @@ CREATE RULE shoe_del_protect AS ON DELETE TO shoe
     parse trees will be empty and the whole query will become
     nothing because there is nothing left to be optimized or
     executed after the rule system is done with it.
-
-    <Note>
-    <Title>Note</Title>
-    <Para>
-    This way might irritate frontend applications because
-    absolutely nothing happened on the database and thus, the
-    backend will not return anything for the query. Not
-    even a <symbol>PGRES_EMPTY_QUERY</symbol> will be available in <application>libpq</>.
-    In <application>psql</application>, nothing happens. This might change in the future.
-    </Para>
-    </Note>
-
 </Para>
 
 <Para>
@@ -1516,7 +1509,7 @@ UPDATE shoelace_data SET
 
     Again an update rule has been applied and so the wheel
     turns on and we are in rewrite round 3. This time rule
-    <literal>log_shoelace</literal> gets applied what produces the extra
+    <literal>log_shoelace</literal> gets applied, producing the extra
     parse tree
 
 <ProgramListing>
@@ -1648,7 +1641,7 @@ sl9       |       0|pink      |    35|inch    |     88.9
 sl10      |    1000|magenta   |    40|inch    |    101.6
 </ProgramListing>
 
-    For the 1000 magenta shoelaces we must debt Al before we can
+    For the 1000 magenta shoelaces we must debit Al before we can
     throw 'em away, but that's another problem. The pink entry we delete.
     To make it a little harder for <ProductName>PostgreSQL</ProductName>,
     we don't delete it directly. Instead we create one more view
@@ -1799,6 +1792,56 @@ GRANT SELECT ON phone_number TO secretary;
 </Para>
 </Sect1>
 
+<Sect1 id="rules-status">
+<Title>Rules and Command Status</Title>
+
+<Para>
+    The <ProductName>PostgreSQL</ProductName> server returns a command
+    status string, such as <literal>INSERT 149592 1</>, for each
+    query it receives.  This is simple enough when there are no rules
+    involved, but what happens when the query is rewritten by rules?
+</Para>
+
+<Para>
+    As of <ProductName>PostgreSQL</ProductName> 7.3, rules affect the
+    command status as follows:
+
+    <orderedlist>
+     <listitem>
+      <para>
+       If there is no unconditional INSTEAD rule for the query, then
+       the originally given query will be executed, and its command
+       status will be returned as usual.  (But note that if there were
+       any conditional INSTEAD rules, the negation of their qualifications
+       will have been added to the original query.  This may reduce the
+       number of rows it processes, and if so the reported status will
+       be affected.)
+      </para>
+     </listitem>
+
+     <listitem>
+      <para>
+       If there is any unconditional INSTEAD rule for the query, then
+       the original query will not be executed at all.  In this case,
+       the server will return the command status for the last query that
+       was inserted by an INSTEAD rule (conditional or unconditional)
+       and is of the same type (INSERT, UPDATE, or DELETE) as the original
+       query.  If no query meeting those requirements is added by any
+       rule, then the returned command status shows the original query
+       type and zeroes for the tuple-count and OID fields.
+      </para>
+     </listitem>
+    </orderedlist>
+</Para>
+
+<Para>
+    The programmer can ensure that any desired INSTEAD rule is the one
+    that sets the command status in the second case, by giving it the
+    alphabetically last rule name among the active rules, so that it
+    fires last.
+</Para>
+</Sect1>
+
 <Sect1 id="rules-triggers">
 <Title>Rules versus Triggers</Title>
 
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index bce849e4ec5678db9e932d8d60805d31e25ea845..5fff2f762ab56eeb21afcd196dfd572332a72578 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.213 2002/09/22 19:42:51 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.214 2002/10/14 22:14:34 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1778,6 +1778,7 @@ _copyQuery(Query *from)
 	Query	   *newnode = makeNode(Query);
 
 	newnode->commandType = from->commandType;
+	newnode->querySource = from->querySource;
 	Node_Copy(from, newnode, utilityStmt);
 	newnode->resultRelation = from->resultRelation;
 	Node_Copy(from, newnode, into);
@@ -1785,7 +1786,6 @@ _copyQuery(Query *from)
 	newnode->isBinary = from->isBinary;
 	newnode->hasAggs = from->hasAggs;
 	newnode->hasSubLinks = from->hasSubLinks;
-	newnode->originalQuery = from->originalQuery;
 
 	Node_Copy(from, newnode, rtable);
 	Node_Copy(from, newnode, jointree);
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 82d4fc6ab63ceb04287348ec786b44d477c491de..551c32d5dbaec8194a9febb777dee83c97e7a3a6 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -20,7 +20,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.160 2002/09/22 19:42:51 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.161 2002/10/14 22:14:34 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -573,6 +573,8 @@ _equalQuery(Query *a, Query *b)
 {
 	if (a->commandType != b->commandType)
 		return false;
+	if (a->querySource != b->querySource)
+		return false;
 	if (!equal(a->utilityStmt, b->utilityStmt))
 		return false;
 	if (a->resultRelation != b->resultRelation)
@@ -587,7 +589,6 @@ _equalQuery(Query *a, Query *b)
 		return false;
 	if (a->hasSubLinks != b->hasSubLinks)
 		return false;
-	/* we deliberately ignore originalQuery */
 	if (!equal(a->rtable, b->rtable))
 		return false;
 	if (!equal(a->jointree, b->jointree))
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 364aa774ada430918ce4c9ae306850fb0d764583..e1a34118a62fbce7790e374913ff26d00d73370e 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -5,7 +5,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *	$Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.175 2002/09/22 19:42:51 tgl Exp $
+ *	$Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.176 2002/10/14 22:14:34 tgl Exp $
  *
  * NOTES
  *	  Every (plan) node in POSTGRES has an associated "out" routine which
@@ -229,7 +229,8 @@ _outIndexElem(StringInfo str, IndexElem *node)
 static void
 _outQuery(StringInfo str, Query *node)
 {
-	appendStringInfo(str, " QUERY :command %d :utility ", node->commandType);
+	appendStringInfo(str, " QUERY :command %d :source %d :utility ",
+					 (int) node->commandType, (int) node->querySource);
 
 	/*
 	 * Hack to work around missing outfuncs routines for a lot of the
@@ -299,6 +300,8 @@ _outQuery(StringInfo str, Query *node)
 
 	appendStringInfo(str, " :resultRelations ");
 	_outIntList(str, node->resultRelations);
+
+	/* planner-internal fields are not written out */
 }
 
 static void
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index fc4bb97e4a78013a66d9c465502711bbf83126c4..33e28413439d32d684a0d5fe46e7fca0f5847cd0 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.134 2002/09/22 19:42:51 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.135 2002/10/14 22:14:34 tgl Exp $
  *
  * NOTES
  *	  Most of the read functions for plan nodes are tested. (In fact, they
@@ -123,6 +123,10 @@ _readQuery(void)
 	token = pg_strtok(&length); /* get commandType */
 	local_node->commandType = atoi(token);
 
+	token = pg_strtok(&length); /* skip :source */
+	token = pg_strtok(&length); /* get querySource */
+	local_node->querySource = atoi(token);
+
 	token = pg_strtok(&length); /* skip :utility */
 	local_node->utilityStmt = nodeRead(true);
 
@@ -149,9 +153,6 @@ _readQuery(void)
 	token = pg_strtok(&length); /* get hasSubLinks */
 	local_node->hasSubLinks = strtobool(token);
 
-	/* we always want originalQuery to be false in a read-in query */
-	local_node->originalQuery = false;
-
 	token = pg_strtok(&length); /* skip :rtable */
 	local_node->rtable = nodeRead(true);
 
@@ -188,6 +189,8 @@ _readQuery(void)
 	token = pg_strtok(&length); /* skip :resultRelations */
 	local_node->resultRelations = toIntList(nodeRead(true));
 
+	/* planner-internal fields are left zero */
+
 	return local_node;
 }
 
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index fe058125a04a55cd2e222a5cdcf4f9b2cf7d73f1..2dcaadc177fb25cf4b73452d41bad10736f2c88d 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *	$Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.250 2002/09/22 00:37:09 tgl Exp $
+ *	$Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.251 2002/10/14 22:14:35 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -164,13 +164,13 @@ parse_analyze(Node *parseTree, ParseState *parentParseState)
 	/*
 	 * Make sure that only the original query is marked original. We have
 	 * to do this explicitly since recursive calls of parse_analyze will
-	 * have set originalQuery in some of the added-on queries.
+	 * have marked some of the added-on queries as "original".
 	 */
 	foreach(listscan, result)
 	{
 		Query	   *q = lfirst(listscan);
 
-		q->originalQuery = (q == query);
+		q->querySource = (q == query ? QSRC_ORIGINAL : QSRC_PARSER);
 	}
 
 	pfree(pstate);
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index 0b2d839eb3f9570a21c7187f659ff1c1b896f228..180e56d9208d4bafeaf0f47f972a81e44b0cc4d5 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.110 2002/09/18 21:35:22 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.111 2002/10/14 22:14:35 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -942,6 +942,7 @@ fireRules(Query *parsetree,
 		RewriteRule *rule_lock = (RewriteRule *) lfirst(i);
 		Node	   *event_qual;
 		List	   *actions;
+		QuerySource	qsrc;
 		List	   *r;
 
 		/* multiple rule action time */
@@ -949,7 +950,18 @@ fireRules(Query *parsetree,
 		event_qual = rule_lock->qual;
 		actions = rule_lock->actions;
 
-		if (event_qual != NULL && *instead_flag)
+		/* Determine correct QuerySource value for actions */
+		if (rule_lock->isInstead)
+		{
+			if (event_qual != NULL)
+				qsrc = QSRC_QUAL_INSTEAD_RULE;
+			else
+				qsrc = QSRC_INSTEAD_RULE;
+		}
+		else
+			qsrc = QSRC_NON_INSTEAD_RULE;
+
+		if (qsrc == QSRC_QUAL_INSTEAD_RULE)
 		{
 			Query	   *qual_product;
 
@@ -976,6 +988,7 @@ fireRules(Query *parsetree,
 			*qual_products = makeList1(qual_product);
 		}
 
+		/* Now process the rule's actions and add them to the result list */
 		foreach(r, actions)
 		{
 			Query	   *rule_action = lfirst(r);
@@ -986,6 +999,8 @@ fireRules(Query *parsetree,
 			rule_action = rewriteRuleAction(parsetree, rule_action,
 											event_qual, rt_index, event);
 
+			rule_action->querySource = qsrc;
+
 			results = lappend(results, rule_action);
 		}
 
@@ -993,9 +1008,10 @@ fireRules(Query *parsetree,
 		 * If this was an unqualified instead rule, throw away an
 		 * eventually saved 'default' parsetree
 		 */
-		if (event_qual == NULL && *instead_flag)
+		if (qsrc == QSRC_INSTEAD_RULE)
 			*qual_products = NIL;
 	}
+
 	return results;
 }
 
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 1b636c18d73ae3a51af3d937f35fc5bb7124cf07..9538b34a4e9e55266fd386f8f8a8b61c2d68123b 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.301 2002/10/13 16:55:05 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.302 2002/10/14 22:14:35 tgl Exp $
  *
  * NOTES
  *	  this is the "main" module of the postgres backend and
@@ -621,6 +621,8 @@ pg_exec_query_string(StringInfo query_string,	/* string to execute */
 		Node	   *parsetree = (Node *) lfirst(parsetree_item);
 		const char *commandTag;
 		char		completionTag[COMPLETION_TAG_BUFSIZE];
+		CmdType		origCmdType;
+		bool		foundOriginalQuery = false;
 		List	   *querytree_list,
 				   *querytree_item;
 
@@ -632,6 +634,26 @@ pg_exec_query_string(StringInfo query_string,	/* string to execute */
 		 */
 		commandTag = CreateCommandTag(parsetree);
 
+		switch (nodeTag(parsetree))
+		{
+			case T_InsertStmt:
+				origCmdType = CMD_INSERT;
+				break;
+			case T_DeleteStmt:
+				origCmdType = CMD_DELETE;
+				break;
+			case T_UpdateStmt:
+				origCmdType = CMD_UPDATE;
+				break;
+			case T_SelectStmt:
+				origCmdType = CMD_SELECT;
+				break;
+			default:
+				/* Otherwise, never match commandType */
+				origCmdType = CMD_UNKNOWN;
+				break;
+		}
+
 		set_ps_display(commandTag);
 
 		BeginCommand(commandTag, dest);
@@ -694,6 +716,7 @@ pg_exec_query_string(StringInfo query_string,	/* string to execute */
 		{
 			Query	   *querytree = (Query *) lfirst(querytree_item);
 			bool		endTransactionBlock = false;
+			bool		canSetTag;
 
 			/* Make sure we are in a transaction command */
 			if (!xact_started)
@@ -708,6 +731,24 @@ pg_exec_query_string(StringInfo query_string,	/* string to execute */
 			 */
 			CHECK_FOR_INTERRUPTS();
 
+			/*
+			 * This query can set the completion tag if it is the original
+			 * query, or if it is an INSTEAD query of the same kind as the
+			 * original and we haven't yet seen the original query.
+			 */
+			if (querytree->querySource == QSRC_ORIGINAL)
+			{
+				canSetTag = true;
+				foundOriginalQuery = true;
+			}
+			else if (!foundOriginalQuery &&
+					 querytree->commandType == origCmdType &&
+					 (querytree->querySource == QSRC_INSTEAD_RULE ||
+					  querytree->querySource == QSRC_QUAL_INSTEAD_RULE))
+				canSetTag = true;
+			else
+				canSetTag = false;
+
 			if (querytree->commandType == CMD_UTILITY)
 			{
 				/*
@@ -736,7 +777,7 @@ pg_exec_query_string(StringInfo query_string,	/* string to execute */
 					IsA(utilityStmt, VariableResetStmt))
 					endTransactionBlock = true;
 
-				if (querytree->originalQuery)
+				if (canSetTag)
 				{
 					/* utility statement can override default tag string */
 					ProcessUtility(utilityStmt, dest, completionTag);
@@ -785,9 +826,9 @@ pg_exec_query_string(StringInfo query_string,	/* string to execute */
 				{
 					elog(DEBUG2, "ProcessQuery");
 
-					if (querytree->originalQuery || length(querytree_list) == 1)
+					if (canSetTag)
 					{
-						/* original stmt can override default tag string */
+						/* statement can override default tag string */
 						ProcessQuery(querytree, plan, dest, completionTag);
 						commandTag = completionTag;
 					}
@@ -853,17 +894,21 @@ pg_exec_query_string(StringInfo query_string,	/* string to execute */
 
 		/*
 		 * It is possible that the original query was removed due to a DO
-		 * INSTEAD rewrite rule.  In that case we will still have the
-		 * default completion tag, which is fine for most purposes, but it
+		 * INSTEAD rewrite rule.  If so, and if we found no INSTEAD query
+		 * matching the command type, we will still have the default
+		 * completion tag.  This is fine for most purposes, but it
 		 * may confuse clients if it's INSERT/UPDATE/DELETE. Clients
 		 * expect those tags to have counts after them (cf. ProcessQuery).
 		 */
-		if (strcmp(commandTag, "INSERT") == 0)
-			commandTag = "INSERT 0 0";
-		else if (strcmp(commandTag, "UPDATE") == 0)
-			commandTag = "UPDATE 0";
-		else if (strcmp(commandTag, "DELETE") == 0)
-			commandTag = "DELETE 0";
+		if (!foundOriginalQuery)
+		{
+			if (strcmp(commandTag, "INSERT") == 0)
+				commandTag = "INSERT 0 0";
+			else if (strcmp(commandTag, "UPDATE") == 0)
+				commandTag = "UPDATE 0";
+			else if (strcmp(commandTag, "DELETE") == 0)
+				commandTag = "DELETE 0";
+		}
 
 		/*
 		 * Tell client that we're done with this query.  Note we emit
@@ -1724,7 +1769,7 @@ PostgresMain(int argc, char *argv[], const char *username)
 	if (!IsUnderPostmaster)
 	{
 		puts("\nPOSTGRES backend interactive interface ");
-		puts("$Revision: 1.301 $ $Date: 2002/10/13 16:55:05 $\n");
+		puts("$Revision: 1.302 $ $Date: 2002/10/14 22:14:35 $\n");
 	}
 
 	/*
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 431e317c89baeb7d2985e616369748f7e91af210..967cb794f7db23cb822b2693761dd0ed6d8f1088 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: catversion.h,v 1.160 2002/09/22 19:42:51 tgl Exp $
+ * $Id: catversion.h,v 1.161 2002/10/14 22:14:35 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*							yyyymmddN */
-#define CATALOG_VERSION_NO	200209221
+#define CATALOG_VERSION_NO	200210141
 
 #endif
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index cde4acebc21a805234e2e6a2e8332b68ce5ca57e..ee0d2210134382f2ecf81034c7ab8db84c98ed9c 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parsenodes.h,v 1.208 2002/09/22 19:42:52 tgl Exp $
+ * $Id: parsenodes.h,v 1.209 2002/10/14 22:14:35 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -17,6 +17,17 @@
 #include "nodes/primnodes.h"
 
 
+/* Possible sources of a Query */
+typedef enum QuerySource
+{
+	QSRC_ORIGINAL,				/* original parsetree (explicit query) */
+	QSRC_PARSER,				/* added by parse analysis */
+	QSRC_INSTEAD_RULE,			/* added by unconditional INSTEAD rule */
+	QSRC_QUAL_INSTEAD_RULE,		/* added by conditional INSTEAD rule */
+	QSRC_NON_INSTEAD_RULE		/* added by non-INSTEAD rule */
+} QuerySource;
+
+
 /*****************************************************************************
  *	Query Tree
  *****************************************************************************/
@@ -37,6 +48,8 @@ typedef struct Query
 
 	CmdType		commandType;	/* select|insert|update|delete|utility */
 
+	QuerySource	querySource;	/* where did I come from? */
+
 	Node	   *utilityStmt;	/* non-null if this is a non-optimizable
 								 * statement */
 
@@ -49,8 +62,6 @@ typedef struct Query
 	bool		hasAggs;		/* has aggregates in tlist or havingQual */
 	bool		hasSubLinks;	/* has subquery SubLink */
 
-	bool		originalQuery;	/* marks original query through rewriting */
-
 	List	   *rtable;			/* list of range table entries */
 	FromExpr   *jointree;		/* table join tree (FROM and WHERE
 								 * clauses) */