diff --git a/doc/src/sgml/xfunc.sgml b/doc/src/sgml/xfunc.sgml
index 73c0287d446e2ef41a300387b6ba59a57b0a5a91..262c1e2e8c7b2b41a164018baec182f83f7e7515 100644
--- a/doc/src/sgml/xfunc.sgml
+++ b/doc/src/sgml/xfunc.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/xfunc.sgml,v 1.49 2002/03/11 05:03:52 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/xfunc.sgml,v 1.50 2002/03/21 16:00:28 tgl Exp $
 -->
 
  <chapter id="xfunc">
@@ -306,7 +306,8 @@ CREATE FUNCTION new_emp() RETURNS EMP AS '
        <para>
 	The  target  list  order must be exactly the same as
 	that in which the columns appear in the table associated
-	with the composite type.
+	with the composite type.  (Naming the columns, as we did above,
+	is irrelevant to the system.)
        </para>
       </listitem>
       <listitem>
@@ -328,28 +329,46 @@ ERROR:  function declared to return emp returns varchar instead of text at colum
      there are some unpleasant restrictions on how functions returning
      composite types can be used.  Briefly, when calling a function that
      returns a row, we cannot retrieve the entire row.  We must either
-     project a single attribute out of the row or pass the entire row into
+     extract a single attribute out of the row or pass the entire row into
      another function.  (Trying to display the entire row value will yield
      a meaningless number.)  For example,
 
 <programlisting>
-SELECT name(new_emp());
+SELECT (new_emp()).name;
 </programlisting>
 
 <screen>
  name
 ------
  None
+</screen>
+
+     We need the extra parentheses to keep the parser from getting confused:
+
+<screen>
+SELECT new_emp().name;
+ERROR:  parser: parse error at or near "."
 </screen>
     </para>
 
     <para>
-     This example makes use of the
-     function notation for projecting attributes.  The  simple  way 
-     to explain this is that we can usually use the
+     Another approach is to use
+     functional notation for extracting attributes.  The  simple  way 
+     to explain this is that we can use the
      notations <literal>attribute(table)</>  and  <literal>table.attribute</>
      interchangeably:
 
+<programlisting>
+SELECT name(new_emp());
+</programlisting>
+
+<screen>
+ name
+------
+ None
+</screen>
+    </para>
+
 <programlisting>
 --
 -- this is the same as:
@@ -367,19 +386,6 @@ SELECT name(EMP) AS youngster
 </screen>
     </para>
 
-    <para>
-	The reason why, in general, we must use the function
-        syntax  for projecting attributes of function return
-        values is that the parser  just  doesn't  understand
-        the  dot syntax for projection when combined
-        with function calls.
-
-<screen>
-SELECT new_emp().name AS nobody;
-ERROR:  parser: parse error at or near "."
-</screen>
-    </para>
-
     <para>
      Another way to use a function returning a row result is to declare a
      second function accepting a row type parameter, and pass the function
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index 2bdacbdf3b3cdc68510802d6639d2d5fc48c4212..2244827f7c4ec39f0e0ddeac0b944c00dfd89436 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.56 2002/03/06 06:09:24 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.57 2002/03/21 16:00:29 tgl Exp $
  *
  * NOTES
  *	  See acl.h.
@@ -200,7 +200,7 @@ ExecuteGrantStmt_Table(GrantStmt *stmt)
 
 	foreach(i, stmt->objects)
 	{
-		char	   *relname = strVal(lfirst(i));
+		char	   *relname = ((RangeVar *) lfirst(i))->relname;
 		Relation	relation;
 		HeapTuple	tuple;
 		Form_pg_class pg_class_tuple;
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index e7bb12807688fa0e1f407f889c05a4d777d59df5..629ffe7c2e9e05806c9f639d52245142ce0d2bdb 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.189 2002/03/20 19:43:34 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.190 2002/03/21 16:00:29 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -1728,7 +1728,7 @@ AddRelationRawConstraints(Relation rel,
 		/*
 		 * Transform raw parsetree to executable expression.
 		 */
-		expr = transformExpr(pstate, cdef->raw_expr, EXPR_COLUMN_FIRST);
+		expr = transformExpr(pstate, cdef->raw_expr);
 
 		/*
 		 * Make sure it yields a boolean result.
@@ -1863,7 +1863,7 @@ cookDefault(ParseState *pstate,
 	/*
 	 * Transform raw parsetree to executable expression.
 	 */
-	expr = transformExpr(pstate, raw_default, EXPR_COLUMN_FIRST);
+	expr = transformExpr(pstate, raw_default);
 
 	/*
 	 * Make sure default expr does not refer to any vars.
diff --git a/src/backend/commands/command.c b/src/backend/commands/command.c
index c32be8b02f397cd9f52009167f5659a7036ac4d8..5821e1d10366acc1ca49b77e12ea0abe1dc1ed5f 100644
--- a/src/backend/commands/command.c
+++ b/src/backend/commands/command.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.161 2002/03/14 22:44:50 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.162 2002/03/21 16:00:31 tgl Exp $
  *
  * NOTES
  *	  The PerformAddAttribute() code, like most of the relation
@@ -33,7 +33,7 @@
 #include "catalog/pg_type.h"
 #include "commands/command.h"
 #include "commands/trigger.h"
-#include "commands/defrem.h"	/* For add constraint unique, primary */
+#include "commands/defrem.h"
 #include "executor/execdefs.h"
 #include "executor/executor.h"
 #include "miscadmin.h"
@@ -44,7 +44,8 @@
 #include "parser/parse_expr.h"
 #include "parser/parse_oper.h"
 #include "parser/parse_relation.h"
-#include "parser/analyze.h"		/* For add constraint unique, primary */
+#include "parser/analyze.h"
+#include "tcop/utility.h"
 #include "utils/acl.h"
 #include "utils/builtins.h"
 #include "utils/fmgroids.h"
@@ -1279,8 +1280,7 @@ AlterTableAddConstraint(char *relationName,
 								 * Convert the A_EXPR in raw_expr into an
 								 * EXPR
 								 */
-								expr = transformExpr(pstate, constr->raw_expr,
-													 EXPR_COLUMN_FIRST);
+								expr = transformExpr(pstate, constr->raw_expr);
 
 								/*
 								 * Make sure it yields a boolean result.
@@ -1366,7 +1366,7 @@ AlterTableAddConstraint(char *relationName,
 					List	   *list;
 					int			count;
 
-					if (is_temp_rel_name(fkconstraint->pktable_name) &&
+					if (is_temp_rel_name(fkconstraint->pktable->relname) &&
 						!is_temp_rel_name(relationName))
 						elog(ERROR, "ALTER TABLE / ADD CONSTRAINT: Unable to reference temporary table from permanent table constraint.");
 
@@ -1375,10 +1375,10 @@ AlterTableAddConstraint(char *relationName,
 					 * someone doesn't delete rows out from under us.
 					 */
 
-					pkrel = heap_openr(fkconstraint->pktable_name, AccessExclusiveLock);
+					pkrel = heap_openr(fkconstraint->pktable->relname, AccessExclusiveLock);
 					if (pkrel->rd_rel->relkind != RELKIND_RELATION)
 						elog(ERROR, "referenced table \"%s\" not a relation",
-							 fkconstraint->pktable_name);
+							 fkconstraint->pktable->relname);
 					heap_close(pkrel, NoLock);
 
 					/*
@@ -1417,7 +1417,7 @@ AlterTableAddConstraint(char *relationName,
 					else
 						trig.tgargs[0] = "<unknown>";
 					trig.tgargs[1] = (char *) relationName;
-					trig.tgargs[2] = fkconstraint->pktable_name;
+					trig.tgargs[2] = fkconstraint->pktable->relname;
 					trig.tgargs[3] = fkconstraint->match_type;
 					count = 4;
 					foreach(list, fkconstraint->fk_attrs)
@@ -1936,9 +1936,10 @@ LockTableCommand(LockStmt *lockstmt)
 	 * at a time
 	 */
 
-	foreach(p, lockstmt->rellist)
+	foreach(p, lockstmt->relations)
 	{
-		char	   *relname = strVal(lfirst(p));
+		RangeVar   *relation = lfirst(p);
+		char	   *relname = relation->relname;
 		int			aclresult;
 		Relation	rel;
 
@@ -1962,3 +1963,94 @@ LockTableCommand(LockStmt *lockstmt)
 		relation_close(rel, NoLock);	/* close rel, keep lock */
 	}
 }
+
+
+/*
+ * CREATE SCHEMA
+ */
+void 
+CreateSchemaCommand(CreateSchemaStmt *stmt)
+{
+	const char *schemaName = stmt->schemaname;
+	const char *authId = stmt->authid;
+	List	   *parsetree_list;
+	List	   *parsetree_item;
+	const char *owner_name;
+	Oid			owner_userid;
+	Oid			saved_userid;
+
+	saved_userid = GetUserId();
+
+	if (!authId)
+	{
+		owner_userid = saved_userid;
+		owner_name = GetUserName(owner_userid);
+	}
+	else if (superuser())
+	{
+		owner_name = authId;
+		/* The following will error out if user does not exist */
+		owner_userid = get_usesysid(owner_name);
+		/*
+		 * Set the current user to the requested authorization so
+		 * that objects created in the statement have the requested
+		 * owner.  (This will revert to session user on error or at
+		 * the end of this routine.)
+		 */
+		SetUserId(owner_userid);
+	}
+	else /* not superuser */
+	{
+		owner_userid = saved_userid;
+		owner_name = GetUserName(owner_userid);
+		if (strcmp(authId, owner_name) != 0)
+			elog(ERROR, "CREATE SCHEMA: permission denied"
+				 "\n\t\"%s\" is not a superuser, so cannot create a schema for \"%s\"",
+				 owner_name, authId);
+	}
+
+	/* FIXME FENN: Create the schema here */
+	(void) schemaName;			/* suppress compiler warning for now... */
+
+	/*
+	 * Let commands in the schema-element-list know about the schema
+	 */
+	CommandCounterIncrement();
+
+	/*
+	 * Examine the list of commands embedded in the CREATE SCHEMA command,
+	 * and reorganize them into a sequentially executable order with no
+	 * forward references.  Note that the result is still a list of raw
+	 * parsetrees in need of parse analysis --- we cannot, in general,
+	 * run analyze.c on one statement until we have actually executed the
+	 * prior ones.
+	 */
+	parsetree_list = analyzeCreateSchemaStmt(stmt);
+
+	/*
+	 * Analyze and execute each command contained in the CREATE SCHEMA
+	 */
+	foreach(parsetree_item, parsetree_list)
+	{
+		Node	   *parsetree = (Node *) lfirst(parsetree_item);
+		List	   *querytree_list,
+				   *querytree_item;
+				   
+		querytree_list = parse_analyze(parsetree, NULL);
+		
+		foreach(querytree_item, querytree_list)
+		{
+			Query	   *querytree = (Query *) lfirst(querytree_item);
+			
+			/* schemas should contain only utility stmts */
+			Assert(querytree->commandType == CMD_UTILITY);
+			/* do this step */
+			ProcessUtility(querytree->utilityStmt, None, NULL);
+			/* make sure later steps can see the object created here */
+			CommandCounterIncrement();
+		}
+	}
+
+	/* Reset current user */
+	SetUserId(saved_userid);
+}
diff --git a/src/backend/commands/creatinh.c b/src/backend/commands/creatinh.c
index c9dee0cbbedb870708208f61e603d5cb5147d33d..04854a2afa1a481bb933d1564e6d4e4e36eca0d8 100644
--- a/src/backend/commands/creatinh.c
+++ b/src/backend/commands/creatinh.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.88 2002/03/20 19:43:42 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.89 2002/03/21 16:00:31 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -69,7 +69,7 @@ DefineRelation(CreateStmt *stmt, char relkind)
 	 * Truncate relname to appropriate length (probably a waste of time,
 	 * as parser should have done this already).
 	 */
-	StrNCpy(relname, stmt->relname, NAMEDATALEN);
+	StrNCpy(relname, (stmt->relation)->relname, NAMEDATALEN);
 
 	/*
 	 * Merge domain attributes into the known columns before processing table
@@ -82,8 +82,9 @@ DefineRelation(CreateStmt *stmt, char relkind)
 	 * Look up inheritance ancestors and generate relation schema,
 	 * including inherited attributes.
 	 */
-	schema = MergeAttributes(schema, stmt->inhRelnames, stmt->istemp,
-						 &inheritOids, &old_constraints, &parentHasOids);
+	schema = MergeAttributes(schema, stmt->inhRelations,
+							 stmt->relation->istemp,
+							 &inheritOids, &old_constraints, &parentHasOids);
 
 	numberOfAttributes = length(schema);
 	if (numberOfAttributes <= 0)
@@ -147,7 +148,7 @@ DefineRelation(CreateStmt *stmt, char relkind)
 	relationId = heap_create_with_catalog(relname, descriptor,
 										  relkind,
 										  stmt->hasoids || parentHasOids,
-										  stmt->istemp,
+										  stmt->relation->istemp,
 										  allowSystemTableMods);
 
 	StoreCatalogInheritance(relationId, inheritOids);
@@ -414,6 +415,8 @@ MergeAttributes(List *schema, List *supers, bool istemp,
 
 	/*
 	 * Reject duplicate names in the list of parents, too.
+	 *
+	 * XXX needs to be smarter about schema-qualified table names.
 	 */
 	foreach(entry, supers)
 	{
@@ -421,9 +424,10 @@ MergeAttributes(List *schema, List *supers, bool istemp,
 
 		foreach(rest, lnext(entry))
 		{
-			if (strcmp(strVal(lfirst(entry)), strVal(lfirst(rest))) == 0)
+			if (strcmp(((RangeVar *) lfirst(entry))->relname, 
+					   ((RangeVar *) lfirst(rest))->relname) == 0)
 				elog(ERROR, "CREATE TABLE: inherited relation \"%s\" duplicated",
-					 strVal(lfirst(entry)));
+					 ((RangeVar *) lfirst(entry))->relname);
 		}
 	}
 
@@ -435,7 +439,7 @@ MergeAttributes(List *schema, List *supers, bool istemp,
 	child_attno = 0;
 	foreach(entry, supers)
 	{
-		char	   *name = strVal(lfirst(entry));
+		char	   *name = ((RangeVar *) lfirst(entry))->relname;
 		Relation	relation;
 		TupleDesc	tupleDesc;
 		TupleConstr *constr;
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index e230ba598a00fae5a6a56d5269f2a33e9a6361c1..95263a5da08d44dd9391ed00cb7273b7af84151a 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -5,7 +5,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994-5, Regents of the University of California
  *
- * $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.71 2002/03/12 00:51:35 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.72 2002/03/21 16:00:32 tgl Exp $
  *
  */
 
@@ -310,9 +310,9 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
 
 				appendStringInfo(str, " on %s",
 								 stringStringInfo(rte->relname));
-				if (strcmp(rte->eref->relname, rte->relname) != 0)
+				if (strcmp(rte->eref->aliasname, rte->relname) != 0)
 					appendStringInfo(str, " %s",
-								   stringStringInfo(rte->eref->relname));
+								   stringStringInfo(rte->eref->aliasname));
 			}
 			break;
 		case T_SubqueryScan:
@@ -322,7 +322,7 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
 											  es->rtable);
 
 				appendStringInfo(str, " %s",
-								 stringStringInfo(rte->eref->relname));
+								 stringStringInfo(rte->eref->aliasname));
 			}
 			break;
 		default:
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0e57d90dfbcada59ffa86021ada6c00f4203259a..e9df6392bc083591565d106dd0f4c4f70f80adb4 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/sequence.c,v 1.71 2002/03/15 19:20:35 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/sequence.c,v 1.72 2002/03/21 16:00:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -123,7 +123,7 @@ DefineSequence(CreateSeqStmt *seq)
 			case SEQ_COL_NAME:
 				typnam->name = "name";
 				coldef->colname = "sequence_name";
-				namestrcpy(&name, seq->seqname);
+				namestrcpy(&name, seq->sequence->relname);
 				value[i - 1] = NameGetDatum(&name);
 				break;
 			case SEQ_COL_LASTVAL:
@@ -170,15 +170,14 @@ DefineSequence(CreateSeqStmt *seq)
 		stmt->tableElts = lappend(stmt->tableElts, coldef);
 	}
 
-	stmt->relname = seq->seqname;
-	stmt->inhRelnames = NIL;
+	stmt->relation = seq->sequence;
+	stmt->inhRelations = NIL;
 	stmt->constraints = NIL;
-	stmt->istemp = seq->istemp;
 	stmt->hasoids = false;
 
 	DefineRelation(stmt, RELKIND_SEQUENCE);
 
-	rel = heap_openr(seq->seqname, AccessExclusiveLock);
+	rel = heap_openr(seq->sequence->relname, AccessExclusiveLock);
 	tupDesc = RelationGetDescr(rel);
 
 	/* Initialize first page of relation with special magic number */
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index e25b83b4556cf4675e300b47d44b83cbf70092c0..5bef86e30610ce1f69a01242c4e5cf8c63f632cc 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.105 2002/03/08 04:37:14 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.106 2002/03/21 16:00:34 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -71,10 +71,11 @@ CreateTrigger(CreateTrigStmt *stmt)
 	char	   *constrname = "";
 	Oid			constrrelid = InvalidOid;
 
-	if (!allowSystemTableMods && IsSystemRelationName(stmt->relname))
-		elog(ERROR, "CreateTrigger: can't create trigger for system relation %s", stmt->relname);
+	if (!allowSystemTableMods && IsSystemRelationName(stmt->relation->relname))
+		elog(ERROR, "CreateTrigger: can't create trigger for system relation %s",
+			stmt->relation->relname);
 
-	if (pg_aclcheck(stmt->relname, GetUserId(),
+	if (pg_aclcheck(stmt->relation->relname, GetUserId(),
 					stmt->isconstraint ? ACL_REFERENCES : ACL_TRIGGER)
 		!= ACLCHECK_OK)
 		elog(ERROR, "permission denied");
@@ -89,7 +90,7 @@ CreateTrigger(CreateTrigStmt *stmt)
 		stmt->trigname = constrtrigname;
 		sprintf(constrtrigname, "RI_ConstraintTrigger_%u", newoid());
 
-		if (strcmp(stmt->constrrelname, "") == 0)
+		if (stmt->constrrel == NULL)
 			constrrelid = InvalidOid;
 		else
 		{
@@ -97,17 +98,17 @@ CreateTrigger(CreateTrigStmt *stmt)
 			 * NoLock is probably sufficient here, since we're only
 			 * interested in getting the relation's OID...
 			 */
-			rel = heap_openr(stmt->constrrelname, NoLock);
+			rel = heap_openr(stmt->constrrel->relname, NoLock);
 			constrrelid = rel->rd_id;
 			heap_close(rel, NoLock);
 		}
 	}
 
-	rel = heap_openr(stmt->relname, AccessExclusiveLock);
+	rel = heap_openr(stmt->relation->relname, AccessExclusiveLock);
 
 	if (rel->rd_rel->relkind != RELKIND_RELATION)
 		elog(ERROR, "CreateTrigger: relation \"%s\" is not a table",
-			 stmt->relname);
+			 stmt->relation->relname);
 
 	TRIGGER_CLEAR_TYPE(tgtype);
 	if (stmt->before)
@@ -159,7 +160,7 @@ CreateTrigger(CreateTrigStmt *stmt)
 
 		if (namestrcmp(&(pg_trigger->tgname), stmt->trigname) == 0)
 			elog(ERROR, "CreateTrigger: trigger %s already defined on relation %s",
-				 stmt->trigname, stmt->relname);
+				 stmt->trigname, stmt->relation->relname);
 		found++;
 	}
 	systable_endscan(tgscan);
@@ -283,11 +284,11 @@ CreateTrigger(CreateTrigStmt *stmt)
 	 */
 	pgrel = heap_openr(RelationRelationName, RowExclusiveLock);
 	tuple = SearchSysCacheCopy(RELNAME,
-							   PointerGetDatum(stmt->relname),
+							   PointerGetDatum(stmt->relation->relname),
 							   0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
 		elog(ERROR, "CreateTrigger: relation %s not found in pg_class",
-			 stmt->relname);
+			 stmt->relation->relname);
 
 	((Form_pg_class) GETSTRUCT(tuple))->reltriggers = found + 1;
 	simple_heap_update(pgrel, &tuple->t_self, tuple);
@@ -320,19 +321,19 @@ DropTrigger(DropTrigStmt *stmt)
 	int			found = 0;
 	int			tgfound = 0;
 
-	if (!allowSystemTableMods && IsSystemRelationName(stmt->relname))
+	if (!allowSystemTableMods && IsSystemRelationName(stmt->relation->relname))
 		elog(ERROR, "DropTrigger: can't drop trigger for system relation %s",
-			 stmt->relname);
+			 stmt->relation->relname);
 
-	if (!pg_ownercheck(GetUserId(), stmt->relname, RELNAME))
-		elog(ERROR, "%s: %s", stmt->relname,
+	if (!pg_ownercheck(GetUserId(), stmt->relation->relname, RELNAME))
+		elog(ERROR, "%s: %s", stmt->relation->relname,
 			 aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
 
-	rel = heap_openr(stmt->relname, AccessExclusiveLock);
+	rel = heap_openr(stmt->relation->relname, AccessExclusiveLock);
 
 	if (rel->rd_rel->relkind != RELKIND_RELATION)
 		elog(ERROR, "DropTrigger: relation \"%s\" is not a table",
-			 stmt->relname);
+			 stmt->relation->relname);
 
 	/*
 	 * Search pg_trigger, delete target trigger, count remaining triggers
@@ -366,10 +367,10 @@ DropTrigger(DropTrigStmt *stmt)
 
 	if (tgfound == 0)
 		elog(ERROR, "DropTrigger: there is no trigger %s on relation %s",
-			 stmt->trigname, stmt->relname);
+			 stmt->trigname, stmt->relation->relname);
 	if (tgfound > 1)
 		elog(NOTICE, "DropTrigger: found (and deleted) %d triggers %s on relation %s",
-			 tgfound, stmt->trigname, stmt->relname);
+			 tgfound, stmt->trigname, stmt->relation->relname);
 
 	/*
 	 * Update relation's pg_class entry.  Crucial side-effect: other
@@ -378,11 +379,11 @@ DropTrigger(DropTrigStmt *stmt)
 	 */
 	pgrel = heap_openr(RelationRelationName, RowExclusiveLock);
 	tuple = SearchSysCacheCopy(RELNAME,
-							   PointerGetDatum(stmt->relname),
+							   PointerGetDatum(stmt->relation->relname),
 							   0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
 		elog(ERROR, "DropTrigger: relation %s not found in pg_class",
-			 stmt->relname);
+			 stmt->relation->relname);
 
 	((Form_pg_class) GETSTRUCT(tuple))->reltriggers = found;
 	simple_heap_update(pgrel, &tuple->t_self, tuple);
@@ -478,20 +479,23 @@ RelationRemoveTriggers(Relation rel)
 	{
 		Form_pg_trigger pg_trigger;
 		Relation	refrel;
-		DropTrigStmt stmt;
+		DropTrigStmt *stmt = makeNode(DropTrigStmt);
 
 		pg_trigger = (Form_pg_trigger) GETSTRUCT(tup);
 
-		stmt.trigname = pstrdup(NameStr(pg_trigger->tgname));
+		stmt->trigname = pstrdup(NameStr(pg_trigger->tgname));
 
 		/* May as well grab AccessExclusiveLock, since DropTrigger will. */
 		refrel = heap_open(pg_trigger->tgrelid, AccessExclusiveLock);
-		stmt.relname = pstrdup(RelationGetRelationName(refrel));
+		stmt->relation = makeNode(RangeVar);
+		/* XXX bogus: what about schema? */
+		stmt->relation->relname = pstrdup(RelationGetRelationName(refrel));
 		heap_close(refrel, NoLock);
 
-		elog(NOTICE, "DROP TABLE implicitly drops referential integrity trigger from table \"%s\"", stmt.relname);
+		elog(NOTICE, "DROP TABLE implicitly drops referential integrity trigger from table \"%s\"",
+			stmt->relation->relname);
 
-		DropTrigger(&stmt);
+		DropTrigger(stmt);
 
 		/*
 		 * Need to do a command counter increment here to show up new
@@ -500,9 +504,6 @@ RelationRemoveTriggers(Relation rel)
 		 * FK table defined on the PK table).
 		 */
 		CommandCounterIncrement();
-
-		pfree(stmt.relname);
-		pfree(stmt.trigname);
 	}
 	systable_endscan(tgscan);
 
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 6b94db107772ad2a1b1d81bd6455c72f599bf5db..836091c583f45224f2834e0079ad666006e48733 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -13,7 +13,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.217 2002/03/06 06:09:38 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.218 2002/03/21 16:00:35 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -209,10 +209,10 @@ vacuum(VacuumStmt *vacstmt)
 										ALLOCSET_DEFAULT_INITSIZE,
 										ALLOCSET_DEFAULT_MAXSIZE);
 
-	/* Convert vacrel, which is just a string, to a Name */
-	if (vacstmt->vacrel)
+	/* Convert relname, which is just a string, to a Name */
+	if (vacstmt->relation)
 	{
-		namestrcpy(&VacRel, vacstmt->vacrel);
+		namestrcpy(&VacRel, vacstmt->relation->relname);
 		VacRelName = &VacRel;
 	}
 	else
@@ -268,7 +268,7 @@ vacuum(VacuumStmt *vacstmt)
 static void
 vacuum_init(VacuumStmt *vacstmt)
 {
-	if (vacstmt->vacuum && vacstmt->vacrel == NULL)
+	if (vacstmt->vacuum && vacstmt->relation == NULL)
 	{
 		/*
 		 * Compute the initially applicable OldestXmin and FreezeLimit
@@ -308,7 +308,7 @@ vacuum_shutdown(VacuumStmt *vacstmt)
 	 * row with info about the transaction IDs used, and try to truncate
 	 * pg_clog.
 	 */
-	if (vacstmt->vacuum && vacstmt->vacrel == NULL)
+	if (vacstmt->vacuum && vacstmt->relation == NULL)
 	{
 		vac_update_dbstats(MyDatabaseId,
 						   initialOldestXmin, initialFreezeLimit);
diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c
index 9d1254a4cb0bfd7373a5f57adaa5be22aac8176b..74a3ac2bcaa63cd64662595c2e19e28c683671a4 100644
--- a/src/backend/commands/view.c
+++ b/src/backend/commands/view.c
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *	$Id: view.c,v 1.58 2001/10/25 05:49:26 momjian Exp $
+ *	$Id: view.c,v 1.59 2002/03/21 16:00:36 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -41,6 +41,7 @@ static void
 DefineVirtualRelation(char *relname, List *tlist)
 {
 	CreateStmt *createStmt = makeNode(CreateStmt);
+	RangeVar   *rel = makeNode(RangeVar);
 	List	   *attrList,
 			   *t;
 
@@ -83,11 +84,13 @@ DefineVirtualRelation(char *relname, List *tlist)
 	 * now create the parameters for keys/inheritance etc. All of them are
 	 * nil...
 	 */
-	createStmt->relname = relname;
+	rel->relname = relname;
+	rel->schemaname = NULL;		/* XXX wrong */
+	rel->istemp = false;
+	createStmt->relation = rel;
 	createStmt->tableElts = attrList;
-	createStmt->inhRelnames = NIL;
+	createStmt->inhRelations = NIL;
 	createStmt->constraints = NIL;
-	createStmt->istemp = false;
 	createStmt->hasoids = false;
 
 	/*
@@ -101,21 +104,24 @@ FormViewRetrieveRule(char *viewName, Query *viewParse)
 {
 	RuleStmt   *rule;
 	char	   *rname;
-	Attr	   *attr;
+	RangeVar   *rel;
 
 	/*
 	 * Create a RuleStmt that corresponds to the suitable rewrite rule
 	 * args for DefineQueryRewrite();
 	 */
-	rule = makeNode(RuleStmt);
 	rname = MakeRetrieveViewRuleName(viewName);
 
-	attr = makeNode(Attr);
-	attr->relname = pstrdup(viewName);
+	rel = makeNode(RangeVar);
+	rel->relname = pstrdup(viewName);
+	rel->inhOpt = INH_NO;
+	rel->alias = NULL;
+
+	rule = makeNode(RuleStmt);
+	rule->relation = rel;
 	rule->rulename = pstrdup(rname);
 	rule->whereClause = NULL;
 	rule->event = CMD_SELECT;
-	rule->object = attr;
 	rule->instead = true;
 	rule->actions = makeList1(viewParse);
 
@@ -191,10 +197,10 @@ UpdateRangeTableOfViewParse(char *viewName, Query *viewParse)
 	 * table... OLD first, then NEW....
 	 */
 	rt_entry1 = addRangeTableEntry(NULL, viewName,
-								   makeAttr("*OLD*", NULL),
+								   makeAlias("*OLD*", NIL),
 								   false, false);
 	rt_entry2 = addRangeTableEntry(NULL, viewName,
-								   makeAttr("*NEW*", NULL),
+								   makeAlias("*NEW*", NIL),
 								   false, false);
 	/* Must override addRangeTableEntry's default access-check flags */
 	rt_entry1->checkForRead = false;
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 35a5c2d713871577ffaf74483384d9a922d528e6..9b8e3586024178765e8ff7621f941193d882b713 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -27,7 +27,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.152 2002/03/06 06:09:42 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.153 2002/03/21 16:00:37 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -707,7 +707,7 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
 				/*
 				 * create the "into" relation
 				 */
-				intoName = parseTree->into;
+				intoName = parseTree->into->relname;
 
 				/*
 				 * have to copy tupType to get rid of constraints
@@ -718,7 +718,7 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
 					heap_create_with_catalog(intoName,
 											 tupdesc,
 											 RELKIND_RELATION, true,
-											 parseTree->isTemp,
+											 parseTree->into->istemp,
 											 allowSystemTableMods);
 
 				FreeTupleDesc(tupdesc);
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index c8c65b1cee43039a9734c8cb07535312b454e65a..f09f90744e8fcae68cf416368dccadc3295d56af 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.67 2002/02/27 19:34:59 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.68 2002/03/21 16:00:38 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -775,7 +775,8 @@ SPI_cursor_open(char *name, void *plan, Datum *Values, char *Nulls)
 
 	/* Modify the parsetree to be a cursor */
 	queryTree->isPortal = true;
-	queryTree->into = pstrdup(name);
+	queryTree->into = makeNode(RangeVar);
+	queryTree->into->relname = pstrdup(name);
 	queryTree->isBinary = false;
 
 	/* Create the QueryDesc object and the executor state */
@@ -1145,7 +1146,7 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
 			if (parseTree->isPortal)
 			{
 				isRetrieveIntoPortal = true;
-				intoName = parseTree->into;
+				intoName = parseTree->into->relname;
 				parseTree->isBinary = false;	/* */
 
 				return SPI_ERROR_CURSOR;
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index ebdc7cf1165892dceef19391d751d470f0480302..fb68866c53ed50950e0558ce5de3db582b304f7f 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.171 2002/03/20 19:43:58 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.172 2002/03/21 16:00:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -733,18 +733,6 @@ _copyVar(Var *from)
 	return newnode;
 }
 
-static Attr *
-_copyAttr(Attr *from)
-{
-	Attr	   *newnode = makeNode(Attr);
-
-	if (from->relname)
-		newnode->relname = pstrdup(from->relname);
-	Node_Copy(from, newnode, attrs);
-
-	return newnode;
-}
-
 /* ----------------
  *		_copyOper
  * ----------------
@@ -1515,8 +1503,7 @@ _copyFkConstraint(FkConstraint *from)
 
 	if (from->constr_name)
 		newnode->constr_name = pstrdup(from->constr_name);
-	if (from->pktable_name)
-		newnode->pktable_name = pstrdup(from->pktable_name);
+	Node_Copy(from, newnode, pktable);
 	Node_Copy(from, newnode, fk_attrs);
 	Node_Copy(from, newnode, pk_attrs);
 	if (from->match_type)
@@ -1553,38 +1540,46 @@ _copyAExpr(A_Expr *from)
 	return newnode;
 }
 
-static A_Const *
-_copyAConst(A_Const *from)
+static ColumnRef *
+_copyColumnRef(ColumnRef *from)
 {
-	A_Const    *newnode = makeNode(A_Const);
+	ColumnRef	   *newnode = makeNode(ColumnRef);
 
-	newnode->val = *((Value *) (copyObject(&(from->val))));
-	Node_Copy(from, newnode, typename);
+	Node_Copy(from, newnode, fields);
+	Node_Copy(from, newnode, indirection);
 
 	return newnode;
 }
 
-static ParamNo *
-_copyParamNo(ParamNo *from)
+static ParamRef *
+_copyParamRef(ParamRef *from)
 {
-	ParamNo    *newnode = makeNode(ParamNo);
+	ParamRef    *newnode = makeNode(ParamRef);
 
 	newnode->number = from->number;
-	Node_Copy(from, newnode, typename);
+	Node_Copy(from, newnode, fields);
 	Node_Copy(from, newnode, indirection);
 
 	return newnode;
 }
 
+static A_Const *
+_copyAConst(A_Const *from)
+{
+	A_Const    *newnode = makeNode(A_Const);
+
+	newnode->val = *((Value *) (copyObject(&(from->val))));
+	Node_Copy(from, newnode, typename);
+
+	return newnode;
+}
+
 static Ident *
 _copyIdent(Ident *from)
 {
 	Ident	   *newnode = makeNode(Ident);
 
-	if (from->name)
-		newnode->name = pstrdup(from->name);
-	Node_Copy(from, newnode, indirection);
-	newnode->isRel = from->isRel;
+	newnode->name = pstrdup(from->name);
 
 	return newnode;
 }
@@ -1614,6 +1609,18 @@ _copyAIndices(A_Indices *from)
 	return newnode;
 }
 
+static ExprFieldSelect *
+_copyExprFieldSelect(ExprFieldSelect *from)
+{
+	ExprFieldSelect	   *newnode = makeNode(ExprFieldSelect);
+
+	Node_Copy(from, newnode, arg);
+	Node_Copy(from, newnode, fields);
+	Node_Copy(from, newnode, indirection);
+
+	return newnode;
+}
+
 static ResTarget *
 _copyResTarget(ResTarget *from)
 {
@@ -1654,15 +1661,32 @@ _copySortGroupBy(SortGroupBy *from)
 	return newnode;
 }
 
+static Alias *
+_copyAlias(Alias *from)
+{
+	Alias	   *newnode = makeNode(Alias);
+
+	if (from->aliasname)
+		newnode->aliasname = pstrdup(from->aliasname);
+	Node_Copy(from, newnode, colnames);
+
+	return newnode;
+}
+
 static RangeVar *
 _copyRangeVar(RangeVar *from)
 {
 	RangeVar   *newnode = makeNode(RangeVar);
 
+	if (from->catalogname)
+		newnode->catalogname = pstrdup(from->catalogname);
+	if (from->schemaname)
+		newnode->schemaname = pstrdup(from->schemaname);
 	if (from->relname)
 		newnode->relname = pstrdup(from->relname);
 	newnode->inhOpt = from->inhOpt;
-	Node_Copy(from, newnode, name);
+	newnode->istemp = from->istemp;
+	Node_Copy(from, newnode, alias);
 
 	return newnode;
 }
@@ -1673,7 +1697,7 @@ _copyRangeSubselect(RangeSubselect *from)
 	RangeSubselect *newnode = makeNode(RangeSubselect);
 
 	Node_Copy(from, newnode, subquery);
-	Node_Copy(from, newnode, name);
+	Node_Copy(from, newnode, alias);
 
 	return newnode;
 }
@@ -1756,11 +1780,9 @@ _copyQuery(Query *from)
 	newnode->commandType = from->commandType;
 	Node_Copy(from, newnode, utilityStmt);
 	newnode->resultRelation = from->resultRelation;
-	if (from->into)
-		newnode->into = pstrdup(from->into);
+	Node_Copy(from, newnode, into);
 	newnode->isPortal = from->isPortal;
 	newnode->isBinary = from->isBinary;
-	newnode->isTemp = from->isTemp;
 	newnode->hasAggs = from->hasAggs;
 	newnode->hasSubLinks = from->hasSubLinks;
 	newnode->originalQuery = from->originalQuery;
@@ -1798,8 +1820,7 @@ _copyInsertStmt(InsertStmt *from)
 {
 	InsertStmt *newnode = makeNode(InsertStmt);
 
-	if (from->relname)
-		newnode->relname = pstrdup(from->relname);
+	Node_Copy(from, newnode, relation);
 	Node_Copy(from, newnode, cols);
 	Node_Copy(from, newnode, targetList);
 	Node_Copy(from, newnode, selectStmt);
@@ -1812,10 +1833,8 @@ _copyDeleteStmt(DeleteStmt *from)
 {
 	DeleteStmt *newnode = makeNode(DeleteStmt);
 
-	if (from->relname)
-		newnode->relname = pstrdup(from->relname);
+	Node_Copy(from, newnode, relation);
 	Node_Copy(from, newnode, whereClause);
-	newnode->inhOpt = from->inhOpt;
 
 	return newnode;
 }
@@ -1825,12 +1844,10 @@ _copyUpdateStmt(UpdateStmt *from)
 {
 	UpdateStmt *newnode = makeNode(UpdateStmt);
 
-	if (from->relname)
-		newnode->relname = pstrdup(from->relname);
+	Node_Copy(from, newnode, relation);
 	Node_Copy(from, newnode, targetList);
 	Node_Copy(from, newnode, whereClause);
 	Node_Copy(from, newnode, fromClause);
-	newnode->inhOpt = from->inhOpt;
 
 	return newnode;
 }
@@ -1841,9 +1858,7 @@ _copySelectStmt(SelectStmt *from)
 	SelectStmt *newnode = makeNode(SelectStmt);
 
 	Node_Copy(from, newnode, distinctClause);
-	if (from->into)
-		newnode->into = pstrdup(from->into);
-	newnode->istemp = from->istemp;
+	Node_Copy(from, newnode, into);
 	Node_Copy(from, newnode, intoColNames);
 	Node_Copy(from, newnode, targetList);
 	Node_Copy(from, newnode, fromClause);
@@ -1885,9 +1900,7 @@ _copyAlterTableStmt(AlterTableStmt *from)
 	AlterTableStmt *newnode = makeNode(AlterTableStmt);
 
 	newnode->subtype = from->subtype;
-	if (from->relname)
-		newnode->relname = pstrdup(from->relname);
-	newnode->inhOpt = from->inhOpt;
+	Node_Copy(from, newnode, relation);
 	if (from->name)
 		newnode->name = pstrdup(from->name);
 	Node_Copy(from, newnode, def);
@@ -1951,8 +1964,7 @@ _copyClusterStmt(ClusterStmt *from)
 {
 	ClusterStmt *newnode = makeNode(ClusterStmt);
 
-	if (from->relname)
-		newnode->relname = pstrdup(from->relname);
+	Node_Copy(from, newnode, relation);
 	if (from->indexname)
 		newnode->indexname = pstrdup(from->indexname);
 
@@ -1965,8 +1977,7 @@ _copyCopyStmt(CopyStmt *from)
 	CopyStmt   *newnode = makeNode(CopyStmt);
 
 	newnode->binary = from->binary;
-	if (from->relname)
-		newnode->relname = pstrdup(from->relname);
+	Node_Copy(from, newnode, relation);
 	newnode->oids = from->oids;
 	newnode->direction = from->direction;
 	if (from->filename)
@@ -1984,11 +1995,10 @@ _copyCreateStmt(CreateStmt *from)
 {
 	CreateStmt *newnode = makeNode(CreateStmt);
 
-	newnode->relname = pstrdup(from->relname);
+	Node_Copy(from, newnode, relation);
 	Node_Copy(from, newnode, tableElts);
-	Node_Copy(from, newnode, inhRelnames);
+	Node_Copy(from, newnode, inhRelations);
 	Node_Copy(from, newnode, constraints);
-	newnode->istemp = from->istemp;
 	newnode->hasoids = from->hasoids;
 
 	return newnode;
@@ -2024,7 +2034,7 @@ _copyDropStmt(DropStmt *from)
 {
 	DropStmt   *newnode = makeNode(DropStmt);
 
-	Node_Copy(from, newnode, names);
+	Node_Copy(from, newnode, objects);
 	newnode->removeType = from->removeType;
 	newnode->behavior = from->behavior;
 
@@ -2036,7 +2046,7 @@ _copyTruncateStmt(TruncateStmt *from)
 {
 	TruncateStmt *newnode = makeNode(TruncateStmt);
 
-	newnode->relName = pstrdup(from->relName);
+	Node_Copy(from, newnode, relation);
 
 	return newnode;
 }
@@ -2047,6 +2057,8 @@ _copyCommentStmt(CommentStmt *from)
 	CommentStmt *newnode = makeNode(CommentStmt);
 
 	newnode->objtype = from->objtype;
+	if (from->objschema)
+		newnode->objschema = pstrdup(from->objschema);
 	newnode->objname = pstrdup(from->objname);
 	if (from->objproperty)
 		newnode->objproperty = pstrdup(from->objproperty);
@@ -2075,7 +2087,7 @@ _copyIndexStmt(IndexStmt *from)
 	IndexStmt  *newnode = makeNode(IndexStmt);
 
 	newnode->idxname = pstrdup(from->idxname);
-	newnode->relname = pstrdup(from->relname);
+	Node_Copy(from, newnode, relation);
 	newnode->accessMethod = pstrdup(from->accessMethod);
 	Node_Copy(from, newnode, indexParams);
 	Node_Copy(from, newnode, whereClause);
@@ -2140,8 +2152,7 @@ _copyRenameStmt(RenameStmt *from)
 {
 	RenameStmt *newnode = makeNode(RenameStmt);
 
-	newnode->relname = pstrdup(from->relname);
-	newnode->inhOpt = from->inhOpt;
+	Node_Copy(from, newnode, relation);
 	if (from->column)
 		newnode->column = pstrdup(from->column);
 	if (from->newname)
@@ -2155,10 +2166,10 @@ _copyRuleStmt(RuleStmt *from)
 {
 	RuleStmt   *newnode = makeNode(RuleStmt);
 
+	Node_Copy(from, newnode, relation);
 	newnode->rulename = pstrdup(from->rulename);
 	Node_Copy(from, newnode, whereClause);
 	newnode->event = from->event;
-	Node_Copy(from, newnode, object);
 	newnode->instead = from->instead;
 	Node_Copy(from, newnode, actions);
 
@@ -2170,8 +2181,7 @@ _copyNotifyStmt(NotifyStmt *from)
 {
 	NotifyStmt *newnode = makeNode(NotifyStmt);
 
-	if (from->relname)
-		newnode->relname = pstrdup(from->relname);
+	Node_Copy(from, newnode, relation);
 
 	return newnode;
 }
@@ -2181,8 +2191,7 @@ _copyListenStmt(ListenStmt *from)
 {
 	ListenStmt *newnode = makeNode(ListenStmt);
 
-	if (from->relname)
-		newnode->relname = pstrdup(from->relname);
+	Node_Copy(from, newnode, relation);
 
 	return newnode;
 }
@@ -2192,8 +2201,7 @@ _copyUnlistenStmt(UnlistenStmt *from)
 {
 	UnlistenStmt *newnode = makeNode(UnlistenStmt);
 
-	if (from->relname)
-		newnode->relname = pstrdup(from->relname);
+	Node_Copy(from, newnode, relation);
 
 	return newnode;
 }
@@ -2213,8 +2221,7 @@ _copyViewStmt(ViewStmt *from)
 {
 	ViewStmt   *newnode = makeNode(ViewStmt);
 
-	if (from->viewname)
-		newnode->viewname = pstrdup(from->viewname);
+	Node_Copy(from, newnode, view);
 	Node_Copy(from, newnode, aliases);
 	Node_Copy(from, newnode, query);
 
@@ -2298,8 +2305,7 @@ _copyVacuumStmt(VacuumStmt *from)
 	newnode->analyze = from->analyze;
 	newnode->freeze = from->freeze;
 	newnode->verbose = from->verbose;
-	if (from->vacrel)
-		newnode->vacrel = pstrdup(from->vacrel);
+	Node_Copy(from, newnode, relation);
 	Node_Copy(from, newnode, va_cols);
 
 	return newnode;
@@ -2322,8 +2328,7 @@ _copyCreateSeqStmt(CreateSeqStmt *from)
 {
 	CreateSeqStmt *newnode = makeNode(CreateSeqStmt);
 
-	if (from->seqname)
-		newnode->seqname = pstrdup(from->seqname);
+	Node_Copy(from, newnode, sequence);
 	Node_Copy(from, newnode, options);
 
 	return newnode;
@@ -2370,8 +2375,7 @@ _copyCreateTrigStmt(CreateTrigStmt *from)
 
 	if (from->trigname)
 		newnode->trigname = pstrdup(from->trigname);
-	if (from->relname)
-		newnode->relname = pstrdup(from->relname);
+	Node_Copy(from, newnode, relation);
 	if (from->funcname)
 		newnode->funcname = pstrdup(from->funcname);
 	Node_Copy(from, newnode, args);
@@ -2389,8 +2393,7 @@ _copyCreateTrigStmt(CreateTrigStmt *from)
 	newnode->isconstraint = from->isconstraint;
 	newnode->deferrable = from->deferrable;
 	newnode->initdeferred = from->initdeferred;
-	if (from->constrrelname)
-		newnode->constrrelname = pstrdup(from->constrrelname);
+	Node_Copy(from, newnode, constrrel);
 
 	return newnode;
 }
@@ -2402,8 +2405,7 @@ _copyDropTrigStmt(DropTrigStmt *from)
 
 	if (from->trigname)
 		newnode->trigname = pstrdup(from->trigname);
-	if (from->relname)
-		newnode->relname = pstrdup(from->relname);
+	Node_Copy(from, newnode, relation);
 
 	return newnode;
 }
@@ -2488,7 +2490,7 @@ _copyLockStmt(LockStmt *from)
 {
 	LockStmt   *newnode = makeNode(LockStmt);
 
-	Node_Copy(from, newnode, rellist);
+	Node_Copy(from, newnode, relations);
 
 	newnode->mode = from->mode;
 
@@ -2548,6 +2550,7 @@ _copyReindexStmt(ReindexStmt *from)
 	ReindexStmt *newnode = makeNode(ReindexStmt);
 
 	newnode->reindexType = from->reindexType;
+	Node_Copy(from, newnode, relation);
 	if (from->name)
 		newnode->name = pstrdup(from->name);
 	newnode->force = from->force;
@@ -2556,6 +2559,19 @@ _copyReindexStmt(ReindexStmt *from)
 	return newnode;
 }
 
+static CreateSchemaStmt *
+_copyCreateSchemaStmt(CreateSchemaStmt *from)
+{
+	CreateSchemaStmt *newnode = makeNode(CreateSchemaStmt);
+
+	newnode->schemaname = pstrdup(from->schemaname);
+	if (from->authid)
+		newnode->authid = pstrdup(from->authid);
+	Node_Copy(from, newnode, schemaElts);
+
+	return newnode;
+}
+
 
 /* ****************************************************************
  *					pg_list.h copy functions
@@ -2888,6 +2904,9 @@ copyObject(void *from)
 		case T_LoadStmt:
 			retval = _copyLoadStmt(from);
 			break;
+		case T_CreateDomainStmt:
+			retval = _copyCreateDomainStmt(from);
+			break;
 		case T_CreatedbStmt:
 			retval = _copyCreatedbStmt(from);
 			break;
@@ -2960,19 +2979,22 @@ copyObject(void *from)
 		case T_CheckPointStmt:
 			retval = (void *) makeNode(CheckPointStmt);
 			break;
+		case T_CreateSchemaStmt:
+			retval = _copyCreateSchemaStmt(from);
+			break;
 
 		case T_A_Expr:
 			retval = _copyAExpr(from);
 			break;
-		case T_Attr:
-			retval = _copyAttr(from);
+		case T_ColumnRef:
+			retval = _copyColumnRef(from);
+			break;
+		case T_ParamRef:
+			retval = _copyParamRef(from);
 			break;
 		case T_A_Const:
 			retval = _copyAConst(from);
 			break;
-		case T_ParamNo:
-			retval = _copyParamNo(from);
-			break;
 		case T_Ident:
 			retval = _copyIdent(from);
 			break;
@@ -2982,6 +3004,9 @@ copyObject(void *from)
 		case T_A_Indices:
 			retval = _copyAIndices(from);
 			break;
+		case T_ExprFieldSelect:
+			retval = _copyExprFieldSelect(from);
+			break;
 		case T_ResTarget:
 			retval = _copyResTarget(from);
 			break;
@@ -2991,6 +3016,9 @@ copyObject(void *from)
 		case T_SortGroupBy:
 			retval = _copySortGroupBy(from);
 			break;
+		case T_Alias:
+			retval = _copyAlias(from);
+			break;
 		case T_RangeVar:
 			retval = _copyRangeVar(from);
 			break;
@@ -3045,9 +3073,6 @@ copyObject(void *from)
 		case T_FuncWithArgs:
 			retval = _copyFuncWithArgs(from);
 			break;
-		case T_CreateDomainStmt:
-			retval = _copyCreateDomainStmt(from);
-			break;
 
 		default:
 			elog(ERROR, "copyObject: don't know how to copy node type %d",
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index c7ed489e091dbd6e1bcd382657ac1c980e0578bd..9788fd2f526abab37efc4b0eba2c8a281ef7fc88 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.119 2002/03/20 19:44:01 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.120 2002/03/21 16:00:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -579,14 +579,12 @@ _equalQuery(Query *a, Query *b)
 		return false;
 	if (a->resultRelation != b->resultRelation)
 		return false;
-	if (!equalstr(a->into, b->into))
+	if (!equal(a->into, b->into))
 		return false;
 	if (a->isPortal != b->isPortal)
 		return false;
 	if (a->isBinary != b->isBinary)
 		return false;
-	if (a->isTemp != b->isTemp)
-		return false;
 	if (a->hasAggs != b->hasAggs)
 		return false;
 	if (a->hasSubLinks != b->hasSubLinks)
@@ -629,7 +627,7 @@ _equalQuery(Query *a, Query *b)
 static bool
 _equalInsertStmt(InsertStmt *a, InsertStmt *b)
 {
-	if (!equalstr(a->relname, b->relname))
+	if (!equal(a->relation, b->relation))
 		return false;
 	if (!equal(a->cols, b->cols))
 		return false;
@@ -644,12 +642,10 @@ _equalInsertStmt(InsertStmt *a, InsertStmt *b)
 static bool
 _equalDeleteStmt(DeleteStmt *a, DeleteStmt *b)
 {
-	if (!equalstr(a->relname, b->relname))
+	if (!equal(a->relation, b->relation))
 		return false;
 	if (!equal(a->whereClause, b->whereClause))
 		return false;
-	if (a->inhOpt != b->inhOpt)
-		return false;
 
 	return true;
 }
@@ -657,7 +653,7 @@ _equalDeleteStmt(DeleteStmt *a, DeleteStmt *b)
 static bool
 _equalUpdateStmt(UpdateStmt *a, UpdateStmt *b)
 {
-	if (!equalstr(a->relname, b->relname))
+	if (!equal(a->relation, b->relation))
 		return false;
 	if (!equal(a->targetList, b->targetList))
 		return false;
@@ -665,8 +661,6 @@ _equalUpdateStmt(UpdateStmt *a, UpdateStmt *b)
 		return false;
 	if (!equal(a->fromClause, b->fromClause))
 		return false;
-	if (a->inhOpt != b->inhOpt)
-		return false;
 
 	return true;
 }
@@ -676,9 +670,7 @@ _equalSelectStmt(SelectStmt *a, SelectStmt *b)
 {
 	if (!equal(a->distinctClause, b->distinctClause))
 		return false;
-	if (!equalstr(a->into, b->into))
-		return false;
-	if (a->istemp != b->istemp)
+	if (!equal(a->into, b->into))
 		return false;
 	if (!equal(a->intoColNames, b->intoColNames))
 		return false;
@@ -738,9 +730,7 @@ _equalAlterTableStmt(AlterTableStmt *a, AlterTableStmt *b)
 {
 	if (a->subtype != b->subtype)
 		return false;
-	if (!equalstr(a->relname, b->relname))
-		return false;
-	if (a->inhOpt != b->inhOpt)
+	if (!equal(a->relation, b->relation))
 		return false;
 	if (!equalstr(a->name, b->name))
 		return false;
@@ -795,7 +785,7 @@ _equalClosePortalStmt(ClosePortalStmt *a, ClosePortalStmt *b)
 static bool
 _equalClusterStmt(ClusterStmt *a, ClusterStmt *b)
 {
-	if (!equalstr(a->relname, b->relname))
+	if (!equal(a->relation, b->relation))
 		return false;
 	if (!equalstr(a->indexname, b->indexname))
 		return false;
@@ -808,7 +798,7 @@ _equalCopyStmt(CopyStmt *a, CopyStmt *b)
 {
 	if (a->binary != b->binary)
 		return false;
-	if (!equalstr(a->relname, b->relname))
+	if (!equal(a->relation, b->relation))
 		return false;
 	if (a->oids != b->oids)
 		return false;
@@ -827,16 +817,14 @@ _equalCopyStmt(CopyStmt *a, CopyStmt *b)
 static bool
 _equalCreateStmt(CreateStmt *a, CreateStmt *b)
 {
-	if (!equalstr(a->relname, b->relname))
+	if (!equal(a->relation, b->relation))
 		return false;
 	if (!equal(a->tableElts, b->tableElts))
 		return false;
-	if (!equal(a->inhRelnames, b->inhRelnames))
+	if (!equal(a->inhRelations, b->inhRelations))
 		return false;
 	if (!equal(a->constraints, b->constraints))
 		return false;
-	if (a->istemp != b->istemp)
-		return false;
 	if (a->hasoids != b->hasoids)
 		return false;
 
@@ -874,7 +862,7 @@ _equalDefineStmt(DefineStmt *a, DefineStmt *b)
 static bool
 _equalDropStmt(DropStmt *a, DropStmt *b)
 {
-	if (!equal(a->names, b->names))
+	if (!equal(a->objects, b->objects))
 		return false;
 	if (a->removeType != b->removeType)
 		return false;
@@ -887,7 +875,7 @@ _equalDropStmt(DropStmt *a, DropStmt *b)
 static bool
 _equalTruncateStmt(TruncateStmt *a, TruncateStmt *b)
 {
-	if (!equalstr(a->relName, b->relName))
+	if (!equal(a->relation, b->relation))
 		return false;
 
 	return true;
@@ -900,6 +888,8 @@ _equalCommentStmt(CommentStmt *a, CommentStmt *b)
 		return false;
 	if (!equalstr(a->objname, b->objname))
 		return false;
+	if (!equalstr(a->objschema, b->objschema))
+		return false;
 	if (!equalstr(a->objproperty, b->objproperty))
 		return false;
 	if (!equal(a->objlist, b->objlist))
@@ -930,7 +920,7 @@ _equalIndexStmt(IndexStmt *a, IndexStmt *b)
 {
 	if (!equalstr(a->idxname, b->idxname))
 		return false;
-	if (!equalstr(a->relname, b->relname))
+	if (!equal(a->relation, b->relation))
 		return false;
 	if (!equalstr(a->accessMethod, b->accessMethod))
 		return false;
@@ -1006,9 +996,7 @@ _equalRemoveOperStmt(RemoveOperStmt *a, RemoveOperStmt *b)
 static bool
 _equalRenameStmt(RenameStmt *a, RenameStmt *b)
 {
-	if (!equalstr(a->relname, b->relname))
-		return false;
-	if (a->inhOpt != b->inhOpt)
+	if (!equal(a->relation, b->relation))
 		return false;
 	if (!equalstr(a->column, b->column))
 		return false;
@@ -1021,14 +1009,14 @@ _equalRenameStmt(RenameStmt *a, RenameStmt *b)
 static bool
 _equalRuleStmt(RuleStmt *a, RuleStmt *b)
 {
+	if (!equal(a->relation, b->relation))
+		return false;
 	if (!equalstr(a->rulename, b->rulename))
 		return false;
 	if (!equal(a->whereClause, b->whereClause))
 		return false;
 	if (a->event != b->event)
 		return false;
-	if (!equal(a->object, b->object))
-		return false;
 	if (a->instead != b->instead)
 		return false;
 	if (!equal(a->actions, b->actions))
@@ -1040,7 +1028,7 @@ _equalRuleStmt(RuleStmt *a, RuleStmt *b)
 static bool
 _equalNotifyStmt(NotifyStmt *a, NotifyStmt *b)
 {
-	if (!equalstr(a->relname, b->relname))
+	if (!equal(a->relation, b->relation))
 		return false;
 
 	return true;
@@ -1049,7 +1037,7 @@ _equalNotifyStmt(NotifyStmt *a, NotifyStmt *b)
 static bool
 _equalListenStmt(ListenStmt *a, ListenStmt *b)
 {
-	if (!equalstr(a->relname, b->relname))
+	if (!equal(a->relation, b->relation))
 		return false;
 
 	return true;
@@ -1058,7 +1046,7 @@ _equalListenStmt(ListenStmt *a, ListenStmt *b)
 static bool
 _equalUnlistenStmt(UnlistenStmt *a, UnlistenStmt *b)
 {
-	if (!equalstr(a->relname, b->relname))
+	if (!equal(a->relation, b->relation))
 		return false;
 
 	return true;
@@ -1076,7 +1064,7 @@ _equalTransactionStmt(TransactionStmt *a, TransactionStmt *b)
 static bool
 _equalViewStmt(ViewStmt *a, ViewStmt *b)
 {
-	if (!equalstr(a->viewname, b->viewname))
+	if (!equal(a->view, b->view))
 		return false;
 	if (!equal(a->aliases, b->aliases))
 		return false;
@@ -1160,7 +1148,7 @@ _equalVacuumStmt(VacuumStmt *a, VacuumStmt *b)
 		return false;
 	if (a->verbose != b->verbose)
 		return false;
-	if (!equalstr(a->vacrel, b->vacrel))
+	if (!equal(a->relation, b->relation))
 		return false;
 	if (!equal(a->va_cols, b->va_cols))
 		return false;
@@ -1184,7 +1172,7 @@ _equalExplainStmt(ExplainStmt *a, ExplainStmt *b)
 static bool
 _equalCreateSeqStmt(CreateSeqStmt *a, CreateSeqStmt *b)
 {
-	if (!equalstr(a->seqname, b->seqname))
+	if (!equal(a->sequence, b->sequence))
 		return false;
 	if (!equal(a->options, b->options))
 		return false;
@@ -1226,7 +1214,7 @@ _equalCreateTrigStmt(CreateTrigStmt *a, CreateTrigStmt *b)
 {
 	if (!equalstr(a->trigname, b->trigname))
 		return false;
-	if (!equalstr(a->relname, b->relname))
+	if (!equal(a->relation, b->relation))
 		return false;
 	if (!equalstr(a->funcname, b->funcname))
 		return false;
@@ -1252,7 +1240,7 @@ _equalCreateTrigStmt(CreateTrigStmt *a, CreateTrigStmt *b)
 		return false;
 	if (a->initdeferred != b->initdeferred)
 		return false;
-	if (!equalstr(a->constrrelname, b->constrrelname))
+	if (!equal(a->constrrel, b->constrrel))
 		return false;
 
 	return true;
@@ -1263,7 +1251,7 @@ _equalDropTrigStmt(DropTrigStmt *a, DropTrigStmt *b)
 {
 	if (!equalstr(a->trigname, b->trigname))
 		return false;
-	if (!equalstr(a->relname, b->relname))
+	if (!equal(a->relation, b->relation))
 		return false;
 
 	return true;
@@ -1340,7 +1328,7 @@ _equalDropUserStmt(DropUserStmt *a, DropUserStmt *b)
 static bool
 _equalLockStmt(LockStmt *a, LockStmt *b)
 {
-	if (!equal(a->rellist, b->rellist))
+	if (!equal(a->relations, b->relations))
 		return false;
 	if (a->mode != b->mode)
 		return false;
@@ -1397,6 +1385,8 @@ _equalReindexStmt(ReindexStmt *a, ReindexStmt *b)
 {
 	if (a->reindexType != b->reindexType)
 		return false;
+	if (!equal(a->relation, b->relation))
+		return false;
 	if (!equalstr(a->name, b->name))
 		return false;
 	if (a->force != b->force)
@@ -1407,6 +1397,19 @@ _equalReindexStmt(ReindexStmt *a, ReindexStmt *b)
 	return true;
 }
 
+static bool
+_equalCreateSchemaStmt(CreateSchemaStmt *a, CreateSchemaStmt *b)
+{
+	if (!equalstr(a->schemaname, b->schemaname))
+		return false;
+	if (!equalstr(a->authid, b->authid))
+		return false;
+	if (!equal(a->schemaElts, b->schemaElts))
+		return false;
+
+	return true;
+}
+
 static bool
 _equalAExpr(A_Expr *a, A_Expr *b)
 {
@@ -1423,13 +1426,9 @@ _equalAExpr(A_Expr *a, A_Expr *b)
 }
 
 static bool
-_equalAttr(Attr *a, Attr *b)
+_equalColumnRef(ColumnRef *a, ColumnRef *b)
 {
-	if (strcmp(a->relname, b->relname) != 0)
-		return false;
-	if (!equal(a->paramNo, b->paramNo))
-		return false;
-	if (!equal(a->attrs, b->attrs))
+	if (!equal(a->fields, b->fields))
 		return false;
 	if (!equal(a->indirection, b->indirection))
 		return false;
@@ -1438,25 +1437,25 @@ _equalAttr(Attr *a, Attr *b)
 }
 
 static bool
-_equalAConst(A_Const *a, A_Const *b)
+_equalParamRef(ParamRef *a, ParamRef *b)
 {
-	if (!equal(&a->val, &b->val))
+	if (a->number != b->number)
 		return false;
-	if (!equal(a->typename, b->typename))
+	if (!equal(a->fields, b->fields))
+		return false;
+	if (!equal(a->indirection, b->indirection))
 		return false;
 
 	return true;
 }
 
 static bool
-_equalParamNo(ParamNo *a, ParamNo *b)
+_equalAConst(A_Const *a, A_Const *b)
 {
-	if (a->number != b->number)
+	if (!equal(&a->val, &b->val))
 		return false;
 	if (!equal(a->typename, b->typename))
 		return false;
-	if (!equal(a->indirection, b->indirection))
-		return false;
 
 	return true;
 }
@@ -1466,10 +1465,6 @@ _equalIdent(Ident *a, Ident *b)
 {
 	if (!equalstr(a->name, b->name))
 		return false;
-	if (!equal(a->indirection, b->indirection))
-		return false;
-	if (a->isRel != b->isRel)
-		return false;
 
 	return true;
 }
@@ -1500,6 +1495,19 @@ _equalAIndices(A_Indices *a, A_Indices *b)
 	return true;
 }
 
+static bool
+_equalExprFieldSelect(ExprFieldSelect *a, ExprFieldSelect *b)
+{
+	if (!equal(a->arg, b->arg))
+		return false;
+	if (!equal(a->fields, b->fields))
+		return false;
+	if (!equal(a->indirection, b->indirection))
+		return false;
+
+	return true;
+}
+
 static bool
 _equalResTarget(ResTarget *a, ResTarget *b)
 {
@@ -1535,14 +1543,31 @@ _equalSortGroupBy(SortGroupBy *a, SortGroupBy *b)
 	return true;
 }
 
+static bool
+_equalAlias(Alias *a, Alias *b)
+{
+	if (!equalstr(a->aliasname, b->aliasname))
+		return false;
+	if (!equal(a->colnames, b->colnames))
+		return false;
+
+	return true;
+}
+
 static bool
 _equalRangeVar(RangeVar *a, RangeVar *b)
 {
+	if (!equalstr(a->catalogname, b->catalogname))
+		return false;
+	if (!equalstr(a->schemaname, b->schemaname))
+		return false;
 	if (!equalstr(a->relname, b->relname))
 		return false;
 	if (a->inhOpt != b->inhOpt)
 		return false;
-	if (!equal(a->name, b->name))
+	if (a->istemp != b->istemp)
+		return false;
+	if (!equal(a->alias, b->alias))
 		return false;
 
 	return true;
@@ -1553,7 +1578,7 @@ _equalRangeSubselect(RangeSubselect *a, RangeSubselect *b)
 {
 	if (!equal(a->subquery, b->subquery))
 		return false;
-	if (!equal(a->name, b->name))
+	if (!equal(a->alias, b->alias))
 		return false;
 
 	return true;
@@ -1704,7 +1729,7 @@ _equalFkConstraint(FkConstraint *a, FkConstraint *b)
 {
 	if (!equalstr(a->constr_name, b->constr_name))
 		return false;
-	if (!equalstr(a->pktable_name, b->pktable_name))
+	if (!equal(a->pktable, b->pktable))
 		return false;
 	if (!equal(a->fk_attrs, b->fk_attrs))
 		return false;
@@ -2111,19 +2136,22 @@ equal(void *a, void *b)
 		case T_CheckPointStmt:
 			retval = true;
 			break;
+		case T_CreateSchemaStmt:
+			retval = _equalCreateSchemaStmt(a, b);
+			break;
 
 		case T_A_Expr:
 			retval = _equalAExpr(a, b);
 			break;
-		case T_Attr:
-			retval = _equalAttr(a, b);
+		case T_ColumnRef:
+			retval = _equalColumnRef(a, b);
+			break;
+		case T_ParamRef:
+			retval = _equalParamRef(a, b);
 			break;
 		case T_A_Const:
 			retval = _equalAConst(a, b);
 			break;
-		case T_ParamNo:
-			retval = _equalParamNo(a, b);
-			break;
 		case T_Ident:
 			retval = _equalIdent(a, b);
 			break;
@@ -2133,6 +2161,9 @@ equal(void *a, void *b)
 		case T_A_Indices:
 			retval = _equalAIndices(a, b);
 			break;
+		case T_ExprFieldSelect:
+			retval = _equalExprFieldSelect(a, b);
+			break;
 		case T_ResTarget:
 			retval = _equalResTarget(a, b);
 			break;
@@ -2142,6 +2173,9 @@ equal(void *a, void *b)
 		case T_SortGroupBy:
 			retval = _equalSortGroupBy(a, b);
 			break;
+		case T_Alias:
+			retval = _equalAlias(a, b);
+			break;
 		case T_RangeVar:
 			retval = _equalRangeVar(a, b);
 			break;
diff --git a/src/backend/nodes/makefuncs.c b/src/backend/nodes/makefuncs.c
index 36f8460b46c17c81d5123bb2c5609cc04e4de869..d8bf80a52efd3eddccbb6e3965e7e76134972898 100644
--- a/src/backend/nodes/makefuncs.c
+++ b/src/backend/nodes/makefuncs.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/makefuncs.c,v 1.27 2002/03/20 19:44:04 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/makefuncs.c,v 1.28 2002/03/21 16:00:40 tgl Exp $
  */
 #include "postgres.h"
 
@@ -159,19 +159,18 @@ makeNullConst(Oid consttype)
 }
 
 /*
- * makeAttr -
- *	  creates an Attr node
+ * makeAlias -
+ *	  creates an Alias node
+ *
+ * NOTE: the given name is copied, but the colnames list (if any) isn't.
  */
-Attr *
-makeAttr(char *relname, char *attname)
+Alias *
+makeAlias(const char *aliasname, List *colnames)
 {
-	Attr	   *a = makeNode(Attr);
+	Alias	   *a = makeNode(Alias);
 
-	a->relname = pstrdup(relname);
-	a->paramNo = NULL;
-	if (attname != NULL)
-		a->attrs = makeList1(makeString(pstrdup(attname)));
-	a->indirection = NULL;
+	a->aliasname = pstrdup(aliasname);
+	a->colnames = colnames;
 
 	return a;
 }
diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
index 5d43a8e15e5e2723ffc9d2049e2381c651b02e70..401b34b88cc4cf07bbb19fe9eff9f20bc3c354c8 100644
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/nodeFuncs.c,v 1.16 2001/10/28 06:25:44 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/nodeFuncs.c,v 1.17 2002/03/21 16:00:40 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -29,7 +29,9 @@ static bool var_is_inner(Var *var);
 bool
 single_node(Node *node)
 {
-	if (IsA(node, Ident) ||IsA(node, Const) ||IsA(node, Var) ||IsA(node, Param))
+	if (IsA(node, Const) ||
+		IsA(node, Var) ||
+		IsA(node, Param))
 		return true;
 	else
 		return false;
@@ -103,13 +105,13 @@ replace_opid(Oper *oper)
  * non_null -
  *		Returns t if the node is a non-null constant, e.g., if the node has a
  *		valid `constvalue' field.
- *
  */
 bool
 non_null(Expr *c)
 {
 
-	if (IsA(c, Const) &&!((Const *) c)->constisnull)
+	if (IsA(c, Const) &&
+		!((Const *) c)->constisnull)
 		return true;
 	else
 		return false;
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 3699fc38ffb6e9e0b57d0768c5d2db88eca5f33a..aff46e6ba33aa6f7096c6b341311cd6aad0f8ed5 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -5,7 +5,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *	$Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.149 2002/03/12 00:51:39 tgl Exp $
+ *	$Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.150 2002/03/21 16:00:40 tgl Exp $
  *
  * NOTES
  *	  Every (plan) node in POSTGRES has an associated "out" routine which
@@ -105,20 +105,19 @@ _outOidList(StringInfo str, List *list)
 static void
 _outCreateStmt(StringInfo str, CreateStmt *node)
 {
-	appendStringInfo(str, " CREATE :relname ");
-	_outToken(str, node->relname);
+	appendStringInfo(str, " CREATE :relation ");
+	_outNode(str, node->relation);
 
-	appendStringInfo(str, "	:columns ");
+	appendStringInfo(str, "	:tableElts ");
 	_outNode(str, node->tableElts);
 
-	appendStringInfo(str, " :inhRelnames ");
-	_outNode(str, node->inhRelnames);
+	appendStringInfo(str, " :inhRelations ");
+	_outNode(str, node->inhRelations);
 
 	appendStringInfo(str, " :constraints ");
 	_outNode(str, node->constraints);
 
-	appendStringInfo(str, " :istemp %s :hasoids %s ",
-					 booltostr(node->istemp),
+	appendStringInfo(str, " :hasoids %s ",
 					 booltostr(node->hasoids));
 }
 
@@ -127,8 +126,8 @@ _outIndexStmt(StringInfo str, IndexStmt *node)
 {
 	appendStringInfo(str, " INDEX :idxname ");
 	_outToken(str, node->idxname);
-	appendStringInfo(str, " :relname ");
-	_outToken(str, node->relname);
+	appendStringInfo(str, " :relation ");
+	_outNode(str, node->relation);
 	appendStringInfo(str, " :accessMethod ");
 	_outToken(str, node->accessMethod);
 	appendStringInfo(str, " :indexParams ");
@@ -142,6 +141,13 @@ _outIndexStmt(StringInfo str, IndexStmt *node)
 					 booltostr(node->primary));
 }
 
+static void
+_outNotifyStmt(StringInfo str, NotifyStmt *node)
+{
+	appendStringInfo(str, "NOTIFY :relation ");
+	_outNode(str, node->relation);
+}
+
 static void
 _outSelectStmt(StringInfo str, SelectStmt *node)
 {
@@ -213,53 +219,40 @@ _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 ", node->commandType);
-
+	/*
+	 * Hack to work around missing outfuncs routines for a lot of the
+	 * utility-statement node types.  (The only one we actually *need*
+	 * for rules support is NotifyStmt.)  Someday we ought to support
+	 * 'em all, but for the meantime do this to avoid getting lots of
+	 * warnings when running with debug_print_parse on.
+	 */
 	if (node->utilityStmt)
 	{
-		/*
-		 * Hack to make up for lack of outfuncs for utility-stmt nodes
-		 */
 		switch (nodeTag(node->utilityStmt))
 		{
 			case T_CreateStmt:
-				appendStringInfo(str, " :create ");
-				_outToken(str, ((CreateStmt *) (node->utilityStmt))->relname);
-				appendStringInfo(str, " ");
-				_outNode(str, node->utilityStmt);
-				break;
-
 			case T_IndexStmt:
-				appendStringInfo(str, " :index ");
-				_outToken(str, ((IndexStmt *) (node->utilityStmt))->idxname);
-				appendStringInfo(str, " on ");
-				_outToken(str, ((IndexStmt *) (node->utilityStmt))->relname);
-				appendStringInfo(str, " ");
-				_outNode(str, node->utilityStmt);
-				break;
-
 			case T_NotifyStmt:
-				appendStringInfo(str, " :notify ");
-				_outToken(str, ((NotifyStmt *) (node->utilityStmt))->relname);
+				_outNode(str, node->utilityStmt);
 				break;
-
 			default:
-				appendStringInfo(str, " :utility ? ");
+				appendStringInfo(str, "?");
+				break;
 		}
 	}
 	else
-		appendStringInfo(str, " :utility <>");
+		appendStringInfo(str, "<>");
 
 	appendStringInfo(str, " :resultRelation %d :into ",
 					 node->resultRelation);
-	_outToken(str, node->into);
+	_outNode(str, node->into);
 
-	appendStringInfo(str, " :isPortal %s :isBinary %s :isTemp %s"
+	appendStringInfo(str, " :isPortal %s :isBinary %s"
 					 " :hasAggs %s :hasSubLinks %s :rtable ",
 					 booltostr(node->isPortal),
 					 booltostr(node->isBinary),
-					 booltostr(node->isTemp),
 					 booltostr(node->hasAggs),
 					 booltostr(node->hasSubLinks));
 	_outNode(str, node->rtable);
@@ -963,6 +956,15 @@ _outTargetEntry(StringInfo str, TargetEntry *node)
 	_outNode(str, node->expr);
 }
 
+static void
+_outAlias(StringInfo str, Alias *node)
+{
+	appendStringInfo(str, " ALIAS :aliasname ");
+	_outToken(str, node->aliasname);
+	appendStringInfo(str, " :colnames ");
+	_outNode(str, node->colnames);
+}
+
 static void
 _outRangeTblEntry(StringInfo str, RangeTblEntry *node)
 {
@@ -1312,19 +1314,46 @@ _outValue(StringInfo str, Value *value)
 }
 
 static void
-_outIdent(StringInfo str, Ident *node)
+_outRangeVar(StringInfo str, RangeVar *node)
 {
-	appendStringInfo(str, " IDENT ");
-	_outToken(str, node->name);
+	appendStringInfo(str, " RANGEVAR :relation ");
+	/*
+	 * we deliberately ignore catalogname here, since it is presently not
+	 * semantically meaningful
+	 */
+	_outToken(str, node->schemaname);
+	appendStringInfo(str, " . ");
+	_outToken(str, node->relname);
+	appendStringInfo(str, " :inhopt %d :istemp %s",
+					(int) node->inhOpt,
+					booltostr(node->istemp));
+	appendStringInfo(str, " :alias ");
+	_outNode(str, node->alias);
 }
 
 static void
-_outAttr(StringInfo str, Attr *node)
+_outColumnRef(StringInfo str, ColumnRef *node)
 {
-	appendStringInfo(str, " ATTR :relname ");
-	_outToken(str, node->relname);
-	appendStringInfo(str, " :attrs ");
-	_outNode(str, node->attrs);
+	appendStringInfo(str, " COLUMNREF :fields ");
+	_outNode(str, node->fields);
+	appendStringInfo(str, " :indirection ");
+	_outNode(str, node->indirection);
+}
+
+static void
+_outParamRef(StringInfo str, ParamRef *node)
+{
+	appendStringInfo(str, " PARAMREF :number %d :fields ", node->number);
+	_outNode(str, node->fields);
+	appendStringInfo(str, " :indirection ");
+	_outNode(str, node->indirection);
+}
+
+static void
+_outIdent(StringInfo str, Ident *node)
+{
+	appendStringInfo(str, " IDENT ");
+	_outToken(str, node->name);
 }
 
 static void
@@ -1336,6 +1365,17 @@ _outAConst(StringInfo str, A_Const *node)
 	_outNode(str, node->typename);
 }
 
+static void
+_outExprFieldSelect(StringInfo str, ExprFieldSelect *node)
+{
+	appendStringInfo(str, " EXPRFIELDSELECT :arg ");
+	_outNode(str, node->arg);
+	appendStringInfo(str, " :fields ");
+	_outNode(str, node->fields);
+	appendStringInfo(str, " :indirection ");
+	_outNode(str, node->indirection);
+}
+
 static void
 _outConstraint(StringInfo str, Constraint *node)
 {
@@ -1384,8 +1424,8 @@ _outFkConstraint(StringInfo str, FkConstraint *node)
 {
 	appendStringInfo(str, " FKCONSTRAINT :constr_name ");
 	_outToken(str, node->constr_name);
-	appendStringInfo(str, " :pktable_name ");
-	_outToken(str, node->pktable_name);
+	appendStringInfo(str, " :pktable ");
+	_outNode(str, node->pktable);
 	appendStringInfo(str, " :fk_attrs ");
 	_outNode(str, node->fk_attrs);
 	appendStringInfo(str, " :pk_attrs ");
@@ -1490,6 +1530,12 @@ _outNode(StringInfo str, void *obj)
 			case T_IndexStmt:
 				_outIndexStmt(str, obj);
 				break;
+			case T_NotifyStmt:
+				_outNotifyStmt(str, obj);
+				break;
+			case T_SelectStmt:
+				_outSelectStmt(str, obj);
+				break;
 			case T_ColumnDef:
 				_outColumnDef(str, obj);
 				break;
@@ -1628,6 +1674,9 @@ _outNode(StringInfo str, void *obj)
 			case T_TargetEntry:
 				_outTargetEntry(str, obj);
 				break;
+			case T_Alias:
+				_outAlias(str, obj);
+				break;
 			case T_RangeTblEntry:
 				_outRangeTblEntry(str, obj);
 				break;
@@ -1670,12 +1719,24 @@ _outNode(StringInfo str, void *obj)
 			case T_A_Expr:
 				_outAExpr(str, obj);
 				break;
+			case T_RangeVar:
+				_outRangeVar(str, obj);
+				break;
+			case T_ColumnRef:
+				_outColumnRef(str, obj);
+				break;
+			case T_ParamRef:
+				_outParamRef(str, obj);
+				break;
 			case T_Ident:
 				_outIdent(str, obj);
 				break;
 			case T_A_Const:
 				_outAConst(str, obj);
 				break;
+			case T_ExprFieldSelect:
+				_outExprFieldSelect(str, obj);
+				break;
 			case T_Constraint:
 				_outConstraint(str, obj);
 				break;
@@ -1694,17 +1755,9 @@ _outNode(StringInfo str, void *obj)
 			case T_BooleanTest:
 				_outBooleanTest(str, obj);
 				break;
-			case T_VariableSetStmt:
-				break;
-			case T_SelectStmt:
-				_outSelectStmt(str, obj);
-				break;
 			case T_FuncCall:
 				_outFuncCall(str, obj);
 				break;
-			case T_Attr:
-				_outAttr(str, obj);
-				break;
 
 			default:
 				elog(WARNING, "_outNode: don't know how to print type %d ",
diff --git a/src/backend/nodes/print.c b/src/backend/nodes/print.c
index 0d929941020b00c5fad25d3e7a7e773009708c3b..ebc5d536e7d2ff917af3a5eecd4aa31c792c8a14 100644
--- a/src/backend/nodes/print.c
+++ b/src/backend/nodes/print.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.51 2001/12/20 02:39:26 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.52 2002/03/21 16:00:41 tgl Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -154,10 +154,10 @@ print_rt(List *rtable)
 
 		if (rte->relname)
 			printf("%d\t%s (%s)\t%u",
-				   i, rte->relname, rte->eref->relname, rte->relid);
+				   i, rte->relname, rte->eref->aliasname, rte->relid);
 		else
 			printf("%d\t[subquery] (%s)\t",
-				   i, rte->eref->relname);
+				   i, rte->eref->aliasname);
 		printf("\t%s\t%s\n",
 			   (rte->inh ? "inh" : ""),
 			   (rte->inFromCl ? "inFromCl" : ""));
@@ -202,7 +202,7 @@ print_expr(Node *expr, List *rtable)
 					Assert(var->varno > 0 &&
 						   (int) var->varno <= length(rtable));
 					rte = rt_fetch(var->varno, rtable);
-					relname = rte->eref->relname;
+					relname = rte->eref->aliasname;
 					attname = get_rte_attribute_name(rte, var->varattno);
 				}
 				break;
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index c0794123b3e54552172481f644437390424df788..66dd317f394f892418b88cdb64320fd6d802b78b 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.116 2002/03/12 00:51:39 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.117 2002/03/21 16:00:42 tgl Exp $
  *
  * NOTES
  *	  Most of the read functions for plan nodes are tested. (In fact, they
@@ -119,34 +119,19 @@ _readQuery(void)
 
 	local_node = makeNode(Query);
 
-	token = pg_strtok(&length); /* skip the :command */
-	token = pg_strtok(&length); /* get the commandType */
+	token = pg_strtok(&length); /* skip :command */
+	token = pg_strtok(&length); /* get commandType */
 	local_node->commandType = atoi(token);
 
 	token = pg_strtok(&length); /* skip :utility */
-	token = pg_strtok(&length);
-	if (length == 0)
-		local_node->utilityStmt = NULL;
-	else
-	{
-		/*
-		 * Hack to make up for lack of readfuncs for utility-stmt nodes
-		 *
-		 * we can't get create or index here, can we?
-		 */
-		NotifyStmt *n = makeNode(NotifyStmt);
-
-		n->relname = debackslash(token, length);
-		local_node->utilityStmt = (Node *) n;
-	}
+	local_node->utilityStmt = nodeRead(true);
 
-	token = pg_strtok(&length); /* skip the :resultRelation */
+	token = pg_strtok(&length); /* skip :resultRelation */
 	token = pg_strtok(&length); /* get the resultRelation */
 	local_node->resultRelation = atoi(token);
 
 	token = pg_strtok(&length); /* skip :into */
-	token = pg_strtok(&length); /* get into */
-	local_node->into = nullable_string(token, length);
+	local_node->into = nodeRead(true);
 
 	token = pg_strtok(&length); /* skip :isPortal */
 	token = pg_strtok(&length); /* get isPortal */
@@ -156,10 +141,6 @@ _readQuery(void)
 	token = pg_strtok(&length); /* get isBinary */
 	local_node->isBinary = strtobool(token);
 
-	token = pg_strtok(&length); /* skip :isTemp */
-	token = pg_strtok(&length); /* get isTemp */
-	local_node->isTemp = strtobool(token);
-
 	token = pg_strtok(&length); /* skip the :hasAggs */
 	token = pg_strtok(&length); /* get hasAggs */
 	local_node->hasAggs = strtobool(token);
@@ -210,6 +191,25 @@ _readQuery(void)
 	return local_node;
 }
 
+/* ----------------
+ *		_readNotifyStmt
+ * ----------------
+ */
+static NotifyStmt *
+_readNotifyStmt(void)
+{
+	NotifyStmt *local_node;
+	char	   *token;
+	int			length;
+
+	local_node = makeNode(NotifyStmt);
+
+	token = pg_strtok(&length); /* skip :relation */
+	local_node->relation = nodeRead(true);
+
+	return local_node;
+}
+
 /* ----------------
  *		_readSortClause
  * ----------------
@@ -1394,21 +1394,93 @@ _readTargetEntry(void)
 	return local_node;
 }
 
-static Attr *
-_readAttr(void)
+static RangeVar *
+_readRangeVar(void)
 {
-	Attr	   *local_node;
+	RangeVar   *local_node;
 	char	   *token;
 	int			length;
 
-	local_node = makeNode(Attr);
+	local_node = makeNode(RangeVar);
 
-	token = pg_strtok(&length); /* eat :relname */
+	local_node->catalogname = NULL;	/* not currently saved in output format */
+
+	token = pg_strtok(&length); /* eat :relation */
+	token = pg_strtok(&length); /* get schemaname */
+	local_node->schemaname = nullable_string(token, length);
+
+	token = pg_strtok(&length); /* eat "." */
 	token = pg_strtok(&length); /* get relname */
-	local_node->relname = debackslash(token, length);
+	local_node->relname = nullable_string(token, length);
+	
+	token = pg_strtok(&length); /* eat :inhopt */
+	token = pg_strtok(&length); /* get inhopt */
+	local_node->inhOpt = (InhOption) atoi(token);
+	
+	token = pg_strtok(&length); /* eat :istemp */
+	token = pg_strtok(&length); /* get istemp */
+	local_node->istemp = strtobool(token);
+
+	token = pg_strtok(&length); /* eat :alias */
+	local_node->alias = nodeRead(true); /* now read it */
+
+	return local_node;
+}
+
+static ColumnRef *
+_readColumnRef(void)
+{
+	ColumnRef  *local_node;
+	char	   *token;
+	int			length;
+
+	local_node = makeNode(ColumnRef);
+
+	token = pg_strtok(&length); /* eat :fields */
+	local_node->fields = nodeRead(true); /* now read it */
+
+	token = pg_strtok(&length); /* eat :indirection */
+	local_node->indirection = nodeRead(true); /* now read it */
+
+	return local_node;
+}
+
+static ExprFieldSelect *
+_readExprFieldSelect(void)
+{
+	ExprFieldSelect  *local_node;
+	char	   *token;
+	int			length;
+
+	local_node = makeNode(ExprFieldSelect);
+
+	token = pg_strtok(&length); /* eat :arg */
+	local_node->arg = nodeRead(true); /* now read it */
+
+	token = pg_strtok(&length); /* eat :fields */
+	local_node->fields = nodeRead(true); /* now read it */
+
+	token = pg_strtok(&length); /* eat :indirection */
+	local_node->indirection = nodeRead(true); /* now read it */
+
+	return local_node;
+}
+
+static Alias *
+_readAlias(void)
+{
+	Alias	   *local_node;
+	char	   *token;
+	int			length;
+
+	local_node = makeNode(Alias);
+
+	token = pg_strtok(&length); /* eat :aliasname */
+	token = pg_strtok(&length); /* get aliasname */
+	local_node->aliasname = debackslash(token, length);
 
-	token = pg_strtok(&length); /* eat :attrs */
-	local_node->attrs = nodeRead(true); /* now read it */
+	token = pg_strtok(&length); /* eat :colnames */
+	local_node->colnames = nodeRead(true); /* now read it */
 
 	return local_node;
 }
@@ -1994,8 +2066,6 @@ parsePlanString(void)
 		return_value = _readArrayRef();
 	else if (length == 3 && strncmp(token, "VAR", length) == 0)
 		return_value = _readVar();
-	else if (length == 4 && strncmp(token, "ATTR", length) == 0)
-		return_value = _readAttr();
 	else if (length == 5 && strncmp(token, "CONST", length) == 0)
 		return_value = _readConst();
 	else if (length == 4 && strncmp(token, "FUNC", length) == 0)
@@ -2006,6 +2076,14 @@ parsePlanString(void)
 		return_value = _readParam();
 	else if (length == 11 && strncmp(token, "TARGETENTRY", length) == 0)
 		return_value = _readTargetEntry();
+	else if (length == 8 && strncmp(token, "RANGEVAR", length) == 0)
+		return_value = _readRangeVar();
+	else if (length == 9 && strncmp(token, "COLUMNREF", length) == 0)
+		return_value = _readColumnRef();
+	else if (length == 15 && strncmp(token, "EXPRFIELDSELECT", length) == 0)
+		return_value = _readExprFieldSelect();
+	else if (length == 5 && strncmp(token, "ALIAS", length) == 0)
+		return_value = _readAlias();
 	else if (length == 3 && strncmp(token, "RTE", length) == 0)
 		return_value = _readRangeTblEntry();
 	else if (length == 4 && strncmp(token, "PATH", length) == 0)
@@ -2032,6 +2110,8 @@ parsePlanString(void)
 		return_value = _readIter();
 	else if (length == 5 && strncmp(token, "QUERY", length) == 0)
 		return_value = _readQuery();
+	else if (length == 6 && strncmp(token, "NOTIFY", length) == 0)
+		return_value = _readNotifyStmt();
 	else if (length == 10 && strncmp(token, "SORTCLAUSE", length) == 0)
 		return_value = _readSortClause();
 	else if (length == 11 && strncmp(token, "GROUPCLAUSE", length) == 0)
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 6585fb1905da64b6395815c8ef3abc1a3a12a76a..41cc4cdd5370b51edb2abe4b46f651a453c3b328 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.94 2002/03/12 00:51:50 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.95 2002/03/21 16:00:44 tgl Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -687,7 +687,7 @@ check_subplans_for_ungrouped_vars_walker(Node *node,
 				rte = rt_fetch(var->varno, context->query->rtable);
 				attname = get_rte_attribute_name(rte, var->varattno);
 				elog(ERROR, "Sub-SELECT uses un-GROUPed attribute %s.%s from outer query",
-					 rte->eref->relname, attname);
+					 rte->eref->aliasname, attname);
 			}
 		}
 	}
@@ -1670,7 +1670,6 @@ expression_tree_walker(Node *node,
 		return false;
 	switch (nodeTag(node))
 	{
-		case T_Ident:
 		case T_Const:
 		case T_Var:
 		case T_Param:
@@ -1963,7 +1962,6 @@ expression_tree_mutator(Node *node,
 		return NULL;
 	switch (nodeTag(node))
 	{
-		case T_Ident:
 		case T_Const:
 		case T_Var:
 		case T_Param:
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 98f5030f78b756706dfd3a66d1afb21b33573fc6..109062c529f50d36bb67ae91094b08b179a94776 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *	$Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.220 2002/03/12 00:51:52 tgl Exp $
+ *	$Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.221 2002/03/21 16:00:48 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -43,13 +43,30 @@
 #endif
 
 
+/* State shared by transformCreateSchemaStmt and its subroutines */
+typedef struct
+{
+	const char *stmtType;		/* "CREATE TABLE" or "ALTER TABLE" */
+	char	   *schemaname;		/* name of schema */
+	char	   *authid;			/* owner of schema */
+	List	   *tables;			/* CREATE TABLE items */
+	List	   *views;			/* CREATE VIEW items */
+	List	   *grants;			/* GRANT items */
+	List	   *fwconstraints;	/* Forward referencing FOREIGN KEY constraints */
+	List	   *alters;			/* Generated ALTER items (from the above) */
+	List	   *ixconstraints;	/* index-creating constraints */
+	List	   *blist;			/* "before list" of things to do before
+								 * creating the schema */
+	List	   *alist;			/* "after list" of things to do after
+								 * creating the schema */
+} CreateSchemaStmtContext;
+
 /* State shared by transformCreateStmt and its subroutines */
 typedef struct
 {
 	const char *stmtType;		/* "CREATE TABLE" or "ALTER TABLE" */
-	char	   *relname;		/* name of relation */
-	List	   *inhRelnames;	/* names of relations to inherit from */
-	bool		istemp;			/* is it to be a temp relation? */
+	RangeVar   *relation;		/* relation to create */
+	List	   *inhRelations;	/* relations to inherit from */
 	bool		hasoids;		/* does relation have an OID column? */
 	Oid			relOid;			/* OID of table, if ALTER TABLE case */
 	List	   *columns;		/* ColumnDef items */
@@ -330,8 +347,8 @@ transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt)
 	qry->commandType = CMD_DELETE;
 
 	/* set up range table with just the result rel */
-	qry->resultRelation = setTargetTable(pstate, stmt->relname,
-										 interpretInhOption(stmt->inhOpt),
+	qry->resultRelation = setTargetTable(pstate, stmt->relation->relname,
+										 interpretInhOption(stmt->relation->inhOpt),
 										 true);
 
 	qry->distinctClause = NIL;
@@ -398,7 +415,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
 	 * table is also mentioned in the SELECT part.	Note that the target
 	 * table is not added to the joinlist or namespace.
 	 */
-	qry->resultRelation = setTargetTable(pstate, stmt->relname,
+	qry->resultRelation = setTargetTable(pstate, stmt->relation->relname,
 										 false, false);
 
 	/*
@@ -443,7 +460,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
 		 */
 		rte = addRangeTableEntryForSubquery(pstate,
 											selectQuery,
-											makeAttr("*SELECT*", NULL),
+											makeAlias("*SELECT*", NIL),
 											true);
 		rtr = makeNode(RangeTblRef);
 		/* assume new rte is at end */
@@ -515,14 +532,15 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
 	foreach(tl, qry->targetList)
 	{
 		TargetEntry *tle = (TargetEntry *) lfirst(tl);
-		Ident	   *id;
+		ResTarget   *col;
 
 		Assert(!tle->resdom->resjunk);
 		if (icolumns == NIL || attnos == NIL)
 			elog(ERROR, "INSERT has more expressions than target columns");
-		id = (Ident *) lfirst(icolumns);
-		updateTargetListEntry(pstate, tle, id->name, lfirsti(attnos),
-							  id->indirection);
+		col = (ResTarget *) lfirst(icolumns);
+		Assert(IsA(col, ResTarget));
+		updateTargetListEntry(pstate, tle, col->name, lfirsti(attnos),
+							  col->indirection);
 		icolumns = lnext(icolumns);
 		attnos = lnext(attnos);
 	}
@@ -691,9 +709,8 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt,
 	List	   *elements;
 
 	cxt.stmtType = "CREATE TABLE";
-	cxt.relname = stmt->relname;
-	cxt.inhRelnames = stmt->inhRelnames;
-	cxt.istemp = stmt->istemp;
+	cxt.relation = stmt->relation;
+	cxt.inhRelations = stmt->inhRelations;
 	cxt.hasoids = stmt->hasoids;
 	cxt.relOid = InvalidOid;
 	cxt.columns = NIL;
@@ -805,7 +822,7 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
 		 * conflicting constraints the user wrote (like a different
 		 * DEFAULT).
 		 */
-		sname = makeObjectName(cxt->relname, column->colname, "seq");
+		sname = makeObjectName((cxt->relation)->relname, column->colname, "seq");
 
 		/*
 		 * Create an expression tree representing the function call
@@ -845,12 +862,12 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
 		 * CREATE/ALTER TABLE.
 		 */
 		sequence = makeNode(CreateSeqStmt);
-		sequence->seqname = pstrdup(sname);
-		sequence->istemp = cxt->istemp;
+		sequence->sequence = copyObject(cxt->relation);
+		sequence->sequence->relname = pstrdup(sname);
 		sequence->options = NIL;
 
 		elog(NOTICE, "%s will create implicit sequence '%s' for SERIAL column '%s.%s'",
-		cxt->stmtType, sequence->seqname, cxt->relname, column->colname);
+		cxt->stmtType, sequence->sequence->relname, (cxt->relation)->relname, column->colname);
 
 		cxt->blist = lappend(cxt->blist, sequence);
 	}
@@ -875,9 +892,6 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
 			Ident	   *id = makeNode(Ident);
 
 			id->name = column->colname;
-			id->indirection = NIL;
-			id->isRel = false;
-
 			fkconstraint->fk_attrs = makeList1(id);
 
 			cxt->fkconstraints = lappend(cxt->fkconstraints, fkconstraint);
@@ -891,7 +905,7 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
 			case CONSTR_NULL:
 				if (saw_nullable && column->is_not_null)
 					elog(ERROR, "%s/(NOT) NULL conflicting declaration for '%s.%s'",
-						 cxt->stmtType, cxt->relname, column->colname);
+						 cxt->stmtType, (cxt->relation)->relname, column->colname);
 				column->is_not_null = FALSE;
 				saw_nullable = true;
 				break;
@@ -899,7 +913,7 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
 			case CONSTR_NOTNULL:
 				if (saw_nullable && !column->is_not_null)
 					elog(ERROR, "%s/(NOT) NULL conflicting declaration for '%s.%s'",
-						 cxt->stmtType, cxt->relname, column->colname);
+						 cxt->stmtType, (cxt->relation)->relname, column->colname);
 				column->is_not_null = TRUE;
 				saw_nullable = true;
 				break;
@@ -907,14 +921,14 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
 			case CONSTR_DEFAULT:
 				if (column->raw_default != NULL)
 					elog(ERROR, "%s/DEFAULT multiple values specified for '%s.%s'",
-						 cxt->stmtType, cxt->relname, column->colname);
+						 cxt->stmtType, (cxt->relation)->relname, column->colname);
 				column->raw_default = constraint->raw_expr;
 				Assert(constraint->cooked_expr == NULL);
 				break;
 
 			case CONSTR_PRIMARY:
 				if (constraint->name == NULL)
-					constraint->name = makeObjectName(cxt->relname,
+					constraint->name = makeObjectName((cxt->relation)->relname,
 													  NULL,
 													  "pkey");
 				if (constraint->keys == NIL)
@@ -928,7 +942,7 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
 
 			case CONSTR_UNIQUE:
 				if (constraint->name == NULL)
-					constraint->name = makeObjectName(cxt->relname,
+					constraint->name = makeObjectName((cxt->relation)->relname,
 													  column->colname,
 													  "key");
 				if (constraint->keys == NIL)
@@ -942,7 +956,7 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
 
 			case CONSTR_CHECK:
 				if (constraint->name == NULL)
-					constraint->name = makeObjectName(cxt->relname,
+					constraint->name = makeObjectName((cxt->relation)->relname,
 													  column->colname,
 													  NULL);
 				cxt->ckconstraints = lappend(cxt->ckconstraints, constraint);
@@ -970,7 +984,7 @@ transformTableConstraint(ParseState *pstate, CreateStmtContext *cxt,
 	{
 		case CONSTR_PRIMARY:
 			if (constraint->name == NULL)
-				constraint->name = makeObjectName(cxt->relname,
+				constraint->name = makeObjectName((cxt->relation)->relname,
 												  NULL,
 												  "pkey");
 			cxt->ixconstraints = lappend(cxt->ixconstraints, constraint);
@@ -1034,21 +1048,21 @@ transformIndexConstraints(ParseState *pstate, CreateStmtContext *cxt)
 			/* In ALTER TABLE case, a primary index might already exist */
 			if (cxt->pkey != NULL ||
 				(OidIsValid(cxt->relOid) &&
-				 relationHasPrimaryKey(cxt->relname)))
+				 relationHasPrimaryKey((cxt->relation)->relname)))
 				elog(ERROR, "%s / PRIMARY KEY multiple primary keys"
 					 " for table '%s' are not allowed",
-					 cxt->stmtType, cxt->relname);
+					 cxt->stmtType, (cxt->relation)->relname);
 			cxt->pkey = index;
 		}
 
 		if (constraint->name != NULL)
 			index->idxname = pstrdup(constraint->name);
 		else if (constraint->contype == CONSTR_PRIMARY)
-			index->idxname = makeObjectName(cxt->relname, NULL, "pkey");
+			index->idxname = makeObjectName((cxt->relation)->relname, NULL, "pkey");
 		else
 			index->idxname = NULL;		/* will set it later */
 
-		index->relname = cxt->relname;
+		index->relation = cxt->relation;
 		index->accessMethod = DEFAULT_INDEX_TYPE;
 		index->indexParams = NIL;
 		index->whereClause = NULL;
@@ -1089,19 +1103,19 @@ transformIndexConstraints(ParseState *pstate, CreateStmtContext *cxt)
 				 */
 				found = true;
 			}
-			else if (cxt->inhRelnames)
+			else if (cxt->inhRelations)
 			{
 				/* try inherited tables */
 				List	   *inher;
 
-				foreach(inher, cxt->inhRelnames)
+				foreach(inher, cxt->inhRelations)
 				{
-					Value	   *inh = lfirst(inher);
+					RangeVar   *inh = lfirst(inher);
 					Relation	rel;
 					int			count;
 
-					Assert(IsA(inh, String));
-					rel = heap_openr(strVal(inh), AccessShareLock);
+					Assert(IsA(inh, RangeVar));
+					rel = heap_openr(inh->relname, AccessShareLock);
 					if (rel->rd_rel->relkind != RELKIND_RELATION)
 						elog(ERROR, "inherited table \"%s\" is not a relation",
 							 strVal(inh));
@@ -1257,7 +1271,7 @@ transformIndexConstraints(ParseState *pstate, CreateStmtContext *cxt)
 		if (index->idxname == NULL && index->indexParams != NIL)
 		{
 			iparam = lfirst(index->indexParams);
-			index->idxname = CreateIndexName(cxt->relname, iparam->name,
+			index->idxname = CreateIndexName((cxt->relation)->relname, iparam->name,
 											 "key", cxt->alist);
 		}
 		if (index->idxname == NULL)		/* should not happen */
@@ -1268,7 +1282,7 @@ transformIndexConstraints(ParseState *pstate, CreateStmtContext *cxt)
 			 cxt->stmtType,
 			 (strcmp(cxt->stmtType, "ALTER TABLE") == 0) ? "ADD " : "",
 			 (index->primary ? "PRIMARY KEY" : "UNIQUE"),
-			 index->idxname, cxt->relname);
+			 index->idxname, (cxt->relation)->relname);
 	}
 }
 
@@ -1328,7 +1342,7 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt)
 		 */
 		if (fkconstraint->pk_attrs == NIL)
 		{
-			if (strcmp(fkconstraint->pktable_name, cxt->relname) != 0)
+			if (strcmp(fkconstraint->pktable->relname, (cxt->relation)->relname) != 0)
 				transformFkeyGetPrimaryKey(fkconstraint, pktypoid);
 			else if (cxt->pkey != NULL)
 			{
@@ -1342,8 +1356,6 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt)
 					Ident	   *pkattr = (Ident *) makeNode(Ident);
 
 					pkattr->name = pstrdup(ielem->name);
-					pkattr->indirection = NIL;
-					pkattr->isRel = false;
 					fkconstraint->pk_attrs = lappend(fkconstraint->pk_attrs,
 													 pkattr);
 					if (attnum >= INDEX_MAX_KEYS)
@@ -1360,13 +1372,13 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt)
 					transformFkeyGetPrimaryKey(fkconstraint, pktypoid);
 				else
 					elog(ERROR, "PRIMARY KEY for referenced table \"%s\" not found",
-						 fkconstraint->pktable_name);
+						 fkconstraint->pktable->relname);
 			}
 		}
 		else
 		{
 			/* Validate the specified referenced key list */
-			if (strcmp(fkconstraint->pktable_name, cxt->relname) != 0)
+			if (strcmp(fkconstraint->pktable->relname, (cxt->relation)->relname) != 0)
 				transformFkeyCheckAttrs(fkconstraint, pktypoid);
 			else
 			{
@@ -1422,7 +1434,7 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt)
 						transformFkeyCheckAttrs(fkconstraint, pktypoid);
 					else
 						elog(ERROR, "UNIQUE constraint matching given keys for referenced table \"%s\" not found",
-							 fkconstraint->pktable_name);
+							 fkconstraint->pktable->relname);
 				}
 			}
 		}
@@ -1447,7 +1459,7 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt)
 		 */
 		fk_trigger = (CreateTrigStmt *) makeNode(CreateTrigStmt);
 		fk_trigger->trigname = fkconstraint->constr_name;
-		fk_trigger->relname = cxt->relname;
+		fk_trigger->relation = cxt->relation;
 		fk_trigger->funcname = "RI_FKey_check_ins";
 		fk_trigger->before = false;
 		fk_trigger->row = true;
@@ -1462,15 +1474,15 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt)
 		fk_trigger->isconstraint = true;
 		fk_trigger->deferrable = fkconstraint->deferrable;
 		fk_trigger->initdeferred = fkconstraint->initdeferred;
-		fk_trigger->constrrelname = fkconstraint->pktable_name;
+		fk_trigger->constrrel = fkconstraint->pktable;
 
 		fk_trigger->args = NIL;
 		fk_trigger->args = lappend(fk_trigger->args,
 								   makeString(fkconstraint->constr_name));
 		fk_trigger->args = lappend(fk_trigger->args,
-								   makeString(cxt->relname));
+								   makeString((cxt->relation)->relname));
 		fk_trigger->args = lappend(fk_trigger->args,
-								 makeString(fkconstraint->pktable_name));
+								 makeString(fkconstraint->pktable->relname));
 		fk_trigger->args = lappend(fk_trigger->args,
 								   makeString(fkconstraint->match_type));
 		fk_attr = fkconstraint->fk_attrs;
@@ -1478,7 +1490,7 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt)
 		if (length(fk_attr) != length(pk_attr))
 			elog(ERROR, "number of key attributes in referenced table must be equal to foreign key"
 				 "\n\tIllegal FOREIGN KEY definition references \"%s\"",
-				 fkconstraint->pktable_name);
+				 fkconstraint->pktable->relname);
 
 		while (fk_attr != NIL)
 		{
@@ -1502,7 +1514,7 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt)
 		 */
 		fk_trigger = (CreateTrigStmt *) makeNode(CreateTrigStmt);
 		fk_trigger->trigname = fkconstraint->constr_name;
-		fk_trigger->relname = fkconstraint->pktable_name;
+		fk_trigger->relation = fkconstraint->pktable;
 		fk_trigger->before = false;
 		fk_trigger->row = true;
 		fk_trigger->actions[0] = 'd';
@@ -1515,7 +1527,7 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt)
 		fk_trigger->isconstraint = true;
 		fk_trigger->deferrable = fkconstraint->deferrable;
 		fk_trigger->initdeferred = fkconstraint->initdeferred;
-		fk_trigger->constrrelname = cxt->relname;
+		fk_trigger->constrrel = cxt->relation;
 		switch ((fkconstraint->actions & FKCONSTR_ON_DELETE_MASK)
 				>> FKCONSTR_ON_DELETE_SHIFT)
 		{
@@ -1545,9 +1557,9 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt)
 		fk_trigger->args = lappend(fk_trigger->args,
 								   makeString(fkconstraint->constr_name));
 		fk_trigger->args = lappend(fk_trigger->args,
-								   makeString(cxt->relname));
+								   makeString((cxt->relation)->relname));
 		fk_trigger->args = lappend(fk_trigger->args,
-								 makeString(fkconstraint->pktable_name));
+								 makeString(fkconstraint->pktable->relname));
 		fk_trigger->args = lappend(fk_trigger->args,
 								   makeString(fkconstraint->match_type));
 		fk_attr = fkconstraint->fk_attrs;
@@ -1574,7 +1586,7 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt)
 		 */
 		fk_trigger = (CreateTrigStmt *) makeNode(CreateTrigStmt);
 		fk_trigger->trigname = fkconstraint->constr_name;
-		fk_trigger->relname = fkconstraint->pktable_name;
+		fk_trigger->relation = fkconstraint->pktable;
 		fk_trigger->before = false;
 		fk_trigger->row = true;
 		fk_trigger->actions[0] = 'u';
@@ -1587,7 +1599,7 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt)
 		fk_trigger->isconstraint = true;
 		fk_trigger->deferrable = fkconstraint->deferrable;
 		fk_trigger->initdeferred = fkconstraint->initdeferred;
-		fk_trigger->constrrelname = cxt->relname;
+		fk_trigger->constrrel = cxt->relation;
 		switch ((fkconstraint->actions & FKCONSTR_ON_UPDATE_MASK)
 				>> FKCONSTR_ON_UPDATE_SHIFT)
 		{
@@ -1617,9 +1629,9 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt)
 		fk_trigger->args = lappend(fk_trigger->args,
 								   makeString(fkconstraint->constr_name));
 		fk_trigger->args = lappend(fk_trigger->args,
-								   makeString(cxt->relname));
+								   makeString((cxt->relation)->relname));
 		fk_trigger->args = lappend(fk_trigger->args,
-								 makeString(fkconstraint->pktable_name));
+								 makeString(fkconstraint->pktable->relname));
 		fk_trigger->args = lappend(fk_trigger->args,
 								   makeString(fkconstraint->match_type));
 		fk_attr = fkconstraint->fk_attrs;
@@ -1672,7 +1684,7 @@ transformIndexStmt(ParseState *pstate, IndexStmt *stmt)
 		 * easily support predicates on indexes created implicitly by
 		 * CREATE TABLE. Fortunately, that's not necessary.
 		 */
-		rte = addRangeTableEntry(pstate, stmt->relname, NULL, false, true);
+		rte = addRangeTableEntry(pstate, stmt->relation->relname, NULL, false, true);
 
 		/* no to join list, yes to namespace */
 		addRTEtoQuery(pstate, rte, false, true);
@@ -1712,7 +1724,7 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt,
 	 * beforehand.	We don't need to hold a refcount on the relcache
 	 * entry, however.
 	 */
-	heap_close(heap_openr(stmt->object->relname, AccessExclusiveLock),
+	heap_close(heap_openr(stmt->relation->relname, AccessExclusiveLock),
 			   NoLock);
 
 	/*
@@ -1721,11 +1733,11 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt,
 	 * rule qualification.
 	 */
 	Assert(pstate->p_rtable == NIL);
-	oldrte = addRangeTableEntry(pstate, stmt->object->relname,
-								makeAttr("*OLD*", NULL),
+	oldrte = addRangeTableEntry(pstate, stmt->relation->relname,
+								makeAlias("*OLD*", NIL),
 								false, true);
-	newrte = addRangeTableEntry(pstate, stmt->object->relname,
-								makeAttr("*NEW*", NULL),
+	newrte = addRangeTableEntry(pstate, stmt->relation->relname,
+								makeAlias("*NEW*", NIL),
 								false, true);
 	/* Must override addRangeTableEntry's default access-check flags */
 	oldrte->checkForRead = false;
@@ -1812,11 +1824,11 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt,
 			 * or they won't be accessible at all.  We decide later
 			 * whether to put them in the joinlist.
 			 */
-			oldrte = addRangeTableEntry(sub_pstate, stmt->object->relname,
-										makeAttr("*OLD*", NULL),
+			oldrte = addRangeTableEntry(sub_pstate, stmt->relation->relname,
+										makeAlias("*OLD*", NIL),
 										false, false);
-			newrte = addRangeTableEntry(sub_pstate, stmt->object->relname,
-										makeAttr("*NEW*", NULL),
+			newrte = addRangeTableEntry(sub_pstate, stmt->relation->relname,
+										makeAlias("*NEW*", NIL),
 										false, false);
 			oldrte->checkForRead = false;
 			newrte->checkForRead = false;
@@ -1950,8 +1962,8 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
 		if (!IsTransactionBlock())
 			elog(ERROR, "DECLARE CURSOR may only be used in begin/end transaction blocks");
 
-		qry->into = stmt->portalname;
-		qry->isTemp = stmt->istemp;
+		qry->into = makeNode(RangeVar);
+		qry->into->relname = stmt->portalname;
 		qry->isPortal = TRUE;
 		qry->isBinary = stmt->binary;	/* internal portal */
 	}
@@ -1959,7 +1971,6 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
 	{
 		/* SELECT */
 		qry->into = stmt->into;
-		qry->isTemp = stmt->istemp;
 		qry->isPortal = FALSE;
 		qry->isBinary = FALSE;
 	}
@@ -2033,8 +2044,7 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
 	int			leftmostRTI;
 	Query	   *leftmostQuery;
 	SetOperationStmt *sostmt;
-	char	   *into;
-	bool		istemp;
+	RangeVar   *into;
 	List	   *intoColNames;
 	char	   *portalname;
 	bool		binary;
@@ -2065,14 +2075,12 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
 	Assert(leftmostSelect && IsA(leftmostSelect, SelectStmt) &&
 		   leftmostSelect->larg == NULL);
 	into = leftmostSelect->into;
-	istemp = leftmostSelect->istemp;
 	intoColNames = leftmostSelect->intoColNames;
 	portalname = stmt->portalname;
 	binary = stmt->binary;
 
 	/* clear them to prevent complaints in transformSetOperationTree() */
 	leftmostSelect->into = NULL;
-	leftmostSelect->istemp = false;
 	leftmostSelect->intoColNames = NIL;
 	stmt->portalname = NULL;
 	stmt->binary = false;
@@ -2174,8 +2182,8 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
 		if (!IsTransactionBlock())
 			elog(ERROR, "DECLARE CURSOR may only be used in begin/end transaction blocks");
 
-		qry->into = portalname;
-		qry->isTemp = istemp;
+		qry->into = makeNode(RangeVar);
+		qry->into->relname = portalname;
 		qry->isPortal = TRUE;
 		qry->isBinary = binary; /* internal portal */
 	}
@@ -2183,7 +2191,6 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
 	{
 		/* SELECT */
 		qry->into = into;
-		qry->isTemp = istemp;
 		qry->isPortal = FALSE;
 		qry->isBinary = FALSE;
 	}
@@ -2325,8 +2332,7 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt)
 		sprintf(selectName, "*SELECT* %d", length(pstate->p_rtable) + 1);
 		rte = addRangeTableEntryForSubquery(pstate,
 											selectQuery,
-											makeAttr(pstrdup(selectName),
-													 NULL),
+											makeAlias(selectName, NIL),
 											false);
 
 		/*
@@ -2468,8 +2474,8 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
 	qry->commandType = CMD_UPDATE;
 	pstate->p_is_update = true;
 
-	qry->resultRelation = setTargetTable(pstate, stmt->relname,
-										 interpretInhOption(stmt->inhOpt),
+	qry->resultRelation = setTargetTable(pstate, stmt->relation->relname,
+										 interpretInhOption(stmt->relation->inhOpt),
 										 true);
 
 	/*
@@ -2553,11 +2559,11 @@ transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt,
 	{
 		case 'A':
 			cxt.stmtType = "ALTER TABLE";
-			cxt.relname = stmt->relname;
-			cxt.inhRelnames = NIL;
-			cxt.istemp = is_temp_rel_name(stmt->relname);
+			cxt.relation = stmt->relation;
+			cxt.inhRelations = NIL;
+			cxt.relation->istemp = is_temp_rel_name(stmt->relation->relname);
 			cxt.relOid = GetSysCacheOid(RELNAME,
-										PointerGetDatum(stmt->relname),
+										PointerGetDatum((stmt->relation)->relname),
 										0, 0, 0);
 			cxt.hasoids = SearchSysCacheExists(ATTNUM,
 											ObjectIdGetDatum(cxt.relOid),
@@ -2585,11 +2591,11 @@ transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt,
 
 		case 'C':
 			cxt.stmtType = "ALTER TABLE";
-			cxt.relname = stmt->relname;
-			cxt.inhRelnames = NIL;
-			cxt.istemp = is_temp_rel_name(stmt->relname);
+			cxt.relation = stmt->relation;
+			cxt.inhRelations = NIL;
+			cxt.relation->istemp = is_temp_rel_name(stmt->relation->relname);
 			cxt.relOid = GetSysCacheOid(RELNAME,
-										PointerGetDatum(stmt->relname),
+										PointerGetDatum((stmt->relation)->relname),
 										0, 0, 0);
 			cxt.hasoids = SearchSysCacheExists(ATTNUM,
 											ObjectIdGetDatum(cxt.relOid),
@@ -2713,15 +2719,18 @@ transformTypeRefsList(ParseState *pstate, List *l)
 static void
 transformTypeRef(ParseState *pstate, TypeName *tn)
 {
-	Attr	   *att;
+	ColumnRef  *cref;
 	Node	   *n;
 	Var		   *v;
 	char	   *tyn;
 
 	if (tn->attrname == NULL)
 		return;
-	att = makeAttr(tn->name, tn->attrname);
-	n = transformExpr(pstate, (Node *) att, EXPR_COLUMN_FIRST);
+	/* XXX this needs work; can't type name be qualified? */
+	cref = makeNode(ColumnRef);
+	cref->fields = makeList2(makeString(tn->name), makeString(tn->attrname));
+	cref->indirection = NIL;
+	n = transformExpr(pstate, (Node *) cref);
 	if (!IsA(n, Var))
 		elog(ERROR, "unsupported expression in %%TYPE");
 	v = (Var *) n;
@@ -2791,7 +2800,7 @@ transformForUpdate(Query *qry, List *forUpdate)
 				RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
 
 				++i;
-				if (strcmp(rte->eref->relname, relname) == 0)
+				if (strcmp(rte->eref->aliasname, relname) == 0)
 				{
 					if (rte->subquery)
 					{
@@ -2835,11 +2844,11 @@ transformFkeyCheckAttrs(FkConstraint *fkconstraint, Oid *pktypoid)
 	/*
 	 * Open the referenced table
 	 */
-	pkrel = heap_openr(fkconstraint->pktable_name, AccessShareLock);
+	pkrel = heap_openr(fkconstraint->pktable->relname, AccessShareLock);
 
 	if (pkrel->rd_rel->relkind != RELKIND_RELATION)
 		elog(ERROR, "Referenced relation \"%s\" is not a table",
-			 fkconstraint->pktable_name);
+			 fkconstraint->pktable->relname);
 
 	/*
 	 * Get the list of index OIDs for the table from the relcache, and
@@ -2901,7 +2910,7 @@ transformFkeyCheckAttrs(FkConstraint *fkconstraint, Oid *pktypoid)
 	}
 	if (!found)
 		elog(ERROR, "UNIQUE constraint matching given keys for referenced table \"%s\" not found",
-			 fkconstraint->pktable_name);
+			 fkconstraint->pktable->relname);
 
 	freeList(indexoidlist);
 	heap_close(pkrel, AccessShareLock);
@@ -2928,11 +2937,11 @@ transformFkeyGetPrimaryKey(FkConstraint *fkconstraint, Oid *pktypoid)
 	/*
 	 * Open the referenced table
 	 */
-	pkrel = heap_openr(fkconstraint->pktable_name, AccessShareLock);
+	pkrel = heap_openr(fkconstraint->pktable->relname, AccessShareLock);
 
 	if (pkrel->rd_rel->relkind != RELKIND_RELATION)
 		elog(ERROR, "Referenced relation \"%s\" is not a table",
-			 fkconstraint->pktable_name);
+			 fkconstraint->pktable->relname);
 
 	/*
 	 * Get the list of index OIDs for the table from the relcache, and
@@ -2965,7 +2974,7 @@ transformFkeyGetPrimaryKey(FkConstraint *fkconstraint, Oid *pktypoid)
 	 */
 	if (indexStruct == NULL)
 		elog(ERROR, "PRIMARY KEY for referenced table \"%s\" not found",
-			 fkconstraint->pktable_name);
+			 fkconstraint->pktable->relname);
 
 	/*
 	 * Now build the list of PK attributes from the indkey definition
@@ -2977,8 +2986,6 @@ transformFkeyGetPrimaryKey(FkConstraint *fkconstraint, Oid *pktypoid)
 		Ident	   *pkattr = makeNode(Ident);
 
 		pkattr->name = pstrdup(NameStr(*attnumAttName(pkrel, pkattno)));
-		pkattr->indirection = NIL;
-		pkattr->isRel = false;
 		pktypoid[attnum++] = attnumTypeId(pkrel, pkattno);
 
 		fkconstraint->pk_attrs = lappend(fkconstraint->pk_attrs, pkattr);
@@ -3070,14 +3077,14 @@ transformFkeyGetColType(CreateStmtContext *cxt, char *colname)
 	if (sysatt)
 		return sysatt->atttypid;
 	/* Look for column among inherited columns (if CREATE TABLE case) */
-	foreach(inher, cxt->inhRelnames)
+	foreach(inher, cxt->inhRelations)
 	{
-		Value	   *inh = lfirst(inher);
+		RangeVar   *inh = lfirst(inher);
 		Relation	rel;
 		int			count;
 
-		Assert(IsA(inh, String));
-		rel = heap_openr(strVal(inh), AccessShareLock);
+		Assert(IsA(inh, RangeVar));
+		rel = heap_openr(inh->relname, AccessShareLock);
 		if (rel->rd_rel->relkind != RELKIND_RELATION)
 			elog(ERROR, "inherited table \"%s\" is not a relation",
 				 strVal(inh));
@@ -3248,3 +3255,104 @@ transformColumnType(ParseState *pstate, ColumnDef *column)
 
 	ReleaseSysCache(ctype);
 }
+
+/*
+ * analyzeCreateSchemaStmt -
+ *	  analyzes the "create schema" statement
+ *
+ * Split the schema element list into individual commands and place
+ * them in the result list in an order such that there are no
+ * forward references (e.g. GRANT to a table created later in the list).
+ *
+ * SQL92 also allows constraints to make forward references, so thumb through
+ * the table columns and move forward references to a posterior alter-table
+ * command.
+ *
+ * The result is a list of parse nodes that still need to be analyzed ---
+ * but we can't analyze the later commands until we've executed the earlier
+ * ones, because of possible inter-object references.
+ *
+ * Note: Called from commands/command.c
+ */
+List *
+analyzeCreateSchemaStmt(CreateSchemaStmt *stmt)
+{
+	CreateSchemaStmtContext cxt;
+	List	   *result;
+	List	   *elements;
+
+	cxt.stmtType = "CREATE SCHEMA";
+	cxt.schemaname = stmt->schemaname;
+	cxt.authid = stmt->authid;
+	cxt.tables = NIL;
+	cxt.views = NIL;
+	cxt.grants = NIL;
+	cxt.fwconstraints = NIL;
+	cxt.alters = NIL;
+	cxt.blist = NIL;
+	cxt.alist = NIL;
+
+	/*
+	 * Run through each schema element in the schema element list.
+	 * Separate statements by type, and do preliminary analysis.
+	 */
+	foreach(elements, stmt->schemaElts)
+	{
+		Node	   *element = lfirst(elements);
+
+		switch (nodeTag(element))
+		{
+			case T_CreateStmt:
+				{
+					CreateStmt *elp = (CreateStmt *) element;
+
+					if (elp->relation->schemaname == NULL)
+						elp->relation->schemaname = cxt.schemaname;
+					else if (strcmp(cxt.schemaname, elp->relation->schemaname))
+						elog(ERROR, "New table refers to a schema (%s)"
+							" different from the one being created (%s)",
+							elp->relation->schemaname, cxt.schemaname);
+
+					/*
+					 * XXX todo: deal with constraints
+					 */
+
+					cxt.tables = lappend(cxt.tables, element);
+				}
+				break;
+
+			case T_ViewStmt:
+				{
+					ViewStmt *elp = (ViewStmt *) element;
+
+					if (elp->view->schemaname == NULL)
+						elp->view->schemaname = cxt.schemaname;
+					else if (strcmp(cxt.schemaname, elp->view->schemaname))
+						elog(ERROR, "New view refers to a schema (%s)"
+							" different from the one being created (%s)",
+							elp->view->schemaname, cxt.schemaname);
+
+					/*
+					 * XXX todo: deal with references between views
+					 */
+
+					cxt.views = lappend(cxt.views, element);
+				}
+				break;
+
+			case T_GrantStmt:
+				cxt.grants = lappend(cxt.grants, element);
+				break;
+
+			default:
+				elog(ERROR, "parser: unsupported schema node (internal error)");
+		}
+	}
+
+	result = NIL;	
+	result = nconc(result, cxt.tables);
+	result = nconc(result, cxt.views);
+	result = nconc(result, cxt.grants);
+
+	return result;
+}
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 6951653ce8a352d7a98525ef1648d5fd55273353..f94eaea509815a4106aa68da98e87efa03da61be 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.294 2002/03/20 19:44:21 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.295 2002/03/21 16:00:50 tgl Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -98,6 +98,7 @@ static void doNegateFloat(Value *v);
 
 %}
 
+
 %union
 {
 	int					ival;
@@ -108,19 +109,17 @@ static void doNegateFloat(Value *v);
 	List				*list;
 	Node				*node;
 	Value				*value;
-
-	Attr				*attr;
-	Ident				*ident;
+	ColumnRef			*columnref;
 
 	TypeName			*typnam;
 	DefElem				*defelt;
 	SortGroupBy			*sortgroupby;
 	JoinExpr			*jexpr;
 	IndexElem			*ielem;
+	Alias				*alias;
 	RangeVar			*range;
 	A_Indices			*aind;
 	ResTarget			*target;
-	ParamNo				*paramno;
 	PrivTarget			*privtarget;
 
 	VersionStmt			*vstmt;
@@ -129,7 +128,7 @@ static void doNegateFloat(Value *v);
 	InsertStmt			*istmt;
 }
 
-%type <node>	stmt,
+%type <node>	stmt, schema_stmt,
 		AlterDatabaseSetStmt, AlterGroupStmt, AlterSchemaStmt, AlterTableStmt,
 		AlterUserStmt, AlterUserSetStmt, AnalyzeStmt,
 		ClosePortalStmt, ClusterStmt, CommentStmt, ConstraintsSetStmt,
@@ -166,11 +165,12 @@ static void doNegateFloat(Value *v);
 %type <list>	OptUserList
 %type <defelt>	OptUserElem
 
+%type <str>		OptSchemaName
+%type <list>	OptSchemaEltList
+
 %type <boolean>	TriggerActionTime, TriggerForSpec, opt_trusted, opt_procedural
 %type <str>		opt_lancompiler
 
-%type <str>		OptConstrFromTable
-
 %type <str>		TriggerEvents
 %type <value>	TriggerFuncArg
 
@@ -178,6 +178,8 @@ static void doNegateFloat(Value *v);
 		database_name, access_method_clause, access_method, attr_name,
 		class, index_name, name, func_name, file_name
 
+%type <range>	qualified_name, OptConstrFromTable
+
 %type <str>		opt_id,
 		all_Op, MathOp, opt_name,
 		OptUseOp, opt_class, SpecialRuleRelation
@@ -193,17 +195,19 @@ static void doNegateFloat(Value *v);
 %type <chr>	TriggerOneEvent
 
 %type <list>	stmtblock, stmtmulti,
-		into_clause, OptTempTableName, relation_name_list,
 		OptTableElementList, OptInherit, definition, opt_distinct,
 		opt_with, func_args, func_args_list, func_as,
 		oper_argtypes, RuleActionList, RuleActionMulti,
 		opt_column_list, columnList, opt_name_list,
 		sort_clause, sortby_list, index_params, index_list, name_list,
-		from_clause, from_list, opt_array_bounds,
-		expr_list, attrs, target_list, update_target_list,
+		from_clause, from_list, opt_array_bounds, qualified_name_list,
+		expr_list, attrs, opt_attrs, target_list, update_target_list,
+		insert_column_list,
 		def_list, opt_indirection, group_clause, TriggerFuncArgs,
 		select_limit, opt_select_limit
 
+%type <range>	into_clause, OptTempTableName
+
 %type <typnam>	func_arg, func_return, func_type, aggr_argtype
 
 %type <boolean>	opt_arg, TriggerForOpt, TriggerForType, OptTemp, OptWithOids
@@ -240,7 +244,7 @@ static void doNegateFloat(Value *v);
 %type <node>	OptTableElement, ConstraintElem
 %type <node>	columnDef
 %type <defelt>	def_elem
-%type <node>	def_arg, columnElem, where_clause,
+%type <node>	def_arg, columnElem, where_clause, insert_column_item,
 				a_expr, b_expr, c_expr, AexprConst,
 				in_expr, having_clause
 %type <list>	row_descriptor, row_list, in_expr_nodes
@@ -252,14 +256,14 @@ static void doNegateFloat(Value *v);
 %type <list>	OptCreateAs, CreateAsList
 %type <node>	CreateAsElement
 %type <value>	NumericOnly, FloatOnly, IntegerOnly
-%type <attr>	event_object, attr, alias_clause
+%type <columnref>	columnref
+%type <alias>	alias_clause
 %type <sortgroupby>		sortby
 %type <ielem>	index_elem, func_index
 %type <node>	table_ref
 %type <jexpr>	joined_table
 %type <range>	relation_expr
 %type <target>	target_el, update_target_el
-%type <paramno> ParamNo
 
 %type <typnam>	Typename, SimpleTypename, ConstTypename
 				GenericType, Numeric, Character, ConstDatetime, ConstInterval, Bit
@@ -290,6 +294,7 @@ static void doNegateFloat(Value *v);
 
 %type <boolean> opt_as
 
+
 /*
  * If you make any token changes, remember to:
  *		- use "yacc -d" and update parse.h
@@ -753,35 +758,57 @@ DropGroupStmt: DROP GROUP UserId
  *
  *****************************************************************************/
 
-CreateSchemaStmt:  CREATE SCHEMA UserId
+CreateSchemaStmt:  CREATE SCHEMA OptSchemaName AUTHORIZATION UserId OptSchemaEltList
 				{
-					/* for now, just make this the same as CREATE DATABASE */
-					CreatedbStmt *n = makeNode(CreatedbStmt);
-					n->dbname = $3;
-					n->dbowner = NULL;
-					n->dbpath = NULL;
-					n->dbtemplate = NULL;
-					n->encoding = -1;
+					CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
+					/* One can omit the schema name or the authorization id... */
+					if ($3 != NULL)
+						n->schemaname = $3;
+					else
+						n->schemaname = $5;
+					n->authid = $5;
+					n->schemaElts = $6;
+					$$ = (Node *)n;
+				}
+		| CREATE SCHEMA ColId OptSchemaEltList
+				{
+					CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
+					/* ...but not both */
+					n->schemaname = $3;
+					n->authid = NULL;
+					n->schemaElts = $4;
 					$$ = (Node *)n;
 				}
 		;
 
-AlterSchemaStmt:  ALTER SCHEMA UserId
+AlterSchemaStmt:  ALTER SCHEMA ColId
 				{
 					elog(ERROR, "ALTER SCHEMA not yet supported");
 				}
 		;
 
-DropSchemaStmt:  DROP SCHEMA UserId
+DropSchemaStmt:  DROP SCHEMA ColId
 				{
-					DropdbStmt *n = makeNode(DropdbStmt);
-					n->dbname = $3;
-					$$ = (Node *)n;
+					elog(ERROR, "DROP SCHEMA not yet supported");
 				}
 		;
 
+OptSchemaName: ColId								{ $$ = $1; }
+		| /* EMPTY */								{ $$ = NULL; }
+		;
+
+OptSchemaEltList: OptSchemaEltList schema_stmt		{ $$ = lappend($1, $2); }
+		| /* EMPTY */								{ $$ = NIL; }
+		;
 
- 
+/*
+ *	schema_stmt are the ones that can show up inside a CREATE SCHEMA
+ *	statement (in addition to by themselves).
+ */
+schema_stmt: CreateStmt
+		| GrantStmt
+		| ViewStmt
+		;
 
 /*****************************************************************************
  *
@@ -978,6 +1005,7 @@ opt_encoding:  Sconst						{ $$ = $1; }
 
 ColId_or_Sconst: ColId						{ $$ = $1; }
 		| SCONST							{ $$ = $1; }
+		;
 
 
 VariableShowStmt:  SHOW ColId
@@ -1073,8 +1101,7 @@ AlterTableStmt:
 				{
 					AlterTableStmt *n = makeNode(AlterTableStmt);
 					n->subtype = 'A';
-					n->relname = $3->relname;
-					n->inhOpt = $3->inhOpt;
+					n->relation = $3;
 					n->def = $6;
 					$$ = (Node *)n;
 				}
@@ -1083,8 +1110,7 @@ AlterTableStmt:
 				{
 					AlterTableStmt *n = makeNode(AlterTableStmt);
 					n->subtype = 'T';
-					n->relname = $3->relname;
-					n->inhOpt = $3->inhOpt;
+					n->relation = $3;
 					n->name = $6;
 					n->def = $7;
 					$$ = (Node *)n;
@@ -1094,8 +1120,7 @@ AlterTableStmt:
 				{
 					AlterTableStmt *n = makeNode(AlterTableStmt);
 					n->subtype = 'S';
-					n->relname = $3->relname;
-					n->inhOpt = $3->inhOpt;
+					n->relation = $3;
 					n->name = $6;
 					n->def = (Node *) makeInteger($9);
 					$$ = (Node *)n;
@@ -1105,8 +1130,7 @@ AlterTableStmt:
                 {
 					AlterTableStmt *n = makeNode(AlterTableStmt);
 					n->subtype = 'M';
-					n->relname = $3->relname;
-					n->inhOpt = $3->inhOpt;
+					n->relation = $3;
 					n->name = $6;
 					n->def = (Node *) makeString($9);
 					$$ = (Node *)n;
@@ -1116,8 +1140,7 @@ AlterTableStmt:
 				{
 					AlterTableStmt *n = makeNode(AlterTableStmt);
 					n->subtype = 'D';
-					n->relname = $3->relname;
-					n->inhOpt = $3->inhOpt;
+					n->relation = $3;
 					n->name = $6;
 					n->behavior = $7;
 					$$ = (Node *)n;
@@ -1127,8 +1150,7 @@ AlterTableStmt:
 				{
 					AlterTableStmt *n = makeNode(AlterTableStmt);
 					n->subtype = 'C';
-					n->relname = $3->relname;
-					n->inhOpt = $3->inhOpt;
+					n->relation = $3;
 					n->def = $5;
 					$$ = (Node *)n;
 				}
@@ -1137,28 +1159,27 @@ AlterTableStmt:
 				{
 					AlterTableStmt *n = makeNode(AlterTableStmt);
 					n->subtype = 'X';
-					n->relname = $3->relname;
-					n->inhOpt = $3->inhOpt;
+					n->relation = $3;
 					n->name = $6;
 					n->behavior = $7;
 					$$ = (Node *)n;
 				}
 /* ALTER TABLE <name> CREATE TOAST TABLE */
-		| ALTER TABLE relation_name CREATE TOAST TABLE
+		| ALTER TABLE qualified_name CREATE TOAST TABLE
 				{
 					AlterTableStmt *n = makeNode(AlterTableStmt);
 					n->subtype = 'E';
-					n->relname = $3;
-					n->inhOpt = INH_NO;
+					$3->inhOpt = INH_NO;
+					n->relation = $3;
 					$$ = (Node *)n;
 				}
 /* ALTER TABLE <name> OWNER TO UserId */
-		| ALTER TABLE relation_name OWNER TO UserId
+		| ALTER TABLE qualified_name OWNER TO UserId
 				{
 					AlterTableStmt *n = makeNode(AlterTableStmt);
 					n->subtype = 'U';
-					n->relname = $3;
-					n->inhOpt = INH_NO;
+					$3->inhOpt = INH_NO;
+					n->relation = $3;
 					n->name = $6;
 					$$ = (Node *)n;
 				}
@@ -1183,7 +1204,8 @@ drop_behavior: CASCADE					{ $$ = CASCADE; }
 opt_drop_behavior: CASCADE				{ $$ = CASCADE; }
 		| RESTRICT						{ $$ = RESTRICT; }
 		| /* EMPTY */					{ $$ = RESTRICT; /* default */ }
-        ;
+		;
+
 
 
 /*****************************************************************************
@@ -1214,11 +1236,11 @@ opt_id:  ColId									{ $$ = $1; }
  *
  *****************************************************************************/
 
-CopyStmt:  COPY opt_binary relation_name opt_with_copy copy_dirn copy_file_name copy_delimiter copy_null
+CopyStmt:  COPY opt_binary qualified_name opt_with_copy copy_dirn copy_file_name copy_delimiter copy_null
 				{
 					CopyStmt *n = makeNode(CopyStmt);
 					n->binary = $2;
-					n->relname = $3;
+					n->relation = $3;
 					n->oids = $4;
 					n->direction = $5;
 					n->filename = $6;
@@ -1263,8 +1285,9 @@ opt_using:	USING								{ $$ = TRUE; }
 		| /*EMPTY*/								{ $$ = TRUE; }
 		;
 
-copy_null:      WITH NULL_P AS Sconst			{ $$ = $4; }
-                | /*EMPTY*/						{ $$ = "\\N"; }
+copy_null:  WITH NULL_P AS Sconst				{ $$ = $4; }
+		| /*EMPTY*/								{ $$ = "\\N"; }
+		;
 
 /*****************************************************************************
  *
@@ -1273,14 +1296,14 @@ copy_null:      WITH NULL_P AS Sconst			{ $$ = $4; }
  *
  *****************************************************************************/
 
-CreateStmt:  CREATE OptTemp TABLE relation_name '(' OptTableElementList ')' OptInherit OptWithOids
+CreateStmt:  CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' OptInherit OptWithOids
 				{
 					CreateStmt *n = makeNode(CreateStmt);
-					n->relname = $4;
+					$4->istemp = $2;
+					n->relation = $4;
 					n->tableElts = $6;
-					n->inhRelnames = $8;
+					n->inhRelations = $8;
 					n->constraints = NIL;
-					n->istemp = $2;
 					n->hasoids = $9;
 					$$ = (Node *)n;
 				}
@@ -1448,10 +1471,7 @@ ColConstraintElem:
 					n->name = NULL;
 					if (exprIsNullConstant($2))
 					{
-						/*
-						 * DEFAULT NULL should be reported as empty expr
-						 * Required for NOT NULL Domain overrides
-						 */
+						/* DEFAULT NULL should be reported as empty expr */
 						n->raw_expr = NULL;
 					}
 					else
@@ -1462,11 +1482,11 @@ ColConstraintElem:
 					n->keys = NULL;
 					$$ = (Node *)n;
 				}
-			| REFERENCES ColId opt_column_list key_match key_actions 
+			| REFERENCES qualified_name opt_column_list key_match key_actions 
 				{
 					FkConstraint *n = makeNode(FkConstraint);
 					n->constr_name		= NULL;
-					n->pktable_name		= $2;
+					n->pktable			= $2;
 					n->fk_attrs			= NIL;
 					n->pk_attrs			= $3;
 					n->match_type		= $4;
@@ -1573,12 +1593,12 @@ ConstraintElem:  CHECK '(' a_expr ')'
 					n->keys = $4;
 					$$ = (Node *)n;
 				}
-		| FOREIGN KEY '(' columnList ')' REFERENCES ColId opt_column_list
+		| FOREIGN KEY '(' columnList ')' REFERENCES qualified_name opt_column_list
 				key_match key_actions ConstraintAttributeSpec
 				{
 					FkConstraint *n = makeNode(FkConstraint);
 					n->constr_name		= NULL;
-					n->pktable_name		= $7;
+					n->pktable			= $7;
 					n->fk_attrs			= $4;
 					n->pk_attrs			= $8;
 					n->match_type		= $9;
@@ -1589,6 +1609,24 @@ ConstraintElem:  CHECK '(' a_expr ')'
 				}
 		;
 
+opt_column_list:  '(' columnList ')'			{ $$ = $2; }
+		| /*EMPTY*/								{ $$ = NIL; }
+		;
+
+columnList:  columnList ',' columnElem
+				{ $$ = lappend($1, $3); }
+		| columnElem
+				{ $$ = makeList1($1); }
+		;
+
+columnElem:  ColId
+				{
+					Ident *id = makeNode(Ident);
+					id->name = $1;
+					$$ = (Node *)id;
+				}
+		;
+
 key_match:  MATCH FULL
 			{
 				$$ = "FULL";
@@ -1624,7 +1662,7 @@ key_reference:  NO ACTION				{ $$ = FKCONSTR_ON_KEY_NOACTION; }
 		| SET DEFAULT					{ $$ = FKCONSTR_ON_KEY_SETDEFAULT; }
 		;
 
-OptInherit:  INHERITS '(' relation_name_list ')'	{ $$ = $3; }
+OptInherit:  INHERITS '(' qualified_name_list ')'	{ $$ = $3; }
 		| /*EMPTY*/									{ $$ = NIL; }
 		;
 
@@ -1639,7 +1677,7 @@ OptWithOids:  WITH OIDS						{ $$ = TRUE; }
  * SELECT ... INTO.
  */
 
-CreateAsStmt:  CREATE OptTemp TABLE relation_name OptCreateAs AS SelectStmt
+CreateAsStmt:  CREATE OptTemp TABLE qualified_name OptCreateAs AS SelectStmt
 				{
 					/*
 					 * When the SelectStmt is a set-operation tree, we must
@@ -1651,7 +1689,7 @@ CreateAsStmt:  CREATE OptTemp TABLE relation_name OptCreateAs AS SelectStmt
 					SelectStmt *n = findLeftmostSelect((SelectStmt *) $7);
 					if (n->into != NULL)
 						elog(ERROR,"CREATE TABLE AS may not specify INTO");
-					n->istemp = $2;
+					$4->istemp = $2;
 					n->into = $4;
 					n->intoColNames = $5;
 					$$ = $7;
@@ -1687,11 +1725,11 @@ CreateAsElement:  ColId
  *
  *****************************************************************************/
 
-CreateSeqStmt:  CREATE OptTemp SEQUENCE relation_name OptSeqList
+CreateSeqStmt:  CREATE OptTemp SEQUENCE qualified_name OptSeqList
 				{
 					CreateSeqStmt *n = makeNode(CreateSeqStmt);
-					n->istemp = $2;
-					n->seqname = $4;
+					$4->istemp = $2;
+					n->sequence = $4;
 					n->options = $5;
 					$$ = (Node *)n;
 				}
@@ -1742,6 +1780,7 @@ OptSeqElem:  CACHE NumericOnly
 
 NumericOnly:  FloatOnly					{ $$ = $1; }
 			| IntegerOnly				{ $$ = $1; }
+		;
 
 FloatOnly:  FCONST
 				{
@@ -1791,6 +1830,7 @@ opt_trusted:  TRUSTED			{ $$ = TRUE; }
 
 opt_lancompiler: LANCOMPILER Sconst { $$ = $2; }
 			| /*EMPTY*/			{ $$ = ""; }
+		;
 
 DropPLangStmt:  DROP opt_procedural LANGUAGE ColId_or_Sconst
 			{
@@ -1813,12 +1853,12 @@ opt_procedural: PROCEDURAL		{ $$ = TRUE; }
  *****************************************************************************/
 
 CreateTrigStmt:  CREATE TRIGGER name TriggerActionTime TriggerEvents ON
-				relation_name TriggerForSpec EXECUTE PROCEDURE
+				qualified_name TriggerForSpec EXECUTE PROCEDURE
 				name '(' TriggerFuncArgs ')'
 				{
 					CreateTrigStmt *n = makeNode(CreateTrigStmt);
 					n->trigname = $3;
-					n->relname = $7;
+					n->relation = $7;
 					n->funcname = $11;
 					n->args = $13;
 					n->before = $4;
@@ -1832,17 +1872,17 @@ CreateTrigStmt:  CREATE TRIGGER name TriggerActionTime TriggerEvents ON
 					n->isconstraint  = FALSE;
 					n->deferrable    = FALSE;
 					n->initdeferred  = FALSE;
-					n->constrrelname = NULL;
+					n->constrrel = NULL;
 					$$ = (Node *)n;
 				}
 		| CREATE CONSTRAINT TRIGGER name AFTER TriggerEvents ON
-				relation_name OptConstrFromTable 
+				qualified_name OptConstrFromTable 
 				ConstraintAttributeSpec
 				FOR EACH ROW EXECUTE PROCEDURE name '(' TriggerFuncArgs ')'
 				{
 					CreateTrigStmt *n = makeNode(CreateTrigStmt);
 					n->trigname = $4;
-					n->relname = $8;
+					n->relation = $8;
 					n->funcname = $16;
 					n->args = $18;
 					n->before = FALSE;
@@ -1857,7 +1897,7 @@ CreateTrigStmt:  CREATE TRIGGER name TriggerActionTime TriggerEvents ON
 					n->deferrable = ($10 & 1) != 0;
 					n->initdeferred = ($10 & 2) != 0;
 
-					n->constrrelname = $9;
+					n->constrrel = $9;
 					$$ = (Node *)n;
 				}
 		;
@@ -1937,9 +1977,9 @@ TriggerFuncArg:  ICONST
 
 OptConstrFromTable:			/* Empty */
 				{
-					$$ = "";
+					$$ = NULL;
 				}
-		| FROM relation_name
+		| FROM qualified_name
 				{
 					$$ = $2;
 				}
@@ -1983,11 +2023,11 @@ ConstraintTimeSpec: INITIALLY IMMEDIATE
 		;
 
 
-DropTrigStmt:  DROP TRIGGER name ON relation_name
+DropTrigStmt:  DROP TRIGGER name ON qualified_name
 				{
 					DropTrigStmt *n = makeNode(DropTrigStmt);
 					n->trigname = $3;
-					n->relname = $5;
+					n->relation = $5;
 					$$ = (Node *) n;
 				}
 		;
@@ -2063,11 +2103,14 @@ def_arg:  func_return  					{  $$ = (Node *)$1; }
  *
  *****************************************************************************/
 
-DropStmt:  DROP drop_type name_list opt_drop_behavior
+/* DropStmt needs to use qualified_name_list as many of the objects
+ * are relations or other schema objects (names can be schema-qualified) */
+ 
+DropStmt:  DROP drop_type qualified_name_list opt_drop_behavior
 				{
 					DropStmt *n = makeNode(DropStmt);
 					n->removeType = $2;
-					n->names = $3;
+					n->objects = $3;
 					n->behavior = $4;
 					$$ = (Node *)n;
 				}
@@ -2089,10 +2132,10 @@ drop_type: TABLE								{ $$ = DROP_TABLE; }
  *
  *****************************************************************************/
 
-TruncateStmt:  TRUNCATE opt_table relation_name
+TruncateStmt:  TRUNCATE opt_table qualified_name
 				{
 					TruncateStmt *n = makeNode(TruncateStmt);
-					n->relName = $3;
+					n->relation = $3;
 					$$ = (Node *)n;
 				}
 			;
@@ -2120,20 +2163,41 @@ CommentStmt:	COMMENT ON comment_type name IS comment_text
 				n->comment = $6;
 				$$ = (Node *) n;
 			}
-		| COMMENT ON COLUMN relation_name '.' attr_name IS comment_text
+		| COMMENT ON COLUMN ColId '.' attr_name IS comment_text
 			{
+				/*
+				 * We can't use qualified_name here as the '.' causes a shift/red; 
+				 * with ColId we do not test for NEW and OLD as table names, but it is OK
+				 * as they would fail anyway as COMMENT cannot appear in a RULE.
+				 * ColumnRef is also innapropriate as we don't take subscripts
+				 * or '*' and have a very precise number of elements (2 or 3)
+				 * so we do it from scratch.
+				 */
 				CommentStmt *n = makeNode(CommentStmt);
 				n->objtype = COLUMN;
+				n->objschema = NULL;
 				n->objname = $4;
 				n->objproperty = $6;
 				n->objlist = NULL;
 				n->comment = $8;
 				$$ = (Node *) n;
 			}
+		| COMMENT ON COLUMN ColId '.' ColId '.' attr_name IS comment_text
+			{
+				CommentStmt *n = makeNode(CommentStmt);
+				n->objtype = COLUMN;
+				n->objschema = $4;
+				n->objname = $6;
+				n->objproperty = $8;
+				n->objlist = NULL;
+				n->comment = $10;
+				$$ = (Node *) n;
+			}
 		| COMMENT ON AGGREGATE name '(' aggr_argtype ')' IS comment_text
 			{
 				CommentStmt *n = makeNode(CommentStmt);
 				n->objtype = AGGREGATE;
+				n->objschema = NULL;
 				n->objname = $4;
 				n->objproperty = NULL;
 				n->objlist = makeList1($6);
@@ -2145,6 +2209,7 @@ CommentStmt:	COMMENT ON comment_type name IS comment_text
 				/* Obsolete syntax, but must support for awhile */
 				CommentStmt *n = makeNode(CommentStmt);
 				n->objtype = AGGREGATE;
+				n->objschema = NULL;
 				n->objname = $4;
 				n->objproperty = NULL;
 				n->objlist = makeList1($5);
@@ -2155,6 +2220,7 @@ CommentStmt:	COMMENT ON comment_type name IS comment_text
 			{
 				CommentStmt *n = makeNode(CommentStmt);
 				n->objtype = FUNCTION;
+				n->objschema = NULL;
 				n->objname = $4;
 				n->objproperty = NULL;
 				n->objlist = $5;
@@ -2165,18 +2231,21 @@ CommentStmt:	COMMENT ON comment_type name IS comment_text
 			{
 				CommentStmt *n = makeNode(CommentStmt);
 				n->objtype = OPERATOR;
+				n->objschema = NULL;
 				n->objname = $4;
 				n->objproperty = NULL;
 				n->objlist = $6;
 				n->comment = $9;
 				$$ = (Node *) n;
 			}
-		| COMMENT ON TRIGGER name ON relation_name IS comment_text
+		| COMMENT ON TRIGGER name ON qualified_name IS comment_text
 			{
 				CommentStmt *n = makeNode(CommentStmt);
 				n->objtype = TRIGGER;
+				/* NOTE: schemaname here refers to the table in objproperty */
+				n->objschema = $6->schemaname;
 				n->objname = $4;
-				n->objproperty = $6;
+				n->objproperty = $6->relname;
 				n->objlist = NULL;
 				n->comment = $8;
 				$$ = (Node *) n;
@@ -2414,14 +2483,14 @@ privilege: SELECT    { $$ = SELECT; }
 
 /* Don't bother trying to fold the first two rules into one using
    opt_table.  You're going to get conflicts. */
-privilege_target: relation_name_list
+privilege_target: qualified_name_list
 				{
 					PrivTarget *n = makeNode(PrivTarget);
 					n->objtype = TABLE;
 					n->objs = $1;
 					$$ = n;
 				}
-			| TABLE relation_name_list
+			| TABLE qualified_name_list
 				{
 					PrivTarget *n = makeNode(PrivTarget);
 					n->objtype = TABLE;
@@ -2513,13 +2582,13 @@ function_with_argtypes: func_name func_args
  *
  *****************************************************************************/
 
-IndexStmt:	CREATE index_opt_unique INDEX index_name ON relation_name
+IndexStmt:	CREATE index_opt_unique INDEX index_name ON qualified_name
 			access_method_clause '(' index_params ')' where_clause
 				{
 					IndexStmt *n = makeNode(IndexStmt);
 					n->unique = $2;
 					n->idxname = $4;
-					n->relname = $6;
+					n->relation = $6;
 					n->accessMethod = $7;
 					n->indexParams = $9;
 					n->whereClause = $11;
@@ -2783,11 +2852,21 @@ oper_argtypes:	Typename
  *
  *****************************************************************************/
 
-ReindexStmt:  REINDEX reindex_type name opt_force
+ReindexStmt:  REINDEX reindex_type qualified_name opt_force
 				{
 					ReindexStmt *n = makeNode(ReindexStmt);
 					n->reindexType = $2;
+					n->relation = $3;
+					n->name = NULL;
+					n->force = $4;
+					$$ = (Node *)n;
+				}
+		| REINDEX DATABASE name opt_force
+				{
+					ReindexStmt *n = makeNode(ReindexStmt);
+					n->reindexType = DATABASE;
 					n->name = $3;
+					n->relation = NULL;
 					n->force = $4;
 					$$ = (Node *)n;
 				}
@@ -2795,8 +2874,8 @@ ReindexStmt:  REINDEX reindex_type name opt_force
 
 reindex_type:  INDEX								{  $$ = INDEX; }
 		| TABLE										{  $$ = TABLE; }
-		| DATABASE									{  $$ = DATABASE; }
 		;
+
 opt_force:	FORCE									{  $$ = TRUE; }
 		| /* EMPTY */								{  $$ = FALSE; }
 		;
@@ -2813,8 +2892,7 @@ opt_force:	FORCE									{  $$ = TRUE; }
 RenameStmt:  ALTER TABLE relation_expr RENAME opt_column opt_name TO name
 				{
 					RenameStmt *n = makeNode(RenameStmt);
-					n->relname = $3->relname;
-					n->inhOpt = $3->inhOpt;
+					n->relation = $3;
 					n->column = $6;
 					n->newname = $8;
 					$$ = (Node *)n;
@@ -2832,23 +2910,20 @@ opt_column:  COLUMN						{ $$ = COLUMN; }
 
 /*****************************************************************************
  *
- *		QUERY:	Define Rewrite Rule , Define Tuple Rule
- *				Define Rule <old rules >
- *
- *		only rewrite rule is supported -- ay 9/94
+ *		QUERY:	Define Rewrite Rule
  *
  *****************************************************************************/
 
 RuleStmt:  CREATE RULE name AS
 		   { QueryIsRule=TRUE; }
-		   ON event TO event_object where_clause
+		   ON event TO qualified_name where_clause
 		   DO opt_instead RuleActionList
 				{
 					RuleStmt *n = makeNode(RuleStmt);
+					n->relation = $9;
 					n->rulename = $3;
-					n->event = $7;
-					n->object = $9;
 					n->whereClause = $10;
+					n->event = $7;
 					n->instead = $12;
 					n->actions = $13;
 					$$ = (Node *)n;
@@ -2888,24 +2963,6 @@ RuleActionStmtOrEmpty:	RuleActionStmt
 				{ $$ = (Node *)NULL; }
 		;
 
-event_object:  relation_name '.' attr_name
-				{
-					$$ = makeNode(Attr);
-					$$->relname = $1;
-					$$->paramNo = NULL;
-					$$->attrs = makeList1(makeString($3));
-					$$->indirection = NIL;
-				}
-		| relation_name
-				{
-					$$ = makeNode(Attr);
-					$$->relname = $1;
-					$$->paramNo = NULL;
-					$$->attrs = NIL;
-					$$->indirection = NIL;
-				}
-		;
-
 /* change me to select, update, etc. some day */
 event:	SELECT							{ $$ = CMD_SELECT; }
 		| UPDATE						{ $$ = CMD_UPDATE; }
@@ -2921,40 +2978,42 @@ opt_instead:  INSTEAD					{ $$ = TRUE; }
 /*****************************************************************************
  *
  *		QUERY:
- *				NOTIFY <relation_name>	can appear both in rule bodies and
+ *				NOTIFY <qualified_name>	can appear both in rule bodies and
  *				as a query-level command
  *
  *****************************************************************************/
 
-NotifyStmt:  NOTIFY relation_name
+NotifyStmt:  NOTIFY qualified_name
 				{
 					NotifyStmt *n = makeNode(NotifyStmt);
-					n->relname = $2;
+					n->relation = $2;
 					$$ = (Node *)n;
 				}
 		;
 
-ListenStmt:  LISTEN relation_name
+ListenStmt:  LISTEN qualified_name
 				{
 					ListenStmt *n = makeNode(ListenStmt);
-					n->relname = $2;
+					n->relation = $2;
 					$$ = (Node *)n;
 				}
-;
+		;
 
-UnlistenStmt:  UNLISTEN relation_name
+UnlistenStmt:  UNLISTEN qualified_name
 				{
 					UnlistenStmt *n = makeNode(UnlistenStmt);
-					n->relname = $2;
+					n->relation = $2;
 					$$ = (Node *)n;
 				}
 		| UNLISTEN '*'
 				{
 					UnlistenStmt *n = makeNode(UnlistenStmt);
-					n->relname = "*";
+					n->relation = makeNode(RangeVar);
+					n->relation->relname = "*";
+					n->relation->schemaname = NULL;
 					$$ = (Node *)n;
 				}
-;
+		;
 
 
 /*****************************************************************************
@@ -3036,10 +3095,10 @@ opt_chain: AND NO CHAIN
  *
  *****************************************************************************/
 
-ViewStmt:  CREATE VIEW name opt_column_list AS SelectStmt
+ViewStmt:  CREATE VIEW qualified_name opt_column_list AS SelectStmt
 				{
 					ViewStmt *n = makeNode(ViewStmt);
-					n->viewname = $3;
+					n->view = $3;
 					n->aliases = $4;
 					n->query = (Query *) $6;
 					$$ = (Node *)n;
@@ -3067,7 +3126,6 @@ LoadStmt:  LOAD file_name
  *
  *		CREATE DATABASE
  *
- *
  *****************************************************************************/
 
 CreatedbStmt:  CREATE DATABASE database_name WITH createdb_opt_list
@@ -3190,21 +3248,6 @@ opt_equal: '='								{ $$ = TRUE; }
 		;
 
 
-/*****************************************************************************
- *
- *		DROP DATABASE
- *
- *****************************************************************************/
-
-DropdbStmt:	DROP DATABASE database_name
-				{
-					DropdbStmt *n = makeNode(DropdbStmt);
-					n->dbname = $3;
-					$$ = (Node *)n;
-				}
-		;
-
-
 /*****************************************************************************
  *
  *		ALTER DATABASE
@@ -3229,10 +3272,25 @@ AlterDatabaseSetStmt: ALTER DATABASE database_name VariableSetStmt
 				}
 		;
 
+
 /*****************************************************************************
  *
- * Manipulate a domain
+ *		DROP DATABASE
+ *
+ *****************************************************************************/
+
+DropdbStmt:	DROP DATABASE database_name
+				{
+					DropdbStmt *n = makeNode(DropdbStmt);
+					n->dbname = $3;
+					$$ = (Node *)n;
+				}
+		;
+
+
+/*****************************************************************************
  *
+ * Manipulate a domain
  *
  *****************************************************************************/
 
@@ -3254,17 +3312,18 @@ opt_as:	AS	{$$ = TRUE; }
 	| /* EMPTY */	{$$ = FALSE; }
 	;
 
+
 /*****************************************************************************
  *
  *		QUERY:
- *				cluster <index_name> on <relation_name>
+ *				cluster <index_name> on <qualified_name>
  *
  *****************************************************************************/
 
-ClusterStmt:  CLUSTER index_name ON relation_name
+ClusterStmt:  CLUSTER index_name ON qualified_name
 				{
 				   ClusterStmt *n = makeNode(ClusterStmt);
-				   n->relname = $4;
+				   n->relation = $4;
 				   n->indexname = $2;
 				   $$ = (Node*)n;
 				}
@@ -3286,11 +3345,11 @@ VacuumStmt:  VACUUM opt_full opt_freeze opt_verbose
 					n->full = $2;
 					n->freeze = $3;
 					n->verbose = $4;
-					n->vacrel = NULL;
+					n->relation = NULL;
 					n->va_cols = NIL;
 					$$ = (Node *)n;
 				}
-		| VACUUM opt_full opt_freeze opt_verbose relation_name
+		| VACUUM opt_full opt_freeze opt_verbose qualified_name
 				{
 					VacuumStmt *n = makeNode(VacuumStmt);
 					n->vacuum = true;
@@ -3298,7 +3357,7 @@ VacuumStmt:  VACUUM opt_full opt_freeze opt_verbose
 					n->full = $2;
 					n->freeze = $3;
 					n->verbose = $4;
-					n->vacrel = $5;
+					n->relation = $5;
 					n->va_cols = NIL;
 					$$ = (Node *)n;
 				}
@@ -3321,11 +3380,11 @@ AnalyzeStmt:  analyze_keyword opt_verbose
 					n->full = false;
 					n->freeze = false;
 					n->verbose = $2;
-					n->vacrel = NULL;
+					n->relation = NULL;
 					n->va_cols = NIL;
 					$$ = (Node *)n;
 				}
-		| analyze_keyword opt_verbose relation_name opt_name_list
+		| analyze_keyword opt_verbose qualified_name opt_name_list
 				{
 					VacuumStmt *n = makeNode(VacuumStmt);
 					n->vacuum = false;
@@ -3333,7 +3392,7 @@ AnalyzeStmt:  analyze_keyword opt_verbose
 					n->full = false;
 					n->freeze = false;
 					n->verbose = $2;
-					n->vacrel = $3;
+					n->relation = $3;
 					n->va_cols = $4;
 					$$ = (Node *)n;
 				}
@@ -3413,15 +3472,9 @@ OptimizableStmt:  SelectStmt
  *
  *****************************************************************************/
 
-/* This rule used 'opt_column_list' between 'relation_name' and 'insert_rest'
- * originally. When the second rule of 'insert_rest' was changed to use the
- * new 'SelectStmt' rule (for INTERSECT and EXCEPT) it produced a shift/reduce
- * conflict. So I just changed the rules 'InsertStmt' and 'insert_rest' to
- * accept the same statements without any shift/reduce conflicts
- */
-InsertStmt:  INSERT INTO relation_name insert_rest
+InsertStmt:  INSERT INTO qualified_name insert_rest
 				{
- 					$4->relname = $3;
+ 					$4->relation = $3;
 					$$ = (Node *) $4;
 				}
 		;
@@ -3447,14 +3500,14 @@ insert_rest:  VALUES '(' target_list ')'
 					$$->targetList = NIL;
 					$$->selectStmt = $1;
 				}
-		| '(' columnList ')' VALUES '(' target_list ')'
+		| '(' insert_column_list ')' VALUES '(' target_list ')'
 				{
 					$$ = makeNode(InsertStmt);
 					$$->cols = $2;
 					$$->targetList = $6;
 					$$->selectStmt = NULL;
 				}
-		| '(' columnList ')' SelectStmt
+		| '(' insert_column_list ')' SelectStmt
 				{
 					$$ = makeNode(InsertStmt);
 					$$->cols = $2;
@@ -3463,22 +3516,19 @@ insert_rest:  VALUES '(' target_list ')'
 				}
 		;
 
-opt_column_list:  '(' columnList ')'			{ $$ = $2; }
-		| /*EMPTY*/								{ $$ = NIL; }
-		;
-
-columnList:  columnList ',' columnElem
+insert_column_list:  insert_column_list ',' insert_column_item
 				{ $$ = lappend($1, $3); }
-		| columnElem
+		| insert_column_item
 				{ $$ = makeList1($1); }
 		;
 
-columnElem:  ColId opt_indirection
+insert_column_item:  ColId opt_indirection
 				{
-					Ident *id = makeNode(Ident);
-					id->name = $1;
-					id->indirection = $2;
-					$$ = (Node *)id;
+					ResTarget *n = makeNode(ResTarget);
+					n->name = $1;
+					n->indirection = $2;
+					n->val = NULL;
+					$$ = (Node *)n;
 				}
 		;
 
@@ -3493,18 +3543,17 @@ columnElem:  ColId opt_indirection
 DeleteStmt:  DELETE FROM relation_expr where_clause
 				{
 					DeleteStmt *n = makeNode(DeleteStmt);
-					n->relname = $3->relname;
-					n->inhOpt = $3->inhOpt;
+					n->relation = $3;
 					n->whereClause = $4;
 					$$ = (Node *)n;
 				}
 		;
 
-LockStmt:	LOCK_P opt_table relation_name_list opt_lock
+LockStmt:	LOCK_P opt_table qualified_name_list opt_lock
 				{
 					LockStmt *n = makeNode(LockStmt);
 
-					n->rellist = $3;
+					n->relations = $3;
 					n->mode = $4;
 					$$ = (Node *)n;
 				}
@@ -3538,8 +3587,7 @@ UpdateStmt:  UPDATE relation_expr
 			  where_clause
 				{
 					UpdateStmt *n = makeNode(UpdateStmt);
-					n->relname = $2->relname;
-					n->inhOpt = $2->inhOpt;
+					n->relation = $2;
 					n->targetList = $4;
 					n->fromClause = $5;
 					n->whereClause = $6;
@@ -3687,8 +3735,7 @@ simple_select: SELECT opt_distinct target_list
 					SelectStmt *n = makeNode(SelectStmt);
 					n->distinctClause = $2;
 					n->targetList = $3;
-					n->istemp = (bool) ((Value *) lfirst($4))->val.ival;
-					n->into = (char *) lnext($4);
+					n->into = $4;
 					n->intoColNames = NIL;
 					n->fromClause = $5;
 					n->whereClause = $6;
@@ -3710,40 +3757,56 @@ simple_select: SELECT opt_distinct target_list
 			}
 		; 
 
-		/* easy way to return two values. Can someone improve this?  bjm */
 into_clause:  INTO OptTempTableName		{ $$ = $2; }
-		| /*EMPTY*/						{ $$ = makeList1(makeInteger(FALSE)); }
+		| /*EMPTY*/		{ $$ = NULL; }
 		;
 
 /*
  * Redundancy here is needed to avoid shift/reduce conflicts,
  * since TEMP is not a reserved word.  See also OptTemp.
- *
- * The result is a cons cell (not a true list!) containing
- * a boolean and a table name.
  */
-OptTempTableName:  TEMPORARY opt_table relation_name
-				{ $$ = lcons(makeInteger(TRUE), (List *) $3); }
-			| TEMP opt_table relation_name
-				{ $$ = lcons(makeInteger(TRUE), (List *) $3); }
-			| LOCAL TEMPORARY opt_table relation_name
-				{ $$ = lcons(makeInteger(TRUE), (List *) $4); }
-			| LOCAL TEMP opt_table relation_name
-				{ $$ = lcons(makeInteger(TRUE), (List *) $4); }
-			| GLOBAL TEMPORARY opt_table relation_name
+OptTempTableName:  TEMPORARY opt_table qualified_name
+				{ 
+					$$ = $3;
+					$$->istemp = true;
+				}
+			| TEMP opt_table qualified_name
+				{ 
+					$$ = $3;
+					$$->istemp = true;
+				}
+			| LOCAL TEMPORARY opt_table qualified_name
+				{ 
+					$$ = $4;
+					$$->istemp = true;
+				}
+			| LOCAL TEMP opt_table qualified_name
+				{ 
+					$$ = $4;
+					$$->istemp = true;
+				}
+			| GLOBAL TEMPORARY opt_table qualified_name
 				{
 					elog(ERROR, "GLOBAL TEMPORARY TABLE is not currently supported");
-					$$ = lcons(makeInteger(TRUE), (List *) $4);
+					$$ = $4;
+					$$->istemp = true;
 				}
-			| GLOBAL TEMP opt_table relation_name
+			| GLOBAL TEMP opt_table qualified_name
 				{
 					elog(ERROR, "GLOBAL TEMPORARY TABLE is not currently supported");
-					$$ = lcons(makeInteger(TRUE), (List *) $4);
+					$$ = $4;
+					$$->istemp = true;
+				}
+			| TABLE qualified_name
+				{ 
+					$$ = $2;
+					$$->istemp = false;
+				}
+			| qualified_name
+				{ 
+					$$ = $1;
+					$$->istemp = false;
 				}
-			| TABLE relation_name
-				{ $$ = lcons(makeInteger(FALSE), (List *) $2); }
-			| relation_name
-				{ $$ = lcons(makeInteger(FALSE), (List *) $1); }
 		;
 
 opt_table:  TABLE								{ $$ = TRUE; }
@@ -3878,13 +3941,6 @@ select_offset_value:	Iconst
  *	...however, recursive addattr and rename supported.  make special
  *	cases for these.
  */
-relation_name_list:  name_list;
-
-name_list:  name
-				{	$$ = makeList1(makeString($1)); }
-		| name_list ',' name
-				{	$$ = lappend($1, makeString($3)); }
-		;
 
 group_clause:  GROUP BY expr_list				{ $$ = $3; }
 		| /*EMPTY*/								{ $$ = NIL; }
@@ -3938,7 +3994,7 @@ table_ref:  relation_expr
 				}
 		| relation_expr alias_clause
 				{
-					$1->name = $2;
+					$1->alias = $2;
 					$$ = (Node *) $1;
 				}
 		| select_with_parens
@@ -3962,7 +4018,7 @@ table_ref:  relation_expr
 				{
 					RangeSubselect *n = makeNode(RangeSubselect);
 					n->subquery = $1;
-					n->name = $2;
+					n->alias = $2;
 					$$ = (Node *) n;
 				}
 		| joined_table
@@ -4077,25 +4133,25 @@ joined_table:  '(' joined_table ')'
 
 alias_clause:  AS ColId '(' name_list ')'
 				{
-					$$ = makeNode(Attr);
-					$$->relname = $2;
-					$$->attrs = $4;
+					$$ = makeNode(Alias);
+					$$->aliasname = $2;
+					$$->colnames = $4;
 				}
 		| AS ColId
 				{
-					$$ = makeNode(Attr);
-					$$->relname = $2;
+					$$ = makeNode(Alias);
+					$$->aliasname = $2;
 				}
 		| ColId '(' name_list ')'
 				{
-					$$ = makeNode(Attr);
-					$$->relname = $1;
-					$$->attrs = $3;
+					$$ = makeNode(Alias);
+					$$->aliasname = $1;
+					$$->colnames = $3;
 				}
 		| ColId
 				{
-					$$ = makeNode(Attr);
-					$$->relname = $1;
+					$$ = makeNode(Alias);
+					$$->aliasname = $1;
 				}
 		;
 
@@ -4124,29 +4180,26 @@ join_qual:  USING '(' name_list ')'				{ $$ = (Node *) $3; }
 		;
 
 
-relation_expr:	relation_name
+relation_expr:	qualified_name
 				{
 					/* default inheritance */
-					$$ = makeNode(RangeVar);
-					$$->relname = $1;
+					$$ = $1;
 					$$->inhOpt = INH_DEFAULT;
-					$$->name = NULL;
+					$$->alias = NULL;
 				}
-		| relation_name '*'
+		| qualified_name '*'
 				{
 					/* inheritance query */
-					$$ = makeNode(RangeVar);
-					$$->relname = $1;
+					$$ = $1;
 					$$->inhOpt = INH_YES;
-					$$->name = NULL;
+					$$->alias = NULL;
 				}
-		| ONLY relation_name
+		| ONLY qualified_name
 				{
 					/* no inheritance */
-					$$ = makeNode(RangeVar);
-					$$->relname = $2;
+					$$ = $2;
 					$$->inhOpt = INH_NO;
-					$$->name = NULL;
+					$$->alias = NULL;
                 }
 		;
 
@@ -4357,6 +4410,7 @@ bit:  BIT opt_varying
 					else type = xlateSqlType("bit");
 					$$ = type;
 				}
+		;
 
 
 /*
@@ -5010,20 +5064,32 @@ b_expr:  c_expr
  * inside parentheses, such as function arguments; that cannot introduce
  * ambiguity to the b_expr syntax.
  */
-c_expr:  attr
+c_expr:  columnref
 				{	$$ = (Node *) $1;  }
-		| ColId opt_indirection
+		| AexprConst
+				{	$$ = $1;  }
+		| PARAM attrs opt_indirection
 				{
-					/* could be a column name or a relation_name */
-					Ident *n = makeNode(Ident);
-					n->name = $1;
-					n->indirection = $2;
+					/*
+					 * PARAM without field names is considered a constant,
+					 * but with 'em, it is not.  Not very consistent ...
+					 */
+					ParamRef *n = makeNode(ParamRef);
+					n->number = $1;
+					n->fields = $2;
+					n->indirection = $3;
 					$$ = (Node *)n;
 				}
-		| AexprConst
-				{	$$ = $1;  }
 		| '(' a_expr ')'
 				{	$$ = $2; }
+		| '(' a_expr ')' attrs opt_indirection
+				{
+					ExprFieldSelect *n = makeNode(ExprFieldSelect);
+					n->arg = $2;
+					n->fields = $4;
+					n->indirection = $5;
+					$$ = (Node *)n;
+				}
 		| CAST '(' a_expr AS Typename ')'
 				{	$$ = makeTypeCast($3, $5); }
 		| case_expr
@@ -5569,34 +5635,40 @@ case_arg:  a_expr
 				{	$$ = NULL; }
 		;
 
-attr:  relation_name '.' attrs opt_indirection
+/*
+ * columnref starts with relation_name not ColId, so that OLD and NEW
+ * references can be accepted.  Note that when there are more than two
+ * dotted names, the first name is not actually a relation name...
+ */
+columnref: relation_name opt_indirection
 				{
-					$$ = makeNode(Attr);
-					$$->relname = $1;
-					$$->paramNo = NULL;
-					$$->attrs = $3;
-					$$->indirection = $4;
+					$$ = makeNode(ColumnRef);
+					$$->fields = makeList1(makeString($1));
+					$$->indirection = $2;
 				}
-		| ParamNo '.' attrs opt_indirection
+		| relation_name attrs opt_indirection
 				{
-					$$ = makeNode(Attr);
-					$$->relname = NULL;
-					$$->paramNo = $1;
-					$$->attrs = $3;
-					$$->indirection = $4;
+					$$ = makeNode(ColumnRef);
+					$$->fields = lcons(makeString($1), $2);
+					$$->indirection = $3;
 				}
 		;
 
-attrs:	  attr_name
-				{ $$ = makeList1(makeString($1)); }
-		| attrs '.' attr_name
+attrs:	  opt_attrs '.' attr_name
 				{ $$ = lappend($1, makeString($3)); }
-		| attrs '.' '*'
+		| opt_attrs '.' '*'
 				{ $$ = lappend($1, makeString("*")); }
 		;
 
+opt_attrs: /*EMPTY*/
+				{ $$ = NIL; }
+		| opt_attrs '.' attr_name
+				{ $$ = lappend($1, makeString($3)); }
+		;
+
 opt_empty_parentheses: '(' ')' { $$ = TRUE; }
 					| /*EMPTY*/ { $$ = TRUE; }
+		;
 
 /*****************************************************************************
  *
@@ -5617,39 +5689,25 @@ target_el:  a_expr AS ColLabel
 				{
 					$$ = makeNode(ResTarget);
 					$$->name = $3;
-					$$->indirection = NULL;
+					$$->indirection = NIL;
 					$$->val = (Node *)$1;
 				}
 		| a_expr
 				{
 					$$ = makeNode(ResTarget);
 					$$->name = NULL;
-					$$->indirection = NULL;
+					$$->indirection = NIL;
 					$$->val = (Node *)$1;
 				}
-		| relation_name '.' '*'
-				{
-					Attr *att = makeNode(Attr);
-					att->relname = $1;
-					att->paramNo = NULL;
-					att->attrs = makeList1(makeString("*"));
-					att->indirection = NIL;
-					$$ = makeNode(ResTarget);
-					$$->name = NULL;
-					$$->indirection = NULL;
-					$$->val = (Node *)att;
-				}
 		| '*'
 				{
-					Attr *att = makeNode(Attr);
-					att->relname = "*";
-					att->paramNo = NULL;
-					att->attrs = NULL;
-					att->indirection = NIL;
+					ColumnRef *n = makeNode(ColumnRef);
+					n->fields = makeList1(makeString("*"));
+					n->indirection = NIL;
 					$$ = makeNode(ResTarget);
 					$$->name = NULL;
-					$$->indirection = NULL;
-					$$->val = (Node *)att;
+					$$->indirection = NIL;
+					$$->val = (Node *)n;
 				}
 		;
 
@@ -5685,6 +5743,42 @@ relation_name:	SpecialRuleRelation
 					$$ = $1;
 				}
 		;
+		
+qualified_name_list:  qualified_name
+				{	$$ = makeList1($1); }
+		| qualified_name_list ',' qualified_name
+				{	$$ = lappend($1, $3); }
+		;
+
+qualified_name: ColId
+				{
+					$$ = makeNode(RangeVar);
+					$$->catalogname = NULL;
+					$$->schemaname = NULL;
+					$$->relname = $1;
+				}
+		| ColId '.' ColId
+				{
+					$$ = makeNode(RangeVar);
+					$$->catalogname = NULL;
+					$$->schemaname = $1;
+					$$->relname = $3;
+				}
+		| ColId '.' ColId '.' ColId
+				{
+					$$ = makeNode(RangeVar);
+					$$->catalogname = $1;
+					$$->schemaname = $3;
+					$$->relname = $5;
+				}
+		;
+
+name_list:  name
+				{	$$ = makeList1(makeString($1)); }
+		| name_list ',' name
+				{	$$ = lappend($1, makeString($3)); }
+		;
+
 
 name:					ColId			{ $$ = $1; };
 database_name:			ColId			{ $$ = $1; };
@@ -5761,8 +5855,14 @@ AexprConst:  Iconst
 
 					$$ = (Node *)n;
 				}
-		| ParamNo
-				{	$$ = (Node *)$1;  }
+		| PARAM opt_indirection
+				{
+					ParamRef *n = makeNode(ParamRef);
+					n->number = $1;
+					n->fields = NIL;
+					n->indirection = $2;
+					$$ = (Node *)n;
+				}
 		| TRUE_P
 				{
 					A_Const *n = makeNode(A_Const);
@@ -5791,14 +5891,6 @@ AexprConst:  Iconst
 				}
 		;
 
-ParamNo:  PARAM opt_indirection
-				{
-					$$ = makeNode(ParamNo);
-					$$->number = $1;
-					$$->indirection = $2;
-				}
-		;
-
 Iconst:  ICONST							{ $$ = $1; };
 Sconst:  SCONST							{ $$ = $1; };
 UserId:  ColId							{ $$ = $1; };
@@ -5866,7 +5958,6 @@ unreserved_keyword:
 		| AGGREGATE						{ $$ = "aggregate"; }
 		| ALTER							{ $$ = "alter"; }
 		| AT							{ $$ = "at"; }
-		| AUTHORIZATION					{ $$ = "authorization"; }
 		| BACKWARD						{ $$ = "backward"; }
 		| BEFORE						{ $$ = "before"; }
 		| BEGIN_TRANS					{ $$ = "begin"; }
@@ -5883,7 +5974,6 @@ unreserved_keyword:
 		| COMMITTED						{ $$ = "committed"; }
 		| CONSTRAINTS					{ $$ = "constraints"; }
 		| COPY							{ $$ = "copy"; }
-		| CREATE						{ $$ = "create"; }
 		| CREATEDB						{ $$ = "createdb"; }
 		| CREATEUSER					{ $$ = "createuser"; }
 		| CURSOR						{ $$ = "cursor"; }
@@ -5909,7 +5999,6 @@ unreserved_keyword:
 		| FORWARD						{ $$ = "forward"; }
 		| FUNCTION						{ $$ = "function"; }
 		| GLOBAL						{ $$ = "global"; }
-		| GRANT							{ $$ = "grant"; }
 		| HANDLER						{ $$ = "handler"; }
 		| HOUR_P						{ $$ = "hour"; }
 		| IMMEDIATE						{ $$ = "immediate"; }
@@ -6061,7 +6150,8 @@ col_name_keyword:
  *  - thomas 2000-11-28
  */
 func_name_keyword:
-		  BETWEEN						{ $$ = "between"; }
+		  AUTHORIZATION					{ $$ = "authorization"; }
+		| BETWEEN						{ $$ = "between"; }
 		| BINARY						{ $$ = "binary"; }
 		| CROSS							{ $$ = "cross"; }
 		| FREEZE						{ $$ = "freeze"; }
@@ -6104,6 +6194,7 @@ reserved_keyword:
 		| COLLATE						{ $$ = "collate"; }
 		| COLUMN						{ $$ = "column"; }
 		| CONSTRAINT					{ $$ = "constraint"; }
+		| CREATE						{ $$ = "create"; }
 		| CURRENT_DATE					{ $$ = "current_date"; }
 		| CURRENT_TIME					{ $$ = "current_time"; }
 		| CURRENT_TIMESTAMP				{ $$ = "current_timestamp"; }
@@ -6120,6 +6211,7 @@ reserved_keyword:
 		| FOR							{ $$ = "for"; }
 		| FOREIGN						{ $$ = "foreign"; }
 		| FROM							{ $$ = "from"; }
+		| GRANT							{ $$ = "grant"; }
 		| GROUP							{ $$ = "group"; }
 		| HAVING						{ $$ = "having"; }
 		| INITIALLY						{ $$ = "initially"; }
@@ -6189,7 +6281,7 @@ static Node *
 makeTypeCast(Node *arg, TypeName *typename)
 {
 	/*
-	 * If arg is an A_Const or ParamNo, just stick the typename into the
+	 * If arg is an A_Const, just stick the typename into the
 	 * field reserved for it --- unless there's something there already!
 	 * (We don't want to collapse x::type1::type2 into just x::type2.)
 	 * Otherwise, generate a TypeCast node.
@@ -6200,12 +6292,6 @@ makeTypeCast(Node *arg, TypeName *typename)
 		((A_Const *) arg)->typename = typename;
 		return arg;
 	}
-	else if (IsA(arg, ParamNo) &&
-			 ((ParamNo *) arg)->typename == NULL)
-	{
-		((ParamNo *) arg)->typename = typename;
-		return arg;
-	}
 	else
 	{
 		TypeCast *n = makeNode(TypeCast);
diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c
index d6ad0a07ea12a6dbf31a7ac7813a5791e09b3d83..dc939a71801e129102ab62bd44bf5dbf35e7fec6 100644
--- a/src/backend/parser/parse_agg.c
+++ b/src/backend/parser/parse_agg.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.46 2001/10/25 05:49:36 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.47 2002/03/21 16:00:58 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -116,7 +116,7 @@ check_ungrouped_columns_walker(Node *node,
 		rte = rt_fetch(var->varno, context->pstate->p_rtable);
 		attname = get_rte_attribute_name(rte, var->varattno);
 		elog(ERROR, "Attribute %s.%s must be GROUPed or used in an aggregate function",
-			 rte->eref->relname, attname);
+			 rte->eref->aliasname, attname);
 	}
 	/* Otherwise, recurse. */
 	return expression_tree_walker(node, check_ungrouped_columns_walker,
@@ -188,8 +188,7 @@ parseCheckAggregates(ParseState *pstate, Query *qry, Node *qual)
 
 Aggref *
 ParseAgg(ParseState *pstate, char *aggname, Oid basetype,
-		 List *args, bool agg_star, bool agg_distinct,
-		 int precedence)
+		 List *args, bool agg_star, bool agg_distinct)
 {
 	HeapTuple	aggtuple;
 	Form_pg_aggregate aggform;
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index 2f1eda4a9bf1502bdaf1b331f5fd754295792209..6e8868f8ea680e6591054f3b0213906b83cb9bb6 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.84 2002/03/12 00:51:54 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.85 2002/03/21 16:00:59 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -285,7 +285,7 @@ transformJoinUsingClause(ParseState *pstate, List *leftVars, List *rightVars)
 	 * transformJoinOnClause() does.  Just invoke transformExpr() to fix
 	 * up the operators, and we're done.
 	 */
-	result = transformExpr(pstate, result, EXPR_COLUMN_FIRST);
+	result = transformExpr(pstate, result);
 
 	/*
 	 * We expect the result to yield bool directly, otherwise complain. We
@@ -326,7 +326,7 @@ transformJoinOnClause(ParseState *pstate, JoinExpr *j,
 	pstate->p_namespace = makeList2(j->larg, j->rarg);
 
 	/* This part is just like transformWhereClause() */
-	result = transformExpr(pstate, j->quals, EXPR_COLUMN_FIRST);
+	result = transformExpr(pstate, j->quals);
 
 	if (!coerce_to_boolean(pstate, &result))
 		elog(ERROR, "JOIN/ON clause must return type boolean, not type %s",
@@ -350,7 +350,7 @@ transformJoinOnClause(ParseState *pstate, JoinExpr *j,
 		if (!intMember(varno, containedRels))
 		{
 			elog(ERROR, "JOIN/ON clause refers to \"%s\", which is not part of JOIN",
-				 rt_fetch(varno, pstate->p_rtable)->eref->relname);
+				 rt_fetch(varno, pstate->p_rtable)->eref->aliasname);
 		}
 	}
 	freeList(clause_varnos);
@@ -375,7 +375,7 @@ transformTableEntry(ParseState *pstate, RangeVar *r)
 	 * automatically generate the range variable if not specified. However
 	 * there are times we need to know whether the entries are legitimate.
 	 */
-	rte = addRangeTableEntry(pstate, relname, r->name,
+	rte = addRangeTableEntry(pstate, relname, r->alias,
 							 interpretInhOption(r->inhOpt), true);
 
 	/*
@@ -408,7 +408,7 @@ transformRangeSubselect(ParseState *pstate, RangeSubselect *r)
 	 * relax this, we'd have to be prepared to gin up a unique alias for
 	 * an unlabeled subselect.
 	 */
-	if (r->name == NULL)
+	if (r->alias == NULL)
 		elog(ERROR, "sub-select in FROM must have an alias");
 
 	/*
@@ -444,7 +444,7 @@ transformRangeSubselect(ParseState *pstate, RangeSubselect *r)
 	/*
 	 * OK, build an RTE for the subquery.
 	 */
-	rte = addRangeTableEntryForSubquery(pstate, query, r->name, true);
+	rte = addRangeTableEntryForSubquery(pstate, query, r->alias, true);
 
 	/*
 	 * We create a RangeTblRef, but we do not add it to the joinlist or
@@ -748,11 +748,11 @@ transformFromClauseItem(ParseState *pstate, Node *n, List **containedRels)
 		 */
 		if (j->alias)
 		{
-			if (j->alias->attrs != NIL)
+			if (j->alias->colnames != NIL)
 			{
-				if (length(j->alias->attrs) > length(res_colnames))
+				if (length(j->alias->colnames) > length(res_colnames))
 					elog(ERROR, "Column alias list for \"%s\" has too many entries",
-						 j->alias->relname);
+						 j->alias->aliasname);
 			}
 		}
 
@@ -791,7 +791,7 @@ transformWhereClause(ParseState *pstate, Node *clause)
 	if (clause == NULL)
 		return NULL;
 
-	qual = transformExpr(pstate, clause, EXPR_COLUMN_FIRST);
+	qual = transformExpr(pstate, clause);
 
 	if (!coerce_to_boolean(pstate, &qual))
 		elog(ERROR, "WHERE clause must return type boolean, not type %s",
@@ -858,9 +858,11 @@ findTargetlistEntry(ParseState *pstate, Node *node, List *tlist, int clause)
 	 * an expression.
 	 *----------
 	 */
-	if (IsA(node, Ident) &&((Ident *) node)->indirection == NIL)
+	if (IsA(node, ColumnRef) &&
+		length(((ColumnRef *) node)->fields) == 1 &&
+		((ColumnRef *) node)->indirection == NIL)
 	{
-		char	   *name = ((Ident *) node)->name;
+		char	   *name = strVal(lfirst(((ColumnRef *) node)->fields));
 
 		if (clause == GROUP_CLAUSE)
 		{
@@ -934,7 +936,7 @@ findTargetlistEntry(ParseState *pstate, Node *node, List *tlist, int clause)
 	 * willing to match a resjunk target here, though the above cases must
 	 * ignore resjunk targets.
 	 */
-	expr = transformExpr(pstate, node, EXPR_COLUMN_FIRST);
+	expr = transformExpr(pstate, node);
 
 	foreach(tl, tlist)
 	{
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 6409ef3226a0f5725dad09cad950425d1f696cc4..73cd89fd3d84ae31b25bc9edaf651db6e51b1b8e 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.110 2002/03/20 19:44:25 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.111 2002/03/21 16:01:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -17,6 +17,7 @@
 
 #include "catalog/pg_operator.h"
 #include "catalog/pg_proc.h"
+#include "miscadmin.h"
 #include "nodes/makefuncs.h"
 #include "nodes/params.h"
 #include "parser/analyze.h"
@@ -41,8 +42,7 @@ bool		Transform_null_equals = false;
 static Node *parser_typecast_constant(Value *expr, TypeName *typename);
 static Node *parser_typecast_expression(ParseState *pstate,
 						   Node *expr, TypeName *typename);
-static Node *transformAttr(ParseState *pstate, Attr *att, int precedence);
-static Node *transformIdent(ParseState *pstate, Ident *ident, int precedence);
+static Node *transformColumnRef(ParseState *pstate, ColumnRef *cref);
 static Node *transformIndirection(ParseState *pstate, Node *basenode,
 					 List *indirection);
 
@@ -85,7 +85,7 @@ parse_expr_init(void)
  * input and output of transformExpr; see SubLink for example.
  */
 Node *
-transformExpr(ParseState *pstate, Node *expr, int precedence)
+transformExpr(ParseState *pstate, Node *expr)
 {
 	Node	   *result = NULL;
 
@@ -105,9 +105,37 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
 
 	switch (nodeTag(expr))
 	{
-		case T_Attr:
+		case T_ColumnRef:
 			{
-				result = transformAttr(pstate, (Attr *) expr, precedence);
+				result = transformColumnRef(pstate, (ColumnRef *) expr);
+				break;
+			}
+		case T_ParamRef:
+			{
+				ParamRef   *pref = (ParamRef *) expr;
+				int			paramno = pref->number;
+				Oid			paramtyp = param_type(paramno);
+				Param	   *param;
+				List	   *fields;
+
+				if (!OidIsValid(paramtyp))
+					elog(ERROR, "Parameter '$%d' is out of range", paramno);
+				param = makeNode(Param);
+				param->paramkind = PARAM_NUM;
+				param->paramid = (AttrNumber) paramno;
+				param->paramname = "<unnamed>";
+				param->paramtype = paramtyp;
+				result = (Node *) param;
+				/* handle qualification, if any */
+				foreach(fields, pref->fields)
+				{
+					result = ParseFuncOrColumn(pstate, strVal(lfirst(fields)),
+											   makeList1(result),
+											   false, false, true);
+				}
+				/* handle subscripts, if any */
+				result = transformIndirection(pstate, result,
+											  pref->indirection);
 				break;
 			}
 		case T_A_Const:
@@ -121,31 +149,28 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
 					result = (Node *) make_const(val);
 				break;
 			}
-		case T_ParamNo:
+		case T_ExprFieldSelect:
 			{
-				ParamNo    *pno = (ParamNo *) expr;
-				int			paramno = pno->number;
-				Oid			toid = param_type(paramno);
-				Param	   *param = makeNode(Param);
+				ExprFieldSelect *efs = (ExprFieldSelect *) expr;
+				List	   *fields;
 
-				if (!OidIsValid(toid))
-					elog(ERROR, "Parameter '$%d' is out of range", paramno);
-				param->paramkind = PARAM_NUM;
-				param->paramid = (AttrNumber) paramno;
-				param->paramname = "<unnamed>";
-				param->paramtype = toid;
-				result = transformIndirection(pstate, (Node *) param,
-											  pno->indirection);
-				/* cope with typecast applied to param */
-				if (pno->typename != NULL)
-					result = parser_typecast_expression(pstate, result,
-														pno->typename);
+				result = transformExpr(pstate, efs->arg);
+				/* handle qualification, if any */
+				foreach(fields, efs->fields)
+				{
+					result = ParseFuncOrColumn(pstate, strVal(lfirst(fields)),
+											   makeList1(result),
+											   false, false, true);
+				}
+				/* handle subscripts, if any */
+				result = transformIndirection(pstate, result,
+											  efs->indirection);
 				break;
 			}
 		case T_TypeCast:
 			{
 				TypeCast   *tc = (TypeCast *) expr;
-				Node	   *arg = transformExpr(pstate, tc->arg, precedence);
+				Node	   *arg = transformExpr(pstate, tc->arg);
 
 				result = parser_typecast_expression(pstate, arg, tc->typename);
 				break;
@@ -179,17 +204,14 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
 									n->arg = a->lexpr;
 
 								result = transformExpr(pstate,
-													   (Node *) n,
-													   precedence);
+													   (Node *) n);
 							}
 							else
 							{
 								Node	   *lexpr = transformExpr(pstate,
-																a->lexpr,
-															 precedence);
+																a->lexpr);
 								Node	   *rexpr = transformExpr(pstate,
-																a->rexpr,
-															 precedence);
+																a->rexpr);
 
 								result = (Node *) make_op(a->opname,
 														  lexpr,
@@ -200,11 +222,9 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
 					case AND:
 						{
 							Node	   *lexpr = transformExpr(pstate,
-															  a->lexpr,
-															  precedence);
+															  a->lexpr);
 							Node	   *rexpr = transformExpr(pstate,
-															  a->rexpr,
-															  precedence);
+															  a->rexpr);
 							Expr	   *expr = makeNode(Expr);
 
 							if (!coerce_to_boolean(pstate, &lexpr))
@@ -226,11 +246,9 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
 					case OR:
 						{
 							Node	   *lexpr = transformExpr(pstate,
-															  a->lexpr,
-															  precedence);
+															  a->lexpr);
 							Node	   *rexpr = transformExpr(pstate,
-															  a->rexpr,
-															  precedence);
+															  a->rexpr);
 							Expr	   *expr = makeNode(Expr);
 
 							if (!coerce_to_boolean(pstate, &lexpr))
@@ -252,8 +270,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
 					case NOT:
 						{
 							Node	   *rexpr = transformExpr(pstate,
-															  a->rexpr,
-															  precedence);
+															  a->rexpr);
 							Expr	   *expr = makeNode(Expr);
 
 							if (!coerce_to_boolean(pstate, &rexpr))
@@ -270,11 +287,6 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
 				}
 				break;
 			}
-		case T_Ident:
-			{
-				result = transformIdent(pstate, (Ident *) expr, precedence);
-				break;
-			}
 		case T_FuncCall:
 			{
 				FuncCall   *fn = (FuncCall *) expr;
@@ -283,14 +295,13 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
 				/* transform the list of arguments */
 				foreach(args, fn->args)
 					lfirst(args) = transformExpr(pstate,
-												 (Node *) lfirst(args),
-												 precedence);
+												 (Node *) lfirst(args));
 				result = ParseFuncOrColumn(pstate,
 										   fn->funcname,
 										   fn->args,
 										   fn->agg_star,
 										   fn->agg_distinct,
-										   precedence);
+										   false);
 				break;
 			}
 		case T_SubLink:
@@ -357,8 +368,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
 					List	   *elist;
 
 					foreach(elist, left_list)
-						lfirst(elist) = transformExpr(pstate, lfirst(elist),
-													  precedence);
+						lfirst(elist) = transformExpr(pstate, lfirst(elist));
 
 					Assert(IsA(sublink->oper, A_Expr));
 					op = ((A_Expr *) sublink->oper)->opname;
@@ -455,7 +465,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
 						a->rexpr = warg;
 						warg = (Node *) a;
 					}
-					neww->expr = transformExpr(pstate, warg, precedence);
+					neww->expr = transformExpr(pstate, warg);
 
 					if (!coerce_to_boolean(pstate, &neww->expr))
 						elog(ERROR, "WHEN clause must have a boolean result");
@@ -472,7 +482,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
 						n->val.type = T_Null;
 						warg = (Node *) n;
 					}
-					neww->result = transformExpr(pstate, warg, precedence);
+					neww->result = transformExpr(pstate, warg);
 
 					newargs = lappend(newargs, neww);
 					typeids = lappendi(typeids, exprType(neww->result));
@@ -496,7 +506,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
 					n->val.type = T_Null;
 					defresult = (Node *) n;
 				}
-				newc->defresult = transformExpr(pstate, defresult, precedence);
+				newc->defresult = transformExpr(pstate, defresult);
 
 				/*
 				 * Note: default result is considered the most significant
@@ -534,7 +544,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
 			{
 				NullTest   *n = (NullTest *) expr;
 
-				n->arg = transformExpr(pstate, n->arg, precedence);
+				n->arg = transformExpr(pstate, n->arg);
 				/* the argument can be any type, so don't coerce it */
 				result = expr;
 				break;
@@ -544,7 +554,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
 			{
 				BooleanTest *b = (BooleanTest *) expr;
 
-				b->arg = transformExpr(pstate, b->arg, precedence);
+				b->arg = transformExpr(pstate, b->arg);
 
 				if (!coerce_to_boolean(pstate, &b->arg))
 				{
@@ -627,47 +637,183 @@ transformIndirection(ParseState *pstate, Node *basenode, List *indirection)
 }
 
 static Node *
-transformAttr(ParseState *pstate, Attr *att, int precedence)
+transformColumnRef(ParseState *pstate, ColumnRef *cref)
 {
-	Node	   *basenode;
+	int			numnames = length(cref->fields);
+	Node	   *node;
+	RangeVar   *rv;
+
+	/*----------
+	 * The allowed syntaxes are:
+	 *
+	 * A		First try to resolve as unqualified column name;
+	 *			if no luck, try to resolve as unqual. table name (A.*).
+	 * A.B		A is an unqual. table name; B is either a
+	 *			column or function name (trying column name first).
+	 * A.B.C	schema A, table B, col or func name C.
+	 * A.B.C.D	catalog A, schema B, table C, col or func D.
+	 * A.*		A is an unqual. table name; means whole-row value.
+	 * A.B.*	whole-row value of table B in schema A.
+	 * A.B.C.*	whole-row value of table C in schema B in catalog A.
+	 *
+	 * We do not need to cope with bare "*"; that will only be accepted by
+	 * the grammar at the top level of a SELECT list, and transformTargetList
+	 * will take care of it before it ever gets here.
+	 *
+	 * Currently, if a catalog name is given then it must equal the current
+	 * database name; we check it here and then discard it.
+	 *
+	 * For whole-row references, the result is an untransformed RangeVar,
+	 * which will work as the argument to a function call, but not in any
+	 * other context at present.  (We could instead coerce to a whole-row Var,
+	 * but that will fail for subselect and join RTEs, because there is no
+	 * pg_type entry for their rowtypes.)
+	 *----------
+	 */
+	switch (numnames)
+	{
+		case 1:
+		{
+			char   *name = strVal(lfirst(cref->fields));
 
-	basenode = ParseNestedFuncOrColumn(pstate, att, precedence);
-	return transformIndirection(pstate, basenode, att->indirection);
-}
+			/* Try to identify as an unqualified column */
+			node = colnameToVar(pstate, name);
+			if (node == NULL)
+			{
+				/*
+				 * Not known as a column of any range-table entry, so
+				 * try to find the name as a relation ... but not if
+				 * subscripts appear.  Note also that only relations
+				 * already entered into the rangetable will be recognized.
+				 */
+				int		levels_up;
 
-static Node *
-transformIdent(ParseState *pstate, Ident *ident, int precedence)
-{
-	Node	   *result = NULL;
-	int			sublevels_up;
+				if (cref->indirection == NIL &&
+					refnameRangeTblEntry(pstate, name, &levels_up) != NULL)
+				{
+					rv = makeNode(RangeVar);
+					rv->relname = name;
+					rv->inhOpt = INH_DEFAULT;
+					node = (Node *) rv;
+				}
+				else
+					elog(ERROR, "Attribute \"%s\" not found", name);
+			}
+			break;
+		}
+		case 2:
+		{
+			char   *name1 = strVal(lfirst(cref->fields));
+			char   *name2 = strVal(lsecond(cref->fields));
 
-	/*
-	 * try to find the ident as a relation ... but not if subscripts
-	 * appear
-	 */
-	if (ident->indirection == NIL &&
-		refnameRangeTblEntry(pstate, ident->name, &sublevels_up) != NULL)
-	{
-		ident->isRel = TRUE;
-		result = (Node *) ident;
-	}
+			/* Whole-row reference? */
+			if (strcmp(name2, "*") == 0)
+			{
+				rv = makeNode(RangeVar);
+				rv->relname = name1;
+				rv->inhOpt = INH_DEFAULT;
+				node = (Node *) rv;
+				break;
+			}
 
-	if (result == NULL || precedence == EXPR_COLUMN_FIRST)
-	{
-		/* try to find the ident as a column */
-		Node	   *var = colnameToVar(pstate, ident->name);
+			/* Try to identify as a once-qualified column */
+			node = qualifiedNameToVar(pstate, name1, name2, true);
+			if (node == NULL)
+			{
+				/*
+				 * Not known as a column of any range-table entry, so
+				 * try it as a function call.  Here, we will create an
+				 * implicit RTE for tables not already entered.
+				 */
+				rv = makeNode(RangeVar);
+				rv->relname = name1;
+				rv->inhOpt = INH_DEFAULT;
+				node = ParseFuncOrColumn(pstate, name2,
+										 makeList1(rv),
+										 false, false, true);
+			}
+			break;
+		}
+		case 3:
+		{
+			char   *name1 = strVal(lfirst(cref->fields));
+			char   *name2 = strVal(lsecond(cref->fields));
+			char   *name3 = strVal(lfirst(lnext(lnext(cref->fields))));
 
-		if (var != NULL)
+			/* Whole-row reference? */
+			if (strcmp(name3, "*") == 0)
+			{
+				rv = makeNode(RangeVar);
+				rv->schemaname = name1;
+				rv->relname = name2;
+				rv->inhOpt = INH_DEFAULT;
+				node = (Node *) rv;
+				break;
+			}
+
+			/* Try to identify as a twice-qualified column */
+			/* XXX do something with schema name here */
+			node = qualifiedNameToVar(pstate, name2, name3, true);
+			if (node == NULL)
+			{
+				/* Try it as a function call */
+				rv = makeNode(RangeVar);
+				rv->schemaname = name1;
+				rv->relname = name2;
+				rv->inhOpt = INH_DEFAULT;
+				node = ParseFuncOrColumn(pstate, name3,
+										 makeList1(rv),
+										 false, false, true);
+			}
+			break;
+		}
+		case 4:
 		{
-			ident->isRel = FALSE;
-			result = transformIndirection(pstate, var, ident->indirection);
+			char   *name1 = strVal(lfirst(cref->fields));
+			char   *name2 = strVal(lsecond(cref->fields));
+			char   *name3 = strVal(lfirst(lnext(lnext(cref->fields))));
+			char   *name4 = strVal(lfirst(lnext(lnext(lnext(cref->fields)))));
+
+			/*
+			 * We check the catalog name and then ignore it.
+			 */
+			if (strcmp(name1, DatabaseName) != 0)
+				elog(ERROR, "Cross-database references are not implemented");
+
+			/* Whole-row reference? */
+			if (strcmp(name4, "*") == 0)
+			{
+				rv = makeNode(RangeVar);
+				rv->schemaname = name2;
+				rv->relname = name3;
+				rv->inhOpt = INH_DEFAULT;
+				node = (Node *) rv;
+				break;
+			}
+
+			/* Try to identify as a twice-qualified column */
+			/* XXX do something with schema name here */
+			node = qualifiedNameToVar(pstate, name3, name4, true);
+			if (node == NULL)
+			{
+				/* Try it as a function call */
+				rv = makeNode(RangeVar);
+				rv->schemaname = name2;
+				rv->relname = name3;
+				rv->inhOpt = INH_DEFAULT;
+				node = ParseFuncOrColumn(pstate, name4,
+										 makeList1(rv),
+										 false, false, true);
+			}
+			break;
 		}
+		default:
+			elog(ERROR, "Invalid qualified name syntax (too many names)");
+			node = NULL;		/* keep compiler quiet */
+			break;
 	}
 
-	if (result == NULL)
-		elog(ERROR, "Attribute '%s' not found", ident->name);
-
-	return result;
+	return transformIndirection(pstate, node, cref->indirection);
 }
 
 /*
@@ -748,10 +894,6 @@ exprType(Node *expr)
 		case T_BooleanTest:
 			type = BOOLOID;
 			break;
-		case T_Ident:
-			/* XXX is this right? */
-			type = UNKNOWNOID;
-			break;
 		default:
 			elog(ERROR, "Do not know how to get type for %d node",
 				 nodeTag(expr));
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index 6dc7b440fa87e9e488d59bc9b2b30e391d8b83a7..ee1bf6c057874949de7747a9fb7f754ee9d538a4 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -8,11 +8,10 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.118 2002/03/20 19:44:29 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.119 2002/03/21 16:01:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
-
 #include "postgres.h"
 
 #include "access/genam.h"
@@ -36,8 +35,7 @@
 
 static Node *ParseComplexProjection(ParseState *pstate,
 					   char *funcname,
-					   Node *first_arg,
-					   bool *attisset);
+					   Node *first_arg);
 static Oid **argtype_inherit(int nargs, Oid *argtypes);
 
 static int	find_inheritors(Oid relid, Oid **supervec);
@@ -60,75 +58,31 @@ static Oid	agg_select_candidate(Oid typeid, CandidateList candidates);
 
 
 /*
- ** ParseNestedFuncOrColumn
- **    Given a nested dot expression (i.e. (relation func ... attr), build up
- ** a tree with of Iter and Func nodes.
- */
-Node *
-ParseNestedFuncOrColumn(ParseState *pstate, Attr *attr, int precedence)
-{
-	List	   *mutator_iter;
-	Node	   *retval = NULL;
-
-	if (attr->paramNo != NULL)
-	{
-		Param	   *param = (Param *) transformExpr(pstate,
-												  (Node *) attr->paramNo,
-													EXPR_RELATION_FIRST);
-
-		retval = ParseFuncOrColumn(pstate, strVal(lfirst(attr->attrs)),
-								   makeList1(param),
-								   false, false,
-								   precedence);
-	}
-	else
-	{
-		Ident	   *ident = makeNode(Ident);
-
-		ident->name = attr->relname;
-		ident->isRel = TRUE;
-		retval = ParseFuncOrColumn(pstate, strVal(lfirst(attr->attrs)),
-								   makeList1(ident),
-								   false, false,
-								   precedence);
-	}
-
-	/* Do more attributes follow this one? */
-	foreach(mutator_iter, lnext(attr->attrs))
-	{
-		retval = ParseFuncOrColumn(pstate, strVal(lfirst(mutator_iter)),
-								   makeList1(retval),
-								   false, false,
-								   precedence);
-	}
-
-	return retval;
-}
-
-/*
- *	parse function
- *
- *	This code is confusing because the database can accept
- *	relation.column, column.function, or relation.column.function.
- *	In these cases, funcname is the last parameter, and fargs are
- *	the rest.
+ *	Parse a function call
  *
- *	It can also be called as func(col) or func(col,col).
- *	In this case, Funcname is the part before parens, and fargs
- *	are the part in parens.
+ *	For historical reasons, Postgres tries to treat the notations tab.col
+ *	and col(tab) as equivalent: if a single-argument function call has an
+ *	argument of complex type and the function name matches any attribute
+ *	of the type, we take it as a column projection.
  *
- *	FYI, projection is choosing column from a table.
+ *	Hence, both cases come through here.  The is_column parameter tells us
+ *	which syntactic construct is actually being dealt with, but this is
+ *	intended to be used only to deliver an appropriate error message,
+ *	not to affect the semantics.  When is_column is true, we should have
+ *	a single argument (the putative table), function name equal to the
+ *	column name, and no aggregate decoration.
  *
+ *	In the function-call case, the argument expressions have been transformed
+ *	already.  In the column case, we may get either a transformed expression
+ *	or a RangeVar node as argument.
  */
 Node *
 ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
-				  bool agg_star, bool agg_distinct,
-				  int precedence)
+				  bool agg_star, bool agg_distinct, bool is_column)
 {
-	Oid			rettype = InvalidOid;
-	Oid			argrelid = InvalidOid;
-	Oid			funcid = InvalidOid;
-	List	   *i = NIL;
+	Oid			rettype;
+	Oid			funcid;
+	List	   *i;
 	Node	   *first_arg = NULL;
 	char	   *refname;
 	int			nargs = length(fargs);
@@ -140,9 +94,8 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
 	bool		retset;
 	bool		must_be_agg = agg_star || agg_distinct;
 	bool		could_be_agg;
-	bool		attisset = false;
-	Oid			toid = InvalidOid;
 	Expr	   *expr;
+	FuncDetailCode fdresult;
 
 	/*
 	 * Most of the rest of the parser just assumes that functions do not
@@ -157,33 +110,26 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
 	if (fargs)
 	{
 		first_arg = lfirst(fargs);
-		if (first_arg == NULL)
+		if (first_arg == NULL)	/* should not happen */
 			elog(ERROR, "Function '%s' does not allow NULL input", funcname);
 	}
 
 	/*
-	 * test for relation.column
-	 *
-	 * check for projection methods: if function takes one argument, and that
-	 * argument is a relation, param, or PQ function returning a complex *
-	 * type, then the function could be a projection.
+	 * check for column projection: if function has one argument, and that
+	 * argument is of complex type, then the function could be a projection.
 	 */
 	/* We only have one parameter, and it's not got aggregate decoration */
 	if (nargs == 1 && !must_be_agg)
 	{
-		/* Is it a plain Relation name from the parser? */
-		if (IsA(first_arg, Ident) &&((Ident *) first_arg)->isRel)
+		/* Is it a not-yet-transformed RangeVar node? */
+		if (IsA(first_arg, RangeVar))
 		{
-			Ident	   *ident = (Ident *) first_arg;
-
 			/* First arg is a relation. This could be a projection. */
-			refname = ident->name;
+			refname = ((RangeVar *) first_arg)->relname;
 
 			retval = qualifiedNameToVar(pstate, refname, funcname, true);
 			if (retval)
 				return retval;
-
-			/* else drop through - attr is a set or function */
 		}
 		else if (ISCOMPLEX(exprType(first_arg)))
 		{
@@ -194,24 +140,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
 			 */
 			retval = ParseComplexProjection(pstate,
 											funcname,
-											first_arg,
-											&attisset);
-			if (attisset)
-			{
-				toid = exprType(first_arg);
-				argrelid = typeidTypeRelid(toid);
-				if (argrelid == InvalidOid)
-					elog(ERROR, "Type '%s' is not a relation type",
-						 typeidTypeName(toid));
-
-				/*
-				 * A projection must match an attribute name of the rel.
-				 */
-				if (get_attnum(argrelid, funcname) == InvalidAttrNumber)
-					elog(ERROR, "No such attribute or function '%s'",
-						 funcname);
-			}
-
+											first_arg);
 			if (retval)
 				return retval;
 		}
@@ -226,15 +155,14 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
 		if (nargs != 1)
 			elog(ERROR, "Aggregate functions may only have one parameter");
 		/* Agg's argument can't be a relation name, either */
-		if (IsA(first_arg, Ident) &&((Ident *) first_arg)->isRel)
+		if (IsA(first_arg, RangeVar))
 			elog(ERROR, "Aggregate functions cannot be applied to relation names");
 		could_be_agg = true;
 	}
 	else
 	{
 		/* Try to parse as an aggregate if above-mentioned checks are OK */
-		could_be_agg = (nargs == 1) &&
-			!(IsA(first_arg, Ident) &&((Ident *) first_arg)->isRel);
+		could_be_agg = (nargs == 1) && !(IsA(first_arg, RangeVar));
 	}
 
 	if (could_be_agg)
@@ -249,8 +177,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
 								 ObjectIdGetDatum(basetype),
 								 0, 0))
 			return (Node *) ParseAgg(pstate, funcname, basetype,
-									 fargs, agg_star, agg_distinct,
-									 precedence);
+									 fargs, agg_star, agg_distinct);
 
 		/* check for aggregate-that-accepts-any-type (eg, COUNT) */
 		if (SearchSysCacheExists(AGGNAME,
@@ -258,8 +185,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
 								 ObjectIdGetDatum(0),
 								 0, 0))
 			return (Node *) ParseAgg(pstate, funcname, 0,
-									 fargs, agg_star, agg_distinct,
-									 precedence);
+									 fargs, agg_star, agg_distinct);
 
 		/*
 		 * No exact match yet, so see if there is another entry in the
@@ -277,8 +203,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
 											basetype, type, -1);
 				basetype = type;
 				return (Node *) ParseAgg(pstate, funcname, basetype,
-										 fargs, agg_star, agg_distinct,
-										 precedence);
+										 fargs, agg_star, agg_distinct);
 			}
 			else
 			{
@@ -300,10 +225,9 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
 	}
 
 	/*
-	 * If we dropped through to here it's really a function (or a set,
-	 * which is implemented as a function). Extract arg type info and
-	 * transform relation name arguments into varnodes of the appropriate
-	 * form.
+	 * Okay, it's not a column projection, so it must really be a function.
+	 * Extract arg type info and transform RangeVar arguments into varnodes
+	 * of the appropriate form.
 	 */
 	MemSet(oid_array, 0, FUNC_MAX_ARGS * sizeof(Oid));
 
@@ -311,8 +235,9 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
 	foreach(i, fargs)
 	{
 		Node	   *arg = lfirst(i);
+		Oid			toid;
 
-		if (IsA(arg, Ident) &&((Ident *) arg)->isRel)
+		if (IsA(arg, RangeVar))
 		{
 			RangeTblEntry *rte;
 			int			vnum;
@@ -321,7 +246,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
 			/*
 			 * a relation
 			 */
-			refname = ((Ident *) arg)->name;
+			refname = ((RangeVar *) arg)->relname;
 
 			rte = refnameRangeTblEntry(pstate, refname,
 									   &sublevels_up);
@@ -346,16 +271,9 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
 				 * RTE is a join or subselect; must fail for lack of a
 				 * named tuple type
 				 */
-				if (nargs == 1)
-				{
-					/*
-					 * Here, we probably have an unrecognized attribute of
-					 * a sub-select; again can't tell if it was x.f or
-					 * f(x)
-					 */
-					elog(ERROR, "No such attribute or function %s.%s",
+				if (is_column)
+					elog(ERROR, "No such attribute %s.%s",
 						 refname, funcname);
-				}
 				else
 				{
 					elog(ERROR, "Cannot pass result of sub-select or join %s to a function",
@@ -365,93 +283,53 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
 
 			toid = typenameTypeId(rte->relname);
 
-			/* replace it in the arg list */
+			/* replace RangeVar in the arg list */
 			lfirst(i) = makeVar(vnum,
 								InvalidAttrNumber,
 								toid,
 								sizeof(Pointer),
 								sublevels_up);
 		}
-		else if (!attisset)
-			toid = exprType(arg);
 		else
-		{
-			/* if attisset is true, we already set toid for the single arg */
-		}
+			toid = exprType(arg);
 
 		oid_array[argn++] = toid;
 	}
 
 	/*
-	 * Is it a set, or a function?
+	 * func_get_detail looks up the function in the catalogs, does
+	 * disambiguation for polymorphic functions, handles inheritance,
+	 * and returns the funcid and type and set or singleton status of
+	 * the function's return value.  it also returns the true argument
+	 * types to the function.
 	 */
-	if (attisset)
-	{							/* we know all of these fields already */
-
+	fdresult = func_get_detail(funcname, fargs, nargs, oid_array,
+							   &funcid, &rettype, &retset,
+							   &true_oid_array);
+	if (fdresult == FUNCDETAIL_COERCION)
+	{
 		/*
-		 * We create a funcnode with a placeholder function seteval(). At
-		 * runtime, seteval() will execute the function identified by the
-		 * funcid it receives as parameter.
-		 *
-		 * Example: retrieve (emp.mgr.name).  The plan for this will scan the
-		 * emp relation, projecting out the mgr attribute, which is a
-		 * funcid. This function is then called (via seteval()) and "name"
-		 * is projected from its result.
+		 * We can do it as a trivial coercion. coerce_type can handle
+		 * these cases, so why duplicate code...
 		 */
-		funcid = F_SETEVAL;
-		rettype = toid;
-		retset = true;
-		true_oid_array = oid_array;
+		return coerce_type(pstate, lfirst(fargs),
+						   oid_array[0], rettype, -1);
 	}
-	else
+	if (fdresult != FUNCDETAIL_NORMAL)
 	{
-		FuncDetailCode fdresult;
-
 		/*
-		 * func_get_detail looks up the function in the catalogs, does
-		 * disambiguation for polymorphic functions, handles inheritance,
-		 * and returns the funcid and type and set or singleton status of
-		 * the function's return value.  it also returns the true argument
-		 * types to the function.
+		 * Oops.  Time to die.
+		 *
+		 * If we are dealing with the attribute notation rel.function,
+		 * give an error message that is appropriate for that case.
 		 */
-		fdresult = func_get_detail(funcname, fargs, nargs, oid_array,
-								   &funcid, &rettype, &retset,
-								   &true_oid_array);
-		if (fdresult == FUNCDETAIL_COERCION)
-		{
-			/*
-			 * We can do it as a trivial coercion. coerce_type can handle
-			 * these cases, so why duplicate code...
-			 */
-			return coerce_type(pstate, lfirst(fargs),
-							   oid_array[0], rettype, -1);
-		}
-		if (fdresult != FUNCDETAIL_NORMAL)
-		{
-			/*
-			 * Oops.  Time to die.
-			 *
-			 * If there is a single argument of complex type, we might be
-			 * dealing with the PostQuel notation rel.function instead of
-			 * the more usual function(rel).  Give a nonspecific error
-			 * message that will cover both cases.
-			 */
-			if (nargs == 1)
-			{
-				Type		tp = typeidType(oid_array[0]);
-
-				if (typeTypeFlag(tp) == 'c')
-					elog(ERROR, "No such attribute or function '%s'",
-						 funcname);
-				ReleaseSysCache(tp);
-			}
-
-			/* Else generate a detailed complaint */
-			func_error(NULL, funcname, nargs, oid_array,
-					   "Unable to identify a function that satisfies the "
-					   "given argument types"
-					   "\n\tYou may need to add explicit typecasts");
-		}
+		if (is_column)
+			elog(ERROR, "Attribute \"%s\" not found", funcname);
+		/* Else generate a detailed complaint */
+		func_error(NULL, funcname, nargs, oid_array,
+				   "Unable to identify a function that satisfies the "
+				   "given argument types"
+				   "\n\tYou may need to add explicit typecasts");
 	}
 
 	/* got it */
@@ -470,26 +348,12 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
 	expr->args = fargs;
 	retval = (Node *) expr;
 
-	/*
-	 * For sets, we want to project out the desired attribute of the
-	 * tuples.
-	 */
-	if (attisset)
-	{
-		FieldSelect *fselect;
-
-		fselect = setup_field_select(retval, funcname, argrelid);
-		rettype = fselect->resulttype;
-		retval = (Node *) fselect;
-	}
-
 	/*
 	 * if the function returns a set of values, then we need to iterate
 	 * over all the returned values in the executor, so we stick an iter
 	 * node here.  if it returns a singleton, then we don't need the iter
 	 * node.
 	 */
-
 	if (retset)
 	{
 		Iter	   *iter = makeNode(Iter);
@@ -1497,10 +1361,10 @@ make_arguments(ParseState *pstate,
 }
 
 /*
- ** setup_field_select
- **		Build a FieldSelect node that says which attribute to project to.
- **		This routine is called by ParseFuncOrColumn() when we have found
- **		a projection on a function result or parameter.
+ * setup_field_select
+ *		Build a FieldSelect node that says which attribute to project to.
+ *		This routine is called by ParseFuncOrColumn() when we have found
+ *		a projection on a function result or parameter.
  */
 static FieldSelect *
 setup_field_select(Node *input, char *attname, Oid relid)
@@ -1521,18 +1385,31 @@ setup_field_select(Node *input, char *attname, Oid relid)
 /*
  * ParseComplexProjection -
  *	  handles function calls with a single argument that is of complex type.
- *	  This routine returns NULL if it can't handle the projection (eg. sets).
+ *	  If the function call is actually a column projection, return a suitably
+ *	  transformed expression tree.  If not, return NULL.
+ *
+ * NB: argument is expected to be transformed already, ie, not a RangeVar.
  */
 static Node *
 ParseComplexProjection(ParseState *pstate,
 					   char *funcname,
-					   Node *first_arg,
-					   bool *attisset)
+					   Node *first_arg)
 {
-	Oid			argtype;
+	Oid			argtype = exprType(first_arg);
 	Oid			argrelid;
+	AttrNumber	attnum;
 	FieldSelect *fselect;
 
+	argrelid = typeidTypeRelid(argtype);
+	if (!argrelid)
+		return NULL;			/* probably should not happen */
+	attnum = get_attnum(argrelid, funcname);
+	if (attnum == InvalidAttrNumber)
+		return NULL;			/* funcname does not match any column */
+
+	/*
+	 * Check for special cases where we don't want to return a FieldSelect.
+	 */
 	switch (nodeTag(first_arg))
 	{
 		case T_Iter:
@@ -1540,75 +1417,42 @@ ParseComplexProjection(ParseState *pstate,
 				Iter	   *iter = (Iter *) first_arg;
 
 				/*
-				 * If the argument of the Iter returns a tuple, funcname
-				 * may be a projection.  If so, we stick the FieldSelect
+				 * If it's an Iter, we stick the FieldSelect
 				 * *inside* the Iter --- this is klugy, but necessary
 				 * because ExecTargetList() currently does the right thing
 				 * only when the Iter node is at the top level of a
 				 * targetlist item.
+				 *
+				 * XXX Iter should go away altogether...
 				 */
-				argtype = iter->itertype;
-				argrelid = typeidTypeRelid(argtype);
-				if (argrelid &&
-					get_attnum(argrelid, funcname) != InvalidAttrNumber)
-				{
-					fselect = setup_field_select(iter->iterexpr,
-												 funcname, argrelid);
-					iter->iterexpr = (Node *) fselect;
-					iter->itertype = fselect->resulttype;
-					return (Node *) iter;
-				}
+				fselect = setup_field_select(iter->iterexpr,
+											 funcname, argrelid);
+				iter->iterexpr = (Node *) fselect;
+				iter->itertype = fselect->resulttype;
+				return (Node *) iter;
 				break;
 			}
 		case T_Var:
 			{
-				/*
-				 * The argument is a set, so this is either a projection
-				 * or a function call on this set.
-				 */
-				*attisset = true;
-				break;
-			}
-		case T_Expr:
-			{
-				Expr	   *expr = (Expr *) first_arg;
-				Func	   *funcnode;
-
-				if (expr->opType != FUNC_EXPR)
-					break;
+				Var		   *var = (Var *) first_arg;
 
 				/*
-				 * If the argument is a function returning a tuple,
-				 * funcname may be a projection
+				 * If the Var is a whole-row tuple, we can just replace it
+				 * with a simple Var reference.
 				 */
-				funcnode = (Func *) expr->oper;
-				argtype = funcnode->functype;
-				argrelid = typeidTypeRelid(argtype);
-				if (argrelid &&
-					get_attnum(argrelid, funcname) != InvalidAttrNumber)
+				if (var->varattno == InvalidAttrNumber)
 				{
-					fselect = setup_field_select((Node *) expr,
-												 funcname, argrelid);
-					return (Node *) fselect;
-				}
-				break;
-			}
-		case T_Param:
-			{
-				Param	   *param = (Param *) first_arg;
+					Oid		vartype;
+					int32	vartypmod;
 
-				/*
-				 * If the Param is a complex type, this could be a
-				 * projection
-				 */
-				argtype = param->paramtype;
-				argrelid = typeidTypeRelid(argtype);
-				if (argrelid &&
-					get_attnum(argrelid, funcname) != InvalidAttrNumber)
-				{
-					fselect = setup_field_select((Node *) param,
-												 funcname, argrelid);
-					return (Node *) fselect;
+					get_atttypetypmod(argrelid, attnum,
+									  &vartype, &vartypmod);
+
+					return (Node *) makeVar(var->varno,
+											attnum,
+											vartype,
+											vartypmod,
+											var->varlevelsup);
 				}
 				break;
 			}
@@ -1616,7 +1460,9 @@ ParseComplexProjection(ParseState *pstate,
 			break;
 	}
 
-	return NULL;
+	/* Else generate a FieldSelect expression */
+	fselect = setup_field_select(first_arg, funcname, argrelid);
+	return (Node *) fselect;
 }
 
 /*
diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c
index be825c26f9ec6667c708bbdea5e9ac7aee9ad5e9..8b259e97c1d29a86a001db7307f6766820549f78 100644
--- a/src/backend/parser/parse_node.c
+++ b/src/backend/parser/parse_node.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.59 2002/03/12 00:51:55 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.60 2002/03/21 16:01:07 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -285,7 +285,7 @@ transformArraySubscripts(ParseState *pstate,
 		{
 			if (ai->lidx)
 			{
-				subexpr = transformExpr(pstate, ai->lidx, EXPR_COLUMN_FIRST);
+				subexpr = transformExpr(pstate, ai->lidx);
 				/* If it's not int4 already, try to coerce */
 				subexpr = CoerceTargetExpr(pstate, subexpr, exprType(subexpr),
 										   INT4OID, -1);
@@ -305,7 +305,7 @@ transformArraySubscripts(ParseState *pstate,
 			}
 			lowerIndexpr = lappend(lowerIndexpr, subexpr);
 		}
-		subexpr = transformExpr(pstate, ai->uidx, EXPR_COLUMN_FIRST);
+		subexpr = transformExpr(pstate, ai->uidx);
 		/* If it's not int4 already, try to coerce */
 		subexpr = CoerceTargetExpr(pstate, subexpr, exprType(subexpr),
 								   INT4OID, -1);
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index 1609c89ce07b796a78b41e5d7e3bd19a4643b56b..5cf868a4d12e484c9bb2f2bccb86a34e83a2235a 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.63 2002/03/12 00:51:56 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.64 2002/03/21 16:01:09 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -104,7 +104,7 @@ scanNameSpaceForRefname(ParseState *pstate, Node *nsnode,
 		int			varno = ((RangeTblRef *) nsnode)->rtindex;
 		RangeTblEntry *rte = rt_fetch(varno, pstate->p_rtable);
 
-		if (strcmp(rte->eref->relname, refname) == 0)
+		if (strcmp(rte->eref->aliasname, refname) == 0)
 			result = (Node *) rte;
 	}
 	else if (IsA(nsnode, JoinExpr))
@@ -113,7 +113,7 @@ scanNameSpaceForRefname(ParseState *pstate, Node *nsnode,
 
 		if (j->alias)
 		{
-			if (strcmp(j->alias->relname, refname) == 0)
+			if (strcmp(j->alias->aliasname, refname) == 0)
 				return (Node *) j;		/* matched a join alias */
 
 			/*
@@ -175,7 +175,7 @@ checkNameSpaceConflicts(ParseState *pstate, Node *namespace1,
 		int			varno = ((RangeTblRef *) namespace1)->rtindex;
 		RangeTblEntry *rte = rt_fetch(varno, pstate->p_rtable);
 
-		scanNameSpaceForConflict(pstate, namespace2, rte->eref->relname);
+		scanNameSpaceForConflict(pstate, namespace2, rte->eref->aliasname);
 	}
 	else if (IsA(namespace1, JoinExpr))
 	{
@@ -183,7 +183,7 @@ checkNameSpaceConflicts(ParseState *pstate, Node *namespace1,
 
 		if (j->alias)
 		{
-			scanNameSpaceForConflict(pstate, namespace2, j->alias->relname);
+			scanNameSpaceForConflict(pstate, namespace2, j->alias->aliasname);
 
 			/*
 			 * Tables within an aliased join are invisible from outside
@@ -268,7 +268,7 @@ scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte, char *colname)
 	 * Scan the user column names (or aliases) for a match. Complain if
 	 * multiple matches.
 	 */
-	foreach(c, rte->eref->attrs)
+	foreach(c, rte->eref->colnames)
 	{
 		attnum++;
 		if (strcmp(strVal(lfirst(c)), colname) == 0)
@@ -420,15 +420,15 @@ qualifiedNameToVar(ParseState *pstate, char *refname, char *colname,
 RangeTblEntry *
 addRangeTableEntry(ParseState *pstate,
 				   char *relname,
-				   Attr *alias,
+				   Alias *alias,
 				   bool inh,
 				   bool inFromCl)
 {
 	RangeTblEntry *rte = makeNode(RangeTblEntry);
-	char	   *refname = alias ? alias->relname : relname;
+	char	   *refname = alias ? alias->aliasname : relname;
 	LOCKMODE	lockmode;
 	Relation	rel;
-	Attr	   *eref;
+	Alias	   *eref;
 	int			maxattrs;
 	int			numaliases;
 	int			varattno;
@@ -447,8 +447,8 @@ addRangeTableEntry(ParseState *pstate,
 	rel = heap_openr(relname, lockmode);
 	rte->relid = RelationGetRelid(rel);
 
-	eref = alias ? (Attr *) copyObject(alias) : makeAttr(refname, NULL);
-	numaliases = length(eref->attrs);
+	eref = alias ? (Alias *) copyObject(alias) : makeAlias(refname, NIL);
+	numaliases = length(eref->colnames);
 
 	/*
 	 * Since the rel is open anyway, let's check that the number of column
@@ -459,13 +459,13 @@ addRangeTableEntry(ParseState *pstate,
 		elog(ERROR, "Table \"%s\" has %d columns available but %d columns specified",
 			 refname, maxattrs, numaliases);
 
-	/* fill in any unspecified alias columns */
+	/* fill in any unspecified alias columns using actual column names */
 	for (varattno = numaliases; varattno < maxattrs; varattno++)
 	{
 		char	   *attrname;
 
 		attrname = pstrdup(NameStr(rel->rd_att->attrs[varattno]->attname));
-		eref->attrs = lappend(eref->attrs, makeString(attrname));
+		eref->colnames = lappend(eref->colnames, makeString(attrname));
 	}
 	rte->eref = eref;
 
@@ -512,12 +512,12 @@ addRangeTableEntry(ParseState *pstate,
 RangeTblEntry *
 addRangeTableEntryForSubquery(ParseState *pstate,
 							  Query *subquery,
-							  Attr *alias,
+							  Alias *alias,
 							  bool inFromCl)
 {
 	RangeTblEntry *rte = makeNode(RangeTblEntry);
-	char	   *refname = alias->relname;
-	Attr	   *eref;
+	char	   *refname = alias->aliasname;
+	Alias	   *eref;
 	int			numaliases;
 	int			varattno;
 	List	   *tlistitem;
@@ -529,7 +529,7 @@ addRangeTableEntryForSubquery(ParseState *pstate,
 	rte->alias = alias;
 
 	eref = copyObject(alias);
-	numaliases = length(eref->attrs);
+	numaliases = length(eref->colnames);
 
 	/* fill in any unspecified alias columns */
 	varattno = 0;
@@ -546,7 +546,7 @@ addRangeTableEntryForSubquery(ParseState *pstate,
 			char	   *attrname;
 
 			attrname = pstrdup(te->resdom->resname);
-			eref->attrs = lappend(eref->attrs, makeString(attrname));
+			eref->colnames = lappend(eref->colnames, makeString(attrname));
 		}
 	}
 	if (varattno < numaliases)
@@ -594,11 +594,11 @@ addRangeTableEntryForJoin(ParseState *pstate,
 						  List *coltypmods,
 						  List *leftcols,
 						  List *rightcols,
-						  Attr *alias,
+						  Alias *alias,
 						  bool inFromCl)
 {
 	RangeTblEntry *rte = makeNode(RangeTblEntry);
-	Attr	   *eref;
+	Alias	   *eref;
 	int			numaliases;
 
 	rte->rtekind = RTE_JOIN;
@@ -612,15 +612,15 @@ addRangeTableEntryForJoin(ParseState *pstate,
 	rte->joinrightcols = rightcols;
 	rte->alias = alias;
 
-	eref = alias ? (Attr *) copyObject(alias) : makeAttr("unnamed_join", NULL);
-	numaliases = length(eref->attrs);
+	eref = alias ? (Alias *) copyObject(alias) : makeAlias("unnamed_join", NIL);
+	numaliases = length(eref->colnames);
 
 	/* fill in any unspecified alias columns */
 	if (numaliases < length(colnames))
 	{
 		while (numaliases-- > 0)
 			colnames = lnext(colnames);
-		eref->attrs = nconc(eref->attrs, colnames);
+		eref->colnames = nconc(eref->colnames, colnames);
 	}
 
 	rte->eref = eref;
@@ -759,7 +759,7 @@ expandRTE(ParseState *pstate, RangeTblEntry *rte,
 
 		rel = heap_openr(rte->relname, AccessShareLock);
 		maxattrs = RelationGetNumberOfAttributes(rel);
-		numaliases = length(rte->eref->attrs);
+		numaliases = length(rte->eref->colnames);
 
 		for (varattno = 0; varattno < maxattrs; varattno++)
 		{
@@ -775,7 +775,7 @@ expandRTE(ParseState *pstate, RangeTblEntry *rte,
 				char	   *label;
 
 				if (varattno < numaliases)
-					label = strVal(nth(varattno, rte->eref->attrs));
+					label = strVal(nth(varattno, rte->eref->colnames));
 				else
 					label = NameStr(attr->attname);
 				*colnames = lappend(*colnames, makeString(pstrdup(label)));
@@ -798,7 +798,7 @@ expandRTE(ParseState *pstate, RangeTblEntry *rte,
 	else if (rte->rtekind == RTE_SUBQUERY)
 	{
 		/* Subquery RTE */
-		List	   *aliasp = rte->eref->attrs;
+		List	   *aliasp = rte->eref->colnames;
 		List	   *tlistitem;
 
 		varattno = 0;
@@ -836,7 +836,7 @@ expandRTE(ParseState *pstate, RangeTblEntry *rte,
 	else if (rte->rtekind == RTE_JOIN)
 	{
 		/* Join RTE */
-		List	   *aliasp = rte->eref->attrs;
+		List	   *aliasp = rte->eref->colnames;
 		List	   *coltypes = rte->joincoltypes;
 		List	   *coltypmods = rte->joincoltypmods;
 
@@ -936,8 +936,8 @@ get_rte_attribute_name(RangeTblEntry *rte, AttrNumber attnum)
 	 * If there is an alias, use it.  (This path should always be taken
 	 * for non-relation RTEs.)
 	 */
-	if (attnum > 0 && attnum <= length(rte->eref->attrs))
-		return strVal(nth(attnum - 1, rte->eref->attrs));
+	if (attnum > 0 && attnum <= length(rte->eref->colnames))
+		return strVal(nth(attnum - 1, rte->eref->colnames));
 
 	/*
 	 * Can get here for a system attribute (which never has an alias), or
@@ -946,7 +946,7 @@ get_rte_attribute_name(RangeTblEntry *rte, AttrNumber attnum)
 	 */
 	if (rte->rtekind != RTE_RELATION)
 		elog(ERROR, "Invalid attnum %d for rangetable entry %s",
-			 attnum, rte->eref->relname);
+			 attnum, rte->eref->aliasname);
 
 	/*
 	 * Use the real name of the table's column
@@ -1002,7 +1002,7 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
 		}
 		/* falling off end of list shouldn't happen... */
 		elog(ERROR, "Subquery %s does not have attribute %d",
-			 rte->eref->relname, attnum);
+			 rte->eref->aliasname, attnum);
 	}
 	else if (rte->rtekind == RTE_JOIN)
 	{
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index f5791298f310c6d9197fe032fa6e702b01f9816d..a4b7816517893072774318494869333521a40abd 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -8,13 +8,13 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.77 2002/03/12 00:51:56 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.78 2002/03/21 16:01:10 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
-
 #include "postgres.h"
 
+#include "miscadmin.h"
 #include "nodes/makefuncs.h"
 #include "parser/parsetree.h"
 #include "parser/parse_coerce.h"
@@ -56,9 +56,9 @@ transformTargetEntry(ParseState *pstate,
 
 	/* Transform the node if caller didn't do it already */
 	if (expr == NULL)
-		expr = transformExpr(pstate, node, EXPR_COLUMN_FIRST);
+		expr = transformExpr(pstate, node);
 
-	if (IsA(expr, Ident) &&((Ident *) expr)->isRel)
+	if (IsA(expr, RangeVar))
 		elog(ERROR, "You can't use relation names alone in the target list, try relation.*.");
 
 	type_id = exprType(expr);
@@ -99,11 +99,13 @@ transformTargetList(ParseState *pstate, List *targetlist)
 	{
 		ResTarget  *res = (ResTarget *) lfirst(targetlist);
 
-		if (IsA(res->val, Attr))
+		if (IsA(res->val, ColumnRef))
 		{
-			Attr	   *att = (Attr *) res->val;
+			ColumnRef  *cref = (ColumnRef *) res->val;
+			List	   *fields = cref->fields;
+			int			numnames = length(fields);
 
-			if (att->relname != NULL && strcmp(att->relname, "*") == 0)
+			if (numnames == 1 && strcmp(strVal(lfirst(fields)), "*") == 0)
 			{
 				/*
 				 * Target item is a single '*', expand all tables (eg.
@@ -112,27 +114,59 @@ transformTargetList(ParseState *pstate, List *targetlist)
 				p_target = nconc(p_target,
 								 ExpandAllTables(pstate));
 			}
-			else if (att->attrs != NIL &&
-					 strcmp(strVal(lfirst(att->attrs)), "*") == 0)
+			else if (strcmp(strVal(nth(numnames-1, fields)), "*") == 0)
 			{
 				/*
 				 * Target item is relation.*, expand that table (eg.
 				 * SELECT emp.*, dname FROM emp, dept)
 				 */
+				char	   *schemaname;
+				char	   *relname;
 				RangeTblEntry *rte;
 				int			sublevels_up;
 
-				rte = refnameRangeTblEntry(pstate, att->relname,
+				switch (numnames)
+				{
+					case 2:
+						schemaname = NULL;
+						relname = strVal(lfirst(fields));
+						break;
+					case 3:
+						schemaname = strVal(lfirst(fields));
+						relname = strVal(lsecond(fields));
+						break;
+					case 4:
+					{
+						char   *name1 = strVal(lfirst(fields));
+
+						/*
+						 * We check the catalog name and then ignore it.
+						 */
+						if (strcmp(name1, DatabaseName) != 0)
+							elog(ERROR, "Cross-database references are not implemented");
+						schemaname = strVal(lsecond(fields));
+						relname = strVal(lfirst(lnext(lnext(fields))));
+						break;
+					}
+					default:
+						elog(ERROR, "Invalid qualified name syntax (too many names)");
+						schemaname = NULL; /* keep compiler quiet */
+						relname = NULL;
+						break;
+				}
+
+				/* XXX do something with schema name */
+				rte = refnameRangeTblEntry(pstate, relname,
 										   &sublevels_up);
 				if (rte == NULL)
-					rte = addImplicitRTE(pstate, att->relname);
+					rte = addImplicitRTE(pstate, relname);
 
 				p_target = nconc(p_target,
 								 expandRelAttrs(pstate, rte));
 			}
 			else
 			{
-				/* Plain Attr node, treat it as an expression */
+				/* Plain ColumnRef node, treat it as an expression */
 				p_target = lappend(p_target,
 								   transformTargetEntry(pstate,
 														res->val,
@@ -143,7 +177,7 @@ transformTargetList(ParseState *pstate, List *targetlist)
 		}
 		else
 		{
-			/* Everything else but Attr */
+			/* Everything else but ColumnRef */
 			p_target = lappend(p_target,
 							   transformTargetEntry(pstate,
 													res->val,
@@ -317,10 +351,9 @@ CoerceTargetExpr(ParseState *pstate,
 
 /*
  * checkInsertTargets -
- *	  generate a list of column names if not supplied or
+ *	  generate a list of INSERT column targets if not supplied, or
  *	  test supplied column names to make sure they are in target table.
  *	  Also return an integer list of the columns' attribute numbers.
- *	  (used exclusively for inserts)
  */
 List *
 checkInsertTargets(ParseState *pstate, List *cols, List **attrnos)
@@ -338,17 +371,16 @@ checkInsertTargets(ParseState *pstate, List *cols, List **attrnos)
 
 		for (i = 0; i < numcol; i++)
 		{
-			Ident	   *id = makeNode(Ident);
+			ResTarget	   *col = makeNode(ResTarget);
 
 #ifdef	_DROP_COLUMN_HACK__
 			if (COLUMN_IS_DROPPED(attr[i]))
 				continue;
 #endif   /* _DROP_COLUMN_HACK__ */
-			id->name = palloc(NAMEDATALEN);
-			StrNCpy(id->name, NameStr(attr[i]->attname), NAMEDATALEN);
-			id->indirection = NIL;
-			id->isRel = false;
-			cols = lappend(cols, id);
+			col->name = pstrdup(NameStr(attr[i]->attname));
+			col->indirection = NIL;
+			col->val = NULL;
+			cols = lappend(cols, col);
 			*attrnos = lappendi(*attrnos, i + 1);
 		}
 	}
@@ -361,7 +393,7 @@ checkInsertTargets(ParseState *pstate, List *cols, List **attrnos)
 
 		foreach(tl, cols)
 		{
-			char	   *name = ((Ident *) lfirst(tl))->name;
+			char	   *name = ((ResTarget *) lfirst(tl))->name;
 			int			attrno;
 
 			/* Lookup column name, elog on failure */
@@ -458,19 +490,35 @@ FigureColnameInternal(Node *node, char **name)
 		case T_Ident:
 			*name = ((Ident *) node)->name;
 			return 2;
-		case T_Attr:
+		case T_ColumnRef:
 			{
-				List	   *attrs = ((Attr *) node)->attrs;
+				List	   *fields = ((ColumnRef *) node)->fields;
 
-				if (attrs)
+				while (lnext(fields) != NIL)
+					fields = lnext(fields);
+				if (strcmp(strVal(lfirst(fields)), "*") != 0)
 				{
-					while (lnext(attrs) != NIL)
-						attrs = lnext(attrs);
-					*name = strVal(lfirst(attrs));
+					*name = strVal(lfirst(fields));
 					return 2;
 				}
 			}
 			break;
+		case T_ExprFieldSelect:
+			{
+				List	   *fields = ((ExprFieldSelect *) node)->fields;
+
+				if (fields)
+				{
+					while (lnext(fields) != NIL)
+						fields = lnext(fields);
+					if (strcmp(strVal(lfirst(fields)), "*") != 0)
+					{
+						*name = strVal(lfirst(fields));
+						return 2;
+					}
+				}
+			}
+			break;
 		case T_FuncCall:
 			*name = ((FuncCall *) node)->funcname;
 			return 2;
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index b0315157e4f7ef751d6215eb776a0407b270d849..0b47aa9c924593f07d064566102d384c5929651e 100644
--- a/src/backend/rewrite/rewriteDefine.c
+++ b/src/backend/rewrite/rewriteDefine.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.63 2001/08/12 21:35:18 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.64 2002/03/21 16:01:16 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -110,63 +110,17 @@ InsertRule(char *rulname,
 	return rewriteObjectId;
 }
 
-/*
- *		for now, event_object must be a single attribute
- */
-static void
-ValidateRule(int event_type,
-			 char *eobj_string,
-			 char *eslot_string,
-			 Node *event_qual,
-			 List **action,
-			 int is_instead,
-			 Oid event_attype)
-{
-	if (((event_type == CMD_INSERT) || (event_type == CMD_DELETE)) &&
-		eslot_string)
-	{
-		elog(ERROR,
-		"rules not allowed for insert or delete events to an attribute");
-	}
-
-#ifdef NOT_USED
-
-	/*---------
-	 * on retrieve to class.attribute do instead nothing is converted to
-	 * 'on retrieve to class.attribute do instead:
-	 *
-	 *	 retrieve (attribute = NULL)'
-	 *
-	 * this is also a terrible hack that works well -- glass
-	 *---------
-	 */
-	if (is_instead && !*action && eslot_string && event_type == CMD_SELECT)
-	{
-		char	   *temp_buffer = (char *) palloc(strlen(template) + 80);
-
-		sprintf(temp_buffer, template, event_attype,
-				get_typlen(event_attype), eslot_string,
-				event_attype);
-
-		*action = (List *) stringToNode(temp_buffer);
-
-		pfree(temp_buffer);
-	}
-#endif
-}
-
 void
 DefineQueryRewrite(RuleStmt *stmt)
 {
-	CmdType		event_type = stmt->event;
-	Attr	   *event_obj = stmt->object;
+	RangeVar   *event_obj = stmt->relation;
 	Node	   *event_qual = stmt->whereClause;
+	CmdType		event_type = stmt->event;
 	bool		is_instead = stmt->instead;
 	List	   *action = stmt->actions;
 	Relation	event_relation;
 	Oid			ev_relid;
 	Oid			ruleId;
-	char	   *eslot_string = NULL;
 	int			event_attno;
 	Oid			event_attype;
 	char	   *actionP,
@@ -186,23 +140,6 @@ DefineQueryRewrite(RuleStmt *stmt)
 	event_relation = heap_openr(event_obj->relname, AccessExclusiveLock);
 	ev_relid = RelationGetRelid(event_relation);
 
-	/*
-	 * The current rewrite handler is known to work on relation level
-	 * rules only. And for SELECT events, it expects one non-nothing
-	 * action that is instead and returns exactly a tuple of the rewritten
-	 * relation. This restricts SELECT rules to views.
-	 *
-	 * Jan
-	 */
-	if (event_obj->attrs)
-		elog(ERROR, "attribute level rules currently not supported");
-
-	/*
-	 * eslot_string = strVal(lfirst(event_obj->attrs));
-	 */
-	else
-		eslot_string = NULL;
-
 	/*
 	 * No rule actions that modify OLD or NEW
 	 */
@@ -358,21 +295,8 @@ DefineQueryRewrite(RuleStmt *stmt)
 	/*
 	 * This rule is allowed - prepare to install it.
 	 */
-	if (eslot_string == NULL)
-	{
-		event_attno = -1;
-		event_attype = InvalidOid;
-	}
-	else
-	{
-		event_attno = attnameAttNum(event_relation, eslot_string);
-		event_attype = attnumTypeId(event_relation, event_attno);
-	}
-
-	/* fix bug about instead nothing */
-	ValidateRule(event_type, event_obj->relname,
-				 eslot_string, event_qual, &action,
-				 is_instead, event_attype);
+	event_attno = -1;
+	event_attype = InvalidOid;
 
 	/*
 	 * We want the rule's table references to be checked as though by the
diff --git a/src/backend/rewrite/rewriteManip.c b/src/backend/rewrite/rewriteManip.c
index af413cab938d701500e1b496707800738adbab81..86a158f94f966a3d7667311ec51bb59fe30eaa94 100644
--- a/src/backend/rewrite/rewriteManip.c
+++ b/src/backend/rewrite/rewriteManip.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.62 2002/03/12 00:51:58 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.63 2002/03/21 16:01:17 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -573,9 +573,9 @@ getInsertSelectQuery(Query *parsetree, Query ***subquery_ptr)
 	 * they've been pushed down to the SELECT.
 	 */
 	if (length(parsetree->rtable) >= 2 &&
-		strcmp(rt_fetch(PRS2_OLD_VARNO, parsetree->rtable)->eref->relname,
+		strcmp(rt_fetch(PRS2_OLD_VARNO, parsetree->rtable)->eref->aliasname,
 			   "*OLD*") == 0 &&
-		strcmp(rt_fetch(PRS2_NEW_VARNO, parsetree->rtable)->eref->relname,
+		strcmp(rt_fetch(PRS2_NEW_VARNO, parsetree->rtable)->eref->aliasname,
 			   "*NEW*") == 0)
 		return parsetree;
 	Assert(parsetree->jointree && IsA(parsetree->jointree, FromExpr));
@@ -589,9 +589,9 @@ getInsertSelectQuery(Query *parsetree, Query ***subquery_ptr)
 		  selectquery->commandType == CMD_SELECT))
 		elog(ERROR, "getInsertSelectQuery: expected to find SELECT subquery");
 	if (length(selectquery->rtable) >= 2 &&
-	 strcmp(rt_fetch(PRS2_OLD_VARNO, selectquery->rtable)->eref->relname,
+	 strcmp(rt_fetch(PRS2_OLD_VARNO, selectquery->rtable)->eref->aliasname,
 			"*OLD*") == 0 &&
-	 strcmp(rt_fetch(PRS2_NEW_VARNO, selectquery->rtable)->eref->relname,
+	 strcmp(rt_fetch(PRS2_NEW_VARNO, selectquery->rtable)->eref->aliasname,
 			"*NEW*") == 0)
 	{
 		if (subquery_ptr)
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 9542170d340a2ed3364d5bde8187edb77a885224..8443fe6591bdd9725c7621843f66e523bfaff056 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.257 2002/03/19 16:10:48 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.258 2002/03/21 16:01:25 tgl Exp $
  *
  * NOTES
  *	  this is the "main" module of the postgres backend and
@@ -1722,7 +1722,7 @@ PostgresMain(int argc, char *argv[], const char *username)
 	if (!IsUnderPostmaster)
 	{
 		puts("\nPOSTGRES backend interactive interface ");
-		puts("$Revision: 1.257 $ $Date: 2002/03/19 16:10:48 $\n");
+		puts("$Revision: 1.258 $ $Date: 2002/03/21 16:01:25 $\n");
 	}
 
 	/*
@@ -2216,6 +2216,10 @@ CreateCommandTag(Node *parsetree)
 			tag = "CREATE DOMAIN";
 			break;
 
+		case T_CreateSchemaStmt:
+			tag = "CREATE";
+			break;
+
 		case T_CreateStmt:
 			tag = "CREATE";
 			break;
diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c
index ef4b4edd40f64d2d65b246ee2b0c2b3f997a3816..4599a27a6428512fd8c4b634270373e8c621299b 100644
--- a/src/backend/tcop/pquery.c
+++ b/src/backend/tcop/pquery.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.50 2002/03/06 06:10:10 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.51 2002/03/21 16:01:27 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -181,12 +181,12 @@ ProcessQuery(Query *parsetree,
 	 */
 	if (isRetrieveIntoPortal)
 	{
-		intoName = parsetree->into;
+		intoName = parsetree->into->relname;
 		portal = PreparePortal(intoName);
 		oldContext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
 		parsetree = copyObject(parsetree);
 		plan = copyObject(plan);
-		intoName = parsetree->into;	/* use copied name in QueryDesc */
+		intoName = parsetree->into->relname;	/* use copied name in QueryDesc */
 
 		/*
 		 * We stay in portal's memory context for now, so that query desc,
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index db8d440034f8d95a6d49e203b4960ec38f686101..9a6813635cac0e1771bb920d3937ef80acfde837 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.135 2002/03/20 19:44:35 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.136 2002/03/21 16:01:30 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -218,6 +218,14 @@ ProcessUtility(Node *parsetree,
 			/*
 			 * relation and attribute manipulation
 			 */
+		case T_CreateSchemaStmt:
+			{
+				CreateSchemaStmt  *stmt = (CreateSchemaStmt *) parsetree;
+
+				CreateSchemaCommand(stmt);
+			}
+			break;
+
 		case T_CreateStmt:
 			DefineRelation((CreateStmt *) parsetree, RELKIND_RELATION);
 
@@ -226,19 +234,19 @@ ProcessUtility(Node *parsetree,
 			 * secondary relation too.
 			 */
 			CommandCounterIncrement();
-			AlterTableCreateToastTable(((CreateStmt *) parsetree)->relname,
+			AlterTableCreateToastTable(((CreateStmt *) parsetree)->relation->relname,
 									   true);
 			break;
 
 		case T_DropStmt:
 			{
 				DropStmt   *stmt = (DropStmt *) parsetree;
-				List	   *args = stmt->names;
+				List	   *args = stmt->objects;
 				List	   *arg;
 
 				foreach(arg, args)
 				{
-					relname = strVal(lfirst(arg));
+					relname = ((RangeVar *) lfirst(arg))->relname;
 
 					switch (stmt->removeType)
 					{
@@ -299,7 +307,8 @@ ProcessUtility(Node *parsetree,
 
 		case T_TruncateStmt:
 			{
-				TruncateRelation(((TruncateStmt *) parsetree)->relName);
+				relname = ((TruncateStmt *) parsetree)->relation->relname;
+				TruncateRelation(relname);
 			}
 			break;
 
@@ -322,7 +331,7 @@ ProcessUtility(Node *parsetree,
 				if (stmt->direction != FROM)
 					SetQuerySnapshot();
 
-				DoCopy(stmt->relname,
+				DoCopy(stmt->relation->relname,
 					   stmt->binary,
 					   stmt->oids,
 					   (bool) (stmt->direction == FROM),
@@ -345,7 +354,7 @@ ProcessUtility(Node *parsetree,
 			{
 				RenameStmt *stmt = (RenameStmt *) parsetree;
 
-				relname = stmt->relname;
+				relname = stmt->relation->relname;
 				if (!allowSystemTableMods && IsSystemRelationName(relname))
 					elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog",
 						 relname);
@@ -380,7 +389,7 @@ ProcessUtility(Node *parsetree,
 					renameatt(relname,	/* relname */
 							  stmt->column,		/* old att name */
 							  stmt->newname,	/* new att name */
-							  interpretInhOption(stmt->inhOpt));		/* recursive? */
+							  interpretInhOption(stmt->relation->inhOpt));		/* recursive? */
 				}
 			}
 			break;
@@ -398,47 +407,47 @@ ProcessUtility(Node *parsetree,
 				switch (stmt->subtype)
 				{
 					case 'A':	/* ADD COLUMN */
-						AlterTableAddColumn(stmt->relname,
-										interpretInhOption(stmt->inhOpt),
+						AlterTableAddColumn(stmt->relation->relname,
+										interpretInhOption((stmt->relation)->inhOpt),
 											(ColumnDef *) stmt->def);
 						break;
 					case 'T':	/* ALTER COLUMN DEFAULT */
-						AlterTableAlterColumnDefault(stmt->relname,
-										interpretInhOption(stmt->inhOpt),
+						AlterTableAlterColumnDefault(stmt->relation->relname,
+										interpretInhOption((stmt->relation)->inhOpt),
 													 stmt->name,
 													 stmt->def);
 						break;
 					case 'S':	/* ALTER COLUMN STATISTICS */
 					case 'M':   /* ALTER COLUMN STORAGE */
-						AlterTableAlterColumnFlags(stmt->relname,
-										interpretInhOption(stmt->inhOpt),
+						AlterTableAlterColumnFlags(stmt->relation->relname,
+										interpretInhOption(stmt->relation->inhOpt),
 														stmt->name,
 														stmt->def,
 												        &(stmt->subtype));
 						break;
 					case 'D':	/* DROP COLUMN */
-						AlterTableDropColumn(stmt->relname,
-										interpretInhOption(stmt->inhOpt),
+						AlterTableDropColumn(stmt->relation->relname,
+										interpretInhOption(stmt->relation->inhOpt),
 											 stmt->name,
 											 stmt->behavior);
 						break;
 					case 'C':	/* ADD CONSTRAINT */
-						AlterTableAddConstraint(stmt->relname,
-										interpretInhOption(stmt->inhOpt),
+						AlterTableAddConstraint(stmt->relation->relname,
+										interpretInhOption(stmt->relation->inhOpt),
 												(List *) stmt->def);
 						break;
 					case 'X':	/* DROP CONSTRAINT */
-						AlterTableDropConstraint(stmt->relname,
-										interpretInhOption(stmt->inhOpt),
+						AlterTableDropConstraint(stmt->relation->relname,
+										interpretInhOption(stmt->relation->inhOpt),
 												 stmt->name,
 												 stmt->behavior);
 						break;
 					case 'E':	/* CREATE TOAST TABLE */
-						AlterTableCreateToastTable(stmt->relname,
+						AlterTableCreateToastTable(stmt->relation->relname,
 												   false);
 						break;
 					case 'U':	/* ALTER OWNER */
-						AlterTableOwner(stmt->relname,
+						AlterTableOwner(stmt->relation->relname,
 										stmt->name);
 						break;
 					default:	/* oops */
@@ -487,7 +496,7 @@ ProcessUtility(Node *parsetree,
 			{
 				ViewStmt   *stmt = (ViewStmt *) parsetree;
 
-				DefineView(stmt->viewname, stmt->query);		/* retrieve parsetree */
+				DefineView(stmt->view->relname, stmt->query);	/* retrieve parsetree */
 			}
 			break;
 
@@ -499,17 +508,17 @@ ProcessUtility(Node *parsetree,
 			{
 				IndexStmt  *stmt = (IndexStmt *) parsetree;
 
-				relname = stmt->relname;
+				relname = stmt->relation->relname;
 				if (!allowSystemTableMods && IsSystemRelationName(relname))
 					elog(ERROR, "CREATE INDEX: relation \"%s\" is a system catalog",
 						 relname);
 				if (!pg_ownercheck(GetUserId(), relname, RELNAME))
 					elog(ERROR, "permission denied");
 
-				DefineIndex(stmt->relname,		/* relation name */
-							stmt->idxname,		/* index name */
-							stmt->accessMethod, /* am name */
-							stmt->indexParams,	/* parameters */
+				DefineIndex(stmt->relation->relname,	/* relation */
+							stmt->idxname,				/* index name */
+							stmt->accessMethod, 		/* am name */
+							stmt->indexParams,			/* parameters */
 							stmt->unique,
 							stmt->primary,
 							(Expr *) stmt->whereClause,
@@ -522,7 +531,7 @@ ProcessUtility(Node *parsetree,
 				RuleStmt   *stmt = (RuleStmt *) parsetree;
 				int			aclcheck_result;
 
-				relname = stmt->object->relname;
+				relname = stmt->relation->relname;
 				aclcheck_result = pg_aclcheck(relname, GetUserId(), ACL_RULE);
 				if (aclcheck_result != ACLCHECK_OK)
 					elog(ERROR, "%s: %s", relname, aclcheck_error_strings[aclcheck_result]);
@@ -603,7 +612,7 @@ ProcessUtility(Node *parsetree,
 			{
 				NotifyStmt *stmt = (NotifyStmt *) parsetree;
 
-				Async_Notify(stmt->relname);
+				Async_Notify(stmt->relation->relname);
 			}
 			break;
 
@@ -611,7 +620,7 @@ ProcessUtility(Node *parsetree,
 			{
 				ListenStmt *stmt = (ListenStmt *) parsetree;
 
-				Async_Listen(stmt->relname, MyProcPid);
+				Async_Listen(stmt->relation->relname, MyProcPid);
 			}
 			break;
 
@@ -619,7 +628,7 @@ ProcessUtility(Node *parsetree,
 			{
 				UnlistenStmt *stmt = (UnlistenStmt *) parsetree;
 
-				Async_Unlisten(stmt->relname, MyProcPid);
+				Async_Unlisten(stmt->relation->relname, MyProcPid);
 			}
 			break;
 
@@ -636,7 +645,7 @@ ProcessUtility(Node *parsetree,
 			{
 				ClusterStmt *stmt = (ClusterStmt *) parsetree;
 
-				relname = stmt->relname;
+				relname = stmt->relation->relname;
 				if (IsSystemRelationName(relname))
 					elog(ERROR, "CLUSTER: relation \"%s\" is a system catalog",
 						 relname);
@@ -712,7 +721,6 @@ ProcessUtility(Node *parsetree,
 
 			/*
 			 * ******************************** DOMAIN statements ****
-			 *
 			 */
 		case T_CreateDomainStmt:
 			DefineDomain((CreateDomainStmt *) parsetree);
@@ -720,9 +728,7 @@ ProcessUtility(Node *parsetree,
 
 			/*
 			 * ******************************** USER statements ****
-			 *
 			 */
-
 		case T_CreateUserStmt:
 			CreateUser((CreateUserStmt *) parsetree);
 			break;
@@ -774,7 +780,7 @@ ProcessUtility(Node *parsetree,
 				switch (stmt->reindexType)
 				{
 					case INDEX:
-						relname = (char *) stmt->name;
+						relname = (char *) stmt->relation->relname;
 						if (IsSystemRelationName(relname))
 						{
 							if (!allowSystemTableMods)
@@ -789,7 +795,7 @@ ProcessUtility(Node *parsetree,
 						ReindexIndex(relname, stmt->force);
 						break;
 					case TABLE:
-						relname = (char *) stmt->name;
+						relname = (char *) stmt->relation->relname;
 						if (!pg_ownercheck(GetUserId(), relname, RELNAME))
 							elog(ERROR, "%s: %s", relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
 						ReindexTable(relname, stmt->force);
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index d47bf3bb945c9f658c7e4ff0022ffade1b4abd41..0e4472faffbda38a97c95f4e407c31e452305e8a 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -3,7 +3,7 @@
  *				back to source text
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.93 2002/03/12 00:51:59 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.94 2002/03/21 16:01:34 tgl Exp $
  *
  *	  This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -48,6 +48,7 @@
 #include "catalog/pg_shadow.h"
 #include "executor/spi.h"
 #include "lib/stringinfo.h"
+#include "nodes/makefuncs.h"
 #include "optimizer/clauses.h"
 #include "optimizer/tlist.h"
 #include "parser/keywords.h"
@@ -659,8 +660,7 @@ deparse_context_for(char *relname, Oid relid)
 	rte->rtekind = RTE_RELATION;
 	rte->relname = relname;
 	rte->relid = relid;
-	rte->eref = makeNode(Attr);
-	rte->eref->relname = relname;
+	rte->eref = makeAlias(relname, NIL);
 	rte->inh = false;
 	rte->inFromCl = true;
 
@@ -755,9 +755,7 @@ deparse_context_for_subplan(const char *name, List *tlist,
 	rte->rtekind = RTE_SPECIAL;	/* XXX */
 	rte->relname = pstrdup(name);
 	rte->relid = InvalidOid;
-	rte->eref = makeNode(Attr);
-	rte->eref->relname = rte->relname;
-	rte->eref->attrs = attrs;
+	rte->eref = makeAlias(rte->relname, attrs);
 	rte->inh = false;
 	rte->inFromCl = true;
 
@@ -1462,7 +1460,7 @@ get_utility_query_def(Query *query, deparse_context *context)
 	{
 		NotifyStmt *stmt = (NotifyStmt *) query->utilityStmt;
 
-		appendStringInfo(buf, "NOTIFY %s", quote_identifier(stmt->relname));
+		appendStringInfo(buf, "NOTIFY %s", quote_identifier(stmt->relation->relname));
 	}
 	else
 		elog(ERROR, "get_utility_query_def: unexpected statement type");
@@ -1512,7 +1510,7 @@ get_names_for_var(Var *var, deparse_context *context,
 	if (rte->rtekind == RTE_JOIN && rte->alias == NULL)
 		*refname = NULL;
 	else
-		*refname = rte->eref->relname;
+		*refname = rte->eref->aliasname;
 
 	if (var->varattno == InvalidAttrNumber)
 		*attname = NULL;
@@ -1758,12 +1756,11 @@ get_rule_expr(Node *node, deparse_context *context)
 				/*
 				 * If the argument is simple enough, we could emit
 				 * arg.fieldname, but most cases where FieldSelect is used
-				 * are *not* simple.  For now, always use the projection-
-				 * function syntax.
+				 * are *not* simple.  So, always use parenthesized syntax.
 				 */
-				appendStringInfo(buf, "%s(", quote_identifier(fieldname));
+				appendStringInfoChar(buf, '(');
 				get_rule_expr(fselect->arg, context);
-				appendStringInfoChar(buf, ')');
+				appendStringInfo(buf, ").%s", quote_identifier(fieldname));
 			}
 			break;
 
@@ -2302,9 +2299,9 @@ get_from_clause(Query *query, deparse_context *context)
 
 			if (!rte->inFromCl)
 				continue;
-			if (strcmp(rte->eref->relname, "*NEW*") == 0)
+			if (strcmp(rte->eref->aliasname, "*NEW*") == 0)
 				continue;
-			if (strcmp(rte->eref->relname, "*OLD*") == 0)
+			if (strcmp(rte->eref->aliasname, "*OLD*") == 0)
 				continue;
 		}
 
@@ -2342,15 +2339,15 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
 		if (rte->alias != NULL)
 		{
 			appendStringInfo(buf, " %s",
-							 quote_identifier(rte->alias->relname));
-			if (rte->alias->attrs != NIL)
+							 quote_identifier(rte->alias->aliasname));
+			if (rte->alias->colnames != NIL)
 			{
 				List	   *col;
 
 				appendStringInfo(buf, "(");
-				foreach(col, rte->alias->attrs)
+				foreach(col, rte->alias->colnames)
 				{
-					if (col != rte->alias->attrs)
+					if (col != rte->alias->colnames)
 						appendStringInfo(buf, ", ");
 					appendStringInfo(buf, "%s",
 								  quote_identifier(strVal(lfirst(col))));
@@ -2420,15 +2417,15 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
 		if (j->alias != NULL)
 		{
 			appendStringInfo(buf, " %s",
-							 quote_identifier(j->alias->relname));
-			if (j->alias->attrs != NIL)
+							 quote_identifier(j->alias->aliasname));
+			if (j->alias->colnames != NIL)
 			{
 				List	   *col;
 
 				appendStringInfo(buf, "(");
-				foreach(col, j->alias->attrs)
+				foreach(col, j->alias->colnames)
 				{
-					if (col != j->alias->attrs)
+					if (col != j->alias->colnames)
 						appendStringInfo(buf, ", ");
 					appendStringInfo(buf, "%s",
 								  quote_identifier(strVal(lfirst(col))));
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index a049a2393584e8d191fcec051b65bfebdaba8bff..5e0fa208cf8c109a6a8cd6b6ebe46f16a8d558e0 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: catversion.h,v 1.107 2002/03/20 19:44:48 tgl Exp $
+ * $Id: catversion.h,v 1.108 2002/03/21 16:01:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*							yyyymmddN */
-#define CATALOG_VERSION_NO	200203191
+#define CATALOG_VERSION_NO	200203211
 
 #endif
diff --git a/src/include/commands/command.h b/src/include/commands/command.h
index cf09111af47891f3525fcffec4a5db9a8311e0c6..36757b1f7028c60e94d35009c18d89f36f74afa2 100644
--- a/src/include/commands/command.h
+++ b/src/include/commands/command.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: command.h,v 1.33 2002/03/05 05:33:29 momjian Exp $
+ * $Id: command.h,v 1.34 2002/03/21 16:01:41 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -72,4 +72,9 @@ extern void AlterTableOwner(const char *relationName, const char *newOwnerName);
  */
 extern void LockTableCommand(LockStmt *lockstmt);
 
+/*
+ * SCHEMA
+ */
+extern void CreateSchemaCommand(CreateSchemaStmt *parsetree);
+
 #endif   /* COMMAND_H */
diff --git a/src/include/nodes/makefuncs.h b/src/include/nodes/makefuncs.h
index 384241990b5a98d40ef1e0e9cbe89711af340c1b..2de7c03cf6ac311b79a8b5b1d082bff6196a0f16 100644
--- a/src/include/nodes/makefuncs.h
+++ b/src/include/nodes/makefuncs.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: makefuncs.h,v 1.31 2002/03/20 19:45:01 tgl Exp $
+ * $Id: makefuncs.h,v 1.32 2002/03/21 16:01:43 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -44,7 +44,7 @@ extern Const *makeConst(Oid consttype,
 
 extern Const *makeNullConst(Oid consttype);
 
-extern Attr *makeAttr(char *relname, char *attname);
+extern Alias *makeAlias(const char *aliasname, List *colnames);
 
 extern RelabelType *makeRelabelType(Node *arg, Oid rtype, int32 rtypmod);
 
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index d25bc5f1563616a584cbb0d2cdeb4ab632fc33a2..95aba8dfaa492c95676787fdd023c39b4128d35c 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: nodes.h,v 1.101 2002/03/19 02:18:23 momjian Exp $
+ * $Id: nodes.h,v 1.102 2002/03/21 16:01:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -195,21 +195,24 @@ typedef enum NodeTag
 	T_DropGroupStmt,
 	T_ReindexStmt,
 	T_CheckPointStmt,
+	T_CreateSchemaStmt,
 	T_AlterDatabaseSetStmt,
 	T_AlterUserSetStmt,
 
 	T_A_Expr = 700,
-	T_Attr,
-	T_A_Const,
-	T_ParamNo,
+	T_ColumnRef,
+	T_ParamRef,
 	T_Ident,
+	T_A_Const,
 	T_FuncCall,
 	T_A_Indices,
+	T_ExprFieldSelect,
 	T_ResTarget,
 	T_TypeCast,
-	T_RangeSubselect,
 	T_SortGroupBy,
+	T_Alias,
 	T_RangeVar,
+	T_RangeSubselect,
 	T_TypeName,
 	T_IndexElem,
 	T_ColumnDef,
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 1b1f01bd28f7ae57732937135843d5287b086a99..4f5d139011f572887453cbe49e8072fa320952b2 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parsenodes.h,v 1.162 2002/03/20 19:45:02 tgl Exp $
+ * $Id: parsenodes.h,v 1.163 2002/03/21 16:01:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -49,10 +49,10 @@ typedef struct Query
 								 * statement */
 
 	int			resultRelation; /* target relation (index into rtable) */
-	char	   *into;			/* portal (cursor) name */
+	struct RangeVar *into;		/* target relation or portal (cursor) 
+								 * for portal just name is meaningful */
 	bool		isPortal;		/* is this a retrieve into portal? */
 	bool		isBinary;		/* binary portal? */
-	bool		isTemp;			/* is 'into' a temp table? */
 
 	bool		hasAggs;		/* has aggregates in tlist or havingQual */
 	bool		hasSubLinks;	/* has subquery SubLink */
@@ -125,15 +125,30 @@ typedef struct TypeName
 } TypeName;
 
 /*
- * ParamNo - specifies a parameter reference
+ * ColumnRef - specifies a reference to a column, or possibly a whole tuple
+ *
+ *		The "fields" list must be nonempty; its last component may be "*"
+ *		instead of a field name.  Subscripts are optional.
+ */
+typedef struct ColumnRef
+{
+	NodeTag		type;
+	List	   *fields;			/* field names (list of Value strings) */
+	List	   *indirection;	/* subscripts (list of A_Indices) */
+} ColumnRef;
+
+/*
+ * ParamRef - specifies a parameter reference
+ *
+ *		The parameter could be qualified with field names and/or subscripts
  */
-typedef struct ParamNo
+typedef struct ParamRef
 {
 	NodeTag		type;
 	int			number;			/* the number of the parameter */
-	TypeName   *typename;		/* the typecast */
-	List	   *indirection;	/* array references */
-} ParamNo;
+	List	   *fields;			/* field names (list of Value strings) */
+	List	   *indirection;	/* subscripts (list of A_Indices) */
+} ParamRef;
 
 /*
  * A_Expr - binary expressions
@@ -147,22 +162,6 @@ typedef struct A_Expr
 	Node	   *rexpr;			/* right argument */
 } A_Expr;
 
-/*
- * Attr -
- *	  specifies an Attribute (ie. a Column); could have nested dots or
- *	  array references.
- *
- */
-typedef struct Attr
-{
-	NodeTag		type;
-	char	   *relname;		/* name of relation (can be "*") */
-	ParamNo    *paramNo;		/* or a parameter */
-	List	   *attrs;			/* attributes (possibly nested); list of
-								 * Values (strings) */
-	List	   *indirection;	/* array refs (list of A_Indices') */
-} Attr;
-
 /*
  * A_Const - a constant expression
  */
@@ -176,11 +175,11 @@ typedef struct A_Const
 /*
  * TypeCast - a CAST expression
  *
- * NOTE: for mostly historical reasons, A_Const and ParamNo parsenodes contain
+ * NOTE: for mostly historical reasons, A_Const parsenodes contain
  * room for a TypeName; we only generate a separate TypeCast node if the
- * argument to be casted is neither of those kinds of nodes.  In theory either
- * representation would work, but it is convenient (especially for A_Const)
- * to have the target type immediately available.
+ * argument to be casted is not a constant.  In theory either representation
+ * would work, but it is convenient to have the target type immediately
+ * available while resolving a constant's datatype.
  */
 typedef struct TypeCast
 {
@@ -284,17 +283,13 @@ typedef struct ColumnDef
 
 /*
  * Ident -
- *	  an identifier (could be an attribute or a relation name). Depending
- *	  on the context at transformStmt time, the identifier is treated as
- *	  either a relation name (in which case, isRel will be set) or an
- *	  attribute (in which case, it will be transformed into an Attr).
+ *	  an unqualified identifier.  This is currently used only in the context
+ *	  of column name lists.
  */
 typedef struct Ident
 {
 	NodeTag		type;
 	char	   *name;			/* its name */
-	List	   *indirection;	/* array references */
-	bool		isRel;			/* is this a relation or a column? */
 } Ident;
 
 /*
@@ -324,6 +319,21 @@ typedef struct A_Indices
 	Node	   *uidx;
 } A_Indices;
 
+/*
+ * ExprFieldSelect - select a field and/or array element from an expression
+ *
+ *		This is used in the raw parsetree to represent selection from an
+ *		arbitrary expression (not a column or param reference).  Either
+ *		fields or indirection may be NIL if not used.
+ */
+typedef struct ExprFieldSelect
+{
+	NodeTag		type;
+	Node	   *arg;			/* the thing being selected from */
+	List	   *fields;			/* field names (list of Value strings) */
+	List	   *indirection;	/* subscripts (list of A_Indices) */
+} ExprFieldSelect;
+
 /*
  * ResTarget -
  *	  result target (used in target list of pre-transformed Parse trees)
@@ -358,15 +368,37 @@ typedef struct SortGroupBy
 	Node	   *node;			/* Expression  */
 } SortGroupBy;
 
+/*
+ * Alias -
+ *	  specifies an alias for a range variable; the alias might also
+ *	  specify renaming of columns within the table.
+ */
+typedef struct Alias
+{
+	NodeTag		type;
+	char	   *aliasname;		/* aliased rel name (never qualified) */
+	List	   *colnames;		/* optional list of column aliases */
+	/* Note: colnames is a list of Value nodes (always strings) */
+} Alias;
+
 /*
  * RangeVar - range variable, used in FROM clauses
+ *
+ * Also used to represent table names in utility statements; there, the alias
+ * field is not used, and inhOpt shows whether to apply the operation
+ * recursively to child tables.  In some contexts it is also useful to carry
+ * a TEMP table indication here.
  */
 typedef struct RangeVar
 {
 	NodeTag		type;
-	char	   *relname;		/* the relation name */
-	InhOption	inhOpt;			/* expand rel by inheritance? */
-	Attr	   *name;			/* optional table alias & column aliases */
+	char	   *catalogname;	/* the catalog (database) name, or NULL */
+	char	   *schemaname;		/* the schema name, or NULL */
+	char	   *relname;		/* the relation/sequence name */
+	InhOption	inhOpt;			/* expand rel by inheritance? 
+								 * recursively act on children? */
+	bool		istemp;			/* is this a temp relation/sequence? */
+	Alias	   *alias;			/* table alias & optional column aliases */
 } RangeVar;
 
 /*
@@ -376,7 +408,7 @@ typedef struct RangeSubselect
 {
 	NodeTag		type;
 	Node	   *subquery;		/* the untransformed sub-select clause */
-	Attr	   *name;			/* table alias & optional column aliases */
+	Alias	   *alias;			/* table alias & optional column aliases */
 } RangeSubselect;
 
 /*
@@ -437,7 +469,7 @@ typedef struct TargetEntry
  *	  like outer joins and join-output-column aliasing.)  Other special
  *	  RTE types also exist, as indicated by RTEKind.
  *
- *	  alias is an Attr node representing the AS alias-clause attached to the
+ *	  alias is an Alias node representing the AS alias-clause attached to the
  *	  FROM expression, or NULL if no clause.
  *
  *	  eref is the table reference name and column reference names (either
@@ -489,7 +521,7 @@ typedef struct RangeTblEntry
 	 */
 
 	/*
-	 * Fields valid for a plain relation or inh_relation RTE (else NULL/zero):
+	 * Fields valid for a plain relation RTE (else NULL/zero):
 	 */
 	char	   *relname;		/* real name of the relation */
 	Oid			relid;			/* OID of the relation */
@@ -517,8 +549,8 @@ typedef struct RangeTblEntry
 	/*
 	 * Fields valid in all RTEs:
 	 */
-	Attr	   *alias;			/* user-written alias clause, if any */
-	Attr	   *eref;			/* expanded reference names */
+	Alias	   *alias;			/* user-written alias clause, if any */
+	Alias	   *eref;			/* expanded reference names */
 	bool		inh;			/* inheritance requested? */
 	bool		inFromCl;		/* present in FROM clause */
 	bool		checkForRead;	/* check rel for read access */
@@ -570,7 +602,7 @@ typedef SortClause GroupClause;
 typedef struct InsertStmt
 {
 	NodeTag		type;
-	char	   *relname;		/* relation to insert into */
+	RangeVar   *relation;		/* relation to insert into */
 	List	   *cols;			/* optional: names of the target columns */
 
 	/*
@@ -589,9 +621,8 @@ typedef struct InsertStmt
 typedef struct DeleteStmt
 {
 	NodeTag		type;
-	char	   *relname;		/* relation to delete from */
+	RangeVar   *relation;		/* relation to delete from */
 	Node	   *whereClause;	/* qualifications */
-	InhOption	inhOpt;			/* recursively act on children? */
 } DeleteStmt;
 
 /* ----------------------
@@ -601,11 +632,10 @@ typedef struct DeleteStmt
 typedef struct UpdateStmt
 {
 	NodeTag		type;
-	char	   *relname;		/* relation to update */
+	RangeVar   *relation;		/* relation to update */
 	List	   *targetList;		/* the target list (of ResTarget) */
 	Node	   *whereClause;	/* qualifications */
-	List	   *fromClause;		/* the from clause */
-	InhOption	inhOpt;			/* recursively act on children? */
+	List	   *fromClause;		/* optional from clause for more tables */
 } UpdateStmt;
 
 /* ----------------------
@@ -639,8 +669,7 @@ typedef struct SelectStmt
 	List	   *distinctClause; /* NULL, list of DISTINCT ON exprs, or
 								 * lcons(NIL,NIL) for all (SELECT
 								 * DISTINCT) */
-	char	   *into;			/* name of table (for select into table) */
-	bool		istemp;			/* into is a temp table? */
+	RangeVar   *into;			/* target table (for select into table) */
 	List	   *intoColNames;	/* column names for into table */
 	List	   *targetList;		/* the target list (of ResTarget) */
 	List	   *fromClause;		/* the FROM clause */
@@ -703,6 +732,22 @@ typedef struct SetOperationStmt
  *		field in Query.
  *****************************************************************************/
 
+/* ----------------------
+ *		Create Schema Statement
+ *
+ * NOTE: the schemaElts list contains raw parsetrees for component statements
+ * of the schema, such as CREATE TABLE, GRANT, etc.  These are analyzed and
+ * executed after the schema itself is created.
+ * ----------------------
+ */
+typedef struct CreateSchemaStmt
+{
+	NodeTag		type;
+	char	   *schemaname;		/* the name of the schema to create */
+	char	   *authid;			/* the owner of the created schema */
+	List	   *schemaElts;		/* schema components (list of parsenodes) */
+} CreateSchemaStmt;
+
 /* ----------------------
  *	Alter Table
  *
@@ -725,8 +770,7 @@ typedef struct AlterTableStmt
 								 *	U = change owner
 								 *------------
 								 */
-	char	   *relname;		/* table to work on */
-	InhOption	inhOpt;			/* recursively act on children? */
+	RangeVar   *relation;		/* table to work on */
 	char	   *name;			/* column or constraint name to act on, or
 								 * new owner */
 	Node	   *def;			/* definition of new column or constraint */
@@ -743,12 +787,12 @@ typedef struct GrantStmt
 	NodeTag		type;
 	bool		is_grant;		/* not revoke */
 	int			objtype;
-	List	   *objects;		/* list of names (as Value strings) */
+	List	   *objects;		/* list of names (as Value strings)
+								 * or relations (as RangeVar's) */
 	List	   *privileges;		/* integer list of privilege codes */
 	List	   *grantees;		/* list of PrivGrantee nodes */
 } GrantStmt;
 
-
 typedef struct PrivGrantee
 {
 	NodeTag		type;
@@ -756,7 +800,6 @@ typedef struct PrivGrantee
 	char	   *groupname;
 } PrivGrantee;
 
-
 typedef struct FuncWithArgs
 {
 	NodeTag		type;
@@ -764,7 +807,6 @@ typedef struct FuncWithArgs
 	List	   *funcargs;		/* list of Typename nodes */
 } FuncWithArgs;
 
-
 /* This is only used internally in gram.y. */
 typedef struct PrivTarget
 {
@@ -773,7 +815,6 @@ typedef struct PrivTarget
 	List	   *objs;
 } PrivTarget;
 
-
 /* ----------------------
  *		Close Portal Statement
  * ----------------------
@@ -792,7 +833,7 @@ typedef struct CopyStmt
 {
 	NodeTag		type;
 	bool		binary;			/* is a binary copy? */
-	char	   *relname;		/* the relation to copy */
+	RangeVar   *relation;		/* the relation to copy */
 	bool		oids;			/* copy oid's? */
 	int			direction;		/* TO or FROM */
 	char	   *filename;		/* if NULL, use stdin/stdout */
@@ -813,12 +854,10 @@ typedef struct CopyStmt
 typedef struct CreateStmt
 {
 	NodeTag		type;
-	char	   *relname;		/* name of relation to create */
+	RangeVar   *relation;		/* relation to create */
 	List	   *tableElts;		/* column definitions (list of ColumnDef) */
-	List	   *inhRelnames;	/* relations to inherit from (list of
-								 * T_String Values) */
+	List	   *inhRelations;	/* relations to inherit from */
 	List	   *constraints;	/* constraints (list of Constraint nodes) */
-	bool		istemp;			/* is this a temp table? */
 	bool		hasoids;		/* should it have OIDs? */
 } CreateStmt;
 
@@ -886,7 +925,7 @@ typedef struct FkConstraint
 {
 	NodeTag		type;
 	char	   *constr_name;	/* Constraint name */
-	char	   *pktable_name;	/* Primary key table name */
+	RangeVar   *pktable;		/* Primary key table */
 	List	   *fk_attrs;		/* Attributes of foreign key */
 	List	   *pk_attrs;		/* Corresponding attrs in PK table */
 	char	   *match_type;		/* FULL or PARTIAL */
@@ -904,7 +943,7 @@ typedef struct CreateTrigStmt
 {
 	NodeTag		type;
 	char	   *trigname;		/* TRIGGER' name */
-	char	   *relname;		/* triggered relation */
+	RangeVar   *relation;		/* triggered relation */
 	char	   *funcname;		/* function to call (or NULL) */
 	List	   *args;			/* list of (T_String) Values or NULL */
 	bool		before;			/* BEFORE/AFTER */
@@ -920,14 +959,14 @@ typedef struct CreateTrigStmt
 	bool		isconstraint;	/* This is an RI trigger */
 	bool		deferrable;		/* [NOT] DEFERRABLE */
 	bool		initdeferred;	/* INITIALLY {DEFERRED|IMMEDIATE} */
-	char	   *constrrelname;	/* opposite relation */
+	RangeVar   *constrrel;		/* opposite relation */
 } CreateTrigStmt;
 
 typedef struct DropTrigStmt
 {
 	NodeTag		type;
 	char	   *trigname;		/* TRIGGER' name */
-	char	   *relname;		/* triggered relation */
+	RangeVar   *relation;		/* triggered relation */
 } DropTrigStmt;
 
 /* ----------------------
@@ -1014,8 +1053,7 @@ typedef struct DropGroupStmt
 typedef struct CreateSeqStmt
 {
 	NodeTag		type;
-	char	   *seqname;		/* the relation to create */
-	bool		istemp;			/* is this a temp sequence? */
+	RangeVar   *sequence;		/* the sequence to create */
 	List	   *options;
 } CreateSeqStmt;
 
@@ -1072,7 +1110,7 @@ typedef struct CreateDomainStmt
 typedef struct DropStmt
 {
 	NodeTag		type;
-	List	   *names;
+	List	   *objects;
 	int			removeType;
 	int	   		behavior;		/* CASCADE or RESTRICT drop behavior */
 } DropStmt;
@@ -1084,7 +1122,7 @@ typedef struct DropStmt
 typedef struct TruncateStmt
 {
 	NodeTag		type;
-	char	   *relName;		/* relation to be truncated */
+	RangeVar   *relation;		/* relation to be truncated */
 } TruncateStmt;
 
 /* ----------------------
@@ -1095,6 +1133,8 @@ typedef struct CommentStmt
 {
 	NodeTag		type;
 	int			objtype;		/* Object's type */
+	char	   *objschema;		/* Schema where object is defined,
+								 * if object is schema specific */
 	char	   *objname;		/* Name of the object */
 	char	   *objproperty;	/* Property Id (such as column) */
 	List	   *objlist;		/* Arguments for VAL objects */
@@ -1132,7 +1172,7 @@ typedef struct IndexStmt
 {
 	NodeTag		type;
 	char	   *idxname;		/* name of the index */
-	char	   *relname;		/* name of relation to index on */
+	RangeVar   *relation;		/* relation to build index on */
 	char	   *accessMethod;	/* name of access method (eg. btree) */
 	List	   *indexParams;	/* a list of IndexElem */
 	Node	   *whereClause;	/* qualification (partial-index predicate) */
@@ -1192,14 +1232,13 @@ typedef struct RemoveOperStmt
 } RemoveOperStmt;
 
 /* ----------------------
- *		Alter Table Statement
+ *		Alter Table Rename Statement
  * ----------------------
  */
 typedef struct RenameStmt
 {
 	NodeTag		type;
-	char	   *relname;		/* relation to be altered */
-	InhOption	inhOpt;			/* recursively act on children? */
+	RangeVar   *relation;		/* relation to be altered */
 	char	   *column;			/* if NULL, rename the relation name to
 								 * the new name. Otherwise, rename this
 								 * column name. */
@@ -1213,10 +1252,10 @@ typedef struct RenameStmt
 typedef struct RuleStmt
 {
 	NodeTag		type;
+	RangeVar   *relation;		/* relation the rule is for */
 	char	   *rulename;		/* name of the rule */
 	Node	   *whereClause;	/* qualifications */
-	CmdType		event;			/* RETRIEVE */
-	struct Attr *object;		/* object affected */
+	CmdType		event;			/* SELECT, INSERT, etc */
 	bool		instead;		/* is a 'do instead'? */
 	List	   *actions;		/* the action statements */
 } RuleStmt;
@@ -1228,7 +1267,7 @@ typedef struct RuleStmt
 typedef struct NotifyStmt
 {
 	NodeTag		type;
-	char	   *relname;		/* relation to notify */
+	RangeVar   *relation;		/* qualified name to notify */
 } NotifyStmt;
 
 /* ----------------------
@@ -1238,7 +1277,7 @@ typedef struct NotifyStmt
 typedef struct ListenStmt
 {
 	NodeTag		type;
-	char	   *relname;		/* relation to listen on */
+	RangeVar   *relation;		/* qualified name to listen on */
 } ListenStmt;
 
 /* ----------------------
@@ -1248,7 +1287,7 @@ typedef struct ListenStmt
 typedef struct UnlistenStmt
 {
 	NodeTag		type;
-	char	   *relname;		/* relation to unlisten on */
+	RangeVar   *relation;		/* qualified name to unlisten on, or '*' */
 } UnlistenStmt;
 
 /* ----------------------
@@ -1268,7 +1307,7 @@ typedef struct TransactionStmt
 typedef struct ViewStmt
 {
 	NodeTag		type;
-	char	   *viewname;		/* name of the view */
+	RangeVar   *view;			/* the view to be created */
 	List	   *aliases;		/* target column names */
 	Query	   *query;			/* the SQL statement */
 } ViewStmt;
@@ -1283,7 +1322,6 @@ typedef struct LoadStmt
 	char	   *filename;		/* file to load */
 } LoadStmt;
 
-
 /* ----------------------
  *		Createdb Statement
  * ----------------------
@@ -1327,7 +1365,7 @@ typedef struct DropdbStmt
 typedef struct ClusterStmt
 {
 	NodeTag		type;
-	char	   *relname;		/* relation being indexed */
+	RangeVar   *relation;		/* relation being indexed */
 	char	   *indexname;		/* original index defined */
 } ClusterStmt;
 
@@ -1346,8 +1384,7 @@ typedef struct VacuumStmt
 	bool		analyze;		/* do ANALYZE step */
 	bool		freeze;			/* early-freeze option */
 	bool		verbose;		/* print progress info */
-	char	   *vacrel;			/* name of single table to process, or
-								 * NULL */
+	RangeVar   *relation;		/* single table to process, or NULL */
 	List	   *va_cols;		/* list of column names, or NIL for all */
 } VacuumStmt;
 
@@ -1413,7 +1450,7 @@ typedef struct VariableResetStmt
 typedef struct LockStmt
 {
 	NodeTag		type;
-	List	   *rellist;		/* relations to lock */
+	List	   *relations;		/* relations to lock */
 	int			mode;			/* lock mode */
 } LockStmt;
 
@@ -1436,7 +1473,8 @@ typedef struct ReindexStmt
 {
 	NodeTag		type;
 	int			reindexType;	/* INDEX|TABLE|DATABASE */
-	const char *name;			/* name to reindex */
+	RangeVar   *relation;		/* Table or index to reindex */
+	const char *name;			/* name of database to reindex */
 	bool		force;
 	bool		all;
 } ReindexStmt;
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index 43e4d5a41e20673cc5ee9c4a7705ab060708abf6..f7323058251e7fb142f84a90b0b7931b34013d85 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -10,7 +10,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: primnodes.h,v 1.58 2002/03/12 00:52:02 tgl Exp $
+ * $Id: primnodes.h,v 1.59 2002/03/21 16:01:48 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -508,7 +508,7 @@ typedef struct RangeTblRef
  * If he writes ON() then only "quals" is set.	Note that NATURAL/USING
  * are not equivalent to ON() since they also affect the output column list.
  *
- * alias is an Attr node representing the AS alias-clause attached to the
+ * alias is an Alias node representing the AS alias-clause attached to the
  * join expression, or NULL if no clause.  NB: presence or absence of the
  * alias has a critical impact on semantics, because a join with an alias
  * restricts visibility of the tables/columns inside it.
@@ -527,7 +527,7 @@ typedef struct JoinExpr
 	Node	   *rarg;			/* right subtree */
 	List	   *using;			/* USING clause, if any (list of String) */
 	Node	   *quals;			/* qualifiers on join, if any */
-	struct Attr *alias;			/* user-written alias clause, if any */
+	struct Alias *alias;		/* user-written alias clause, if any */
 	int			rtindex;		/* RT index assigned for join */
 } JoinExpr;
 
diff --git a/src/include/parser/analyze.h b/src/include/parser/analyze.h
index 09cdde3786e2a930235f5205c5106e2ee1b5d947..7d520eef5c3a917a29d664a9d37f8d0082109c5c 100644
--- a/src/include/parser/analyze.h
+++ b/src/include/parser/analyze.h
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: analyze.h,v 1.18 2001/11/05 17:46:34 momjian Exp $
+ * $Id: analyze.h,v 1.19 2002/03/21 16:01:53 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -16,6 +16,7 @@
 #include "parser/parse_node.h"
 
 extern List *parse_analyze(Node *parseTree, ParseState *parentParseState);
+extern List *analyzeCreateSchemaStmt(CreateSchemaStmt *stmt);
 
 extern void CheckSelectForUpdate(Query *qry);
 
diff --git a/src/include/parser/parse_agg.h b/src/include/parser/parse_agg.h
index 22d046e48fc34bd932c5dccaa7e4c5bb5919287b..666e4ede7645706e5b8acc3b434534bba5956b0f 100644
--- a/src/include/parser/parse_agg.h
+++ b/src/include/parser/parse_agg.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parse_agg.h,v 1.20 2001/11/05 17:46:34 momjian Exp $
+ * $Id: parse_agg.h,v 1.21 2002/03/21 16:01:55 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,8 +19,7 @@
 extern void AddAggToParseState(ParseState *pstate, Aggref *aggref);
 extern void parseCheckAggregates(ParseState *pstate, Query *qry, Node *qual);
 extern Aggref *ParseAgg(ParseState *pstate, char *aggname, Oid basetype,
-		 List *args, bool agg_star, bool agg_distinct,
-		 int precedence);
+		 List *args, bool agg_star, bool agg_distinct);
 extern void agg_error(char *caller, char *aggname, Oid basetypeID);
 
 #endif   /* PARSE_AGG_H */
diff --git a/src/include/parser/parse_expr.h b/src/include/parser/parse_expr.h
index 6c906420de74aa793d273b262120597f395bc316..e330f8c249a44a479b0f07d7c4d31aeee1a78c91 100644
--- a/src/include/parser/parse_expr.h
+++ b/src/include/parser/parse_expr.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parse_expr.h,v 1.25 2001/11/05 17:46:34 momjian Exp $
+ * $Id: parse_expr.h,v 1.26 2002/03/21 16:01:59 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -16,13 +16,12 @@
 
 #include "parser/parse_node.h"
 
-#define EXPR_COLUMN_FIRST	1
-#define EXPR_RELATION_FIRST 2
 
+/* GUC parameters */
 extern int	max_expr_depth;
 extern bool Transform_null_equals;
 
-extern Node *transformExpr(ParseState *pstate, Node *expr, int precedence);
+extern Node *transformExpr(ParseState *pstate, Node *expr);
 extern Oid	exprType(Node *expr);
 extern int32 exprTypmod(Node *expr);
 extern bool exprIsLengthCoercion(Node *expr, int32 *coercedTypmod);
diff --git a/src/include/parser/parse_func.h b/src/include/parser/parse_func.h
index ff70080f2173287dc8ce0dacbc533bbe59d6c648..603ea9369c620bfd0db0f6c6ffa442c35d3a3917 100644
--- a/src/include/parser/parse_func.h
+++ b/src/include/parser/parse_func.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parse_func.h,v 1.35 2001/11/05 17:46:35 momjian Exp $
+ * $Id: parse_func.h,v 1.36 2002/03/21 16:02:01 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -47,12 +47,9 @@ typedef enum
 } FuncDetailCode;
 
 
-extern Node *ParseNestedFuncOrColumn(ParseState *pstate, Attr *attr,
-						int precedence);
 extern Node *ParseFuncOrColumn(ParseState *pstate,
 				  char *funcname, List *fargs,
-				  bool agg_star, bool agg_distinct,
-				  int precedence);
+				  bool agg_star, bool agg_distinct, bool is_column);
 
 extern FuncDetailCode func_get_detail(char *funcname, List *fargs,
 				int nargs, Oid *argtypes,
diff --git a/src/include/parser/parse_relation.h b/src/include/parser/parse_relation.h
index 1b579850f4eeac7ce4014c06a5fded3ddc4cc35a..656c70a688a01c1e22db268e8790fe786f6a5883 100644
--- a/src/include/parser/parse_relation.h
+++ b/src/include/parser/parse_relation.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parse_relation.h,v 1.29 2002/03/12 00:52:04 tgl Exp $
+ * $Id: parse_relation.h,v 1.30 2002/03/21 16:02:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -29,12 +29,12 @@ extern Node *qualifiedNameToVar(ParseState *pstate, char *refname,
 				   char *colname, bool implicitRTEOK);
 extern RangeTblEntry *addRangeTableEntry(ParseState *pstate,
 				   char *relname,
-				   Attr *alias,
+				   Alias *alias,
 				   bool inh,
 				   bool inFromCl);
 extern RangeTblEntry *addRangeTableEntryForSubquery(ParseState *pstate,
 							  Query *subquery,
-							  Attr *alias,
+							  Alias *alias,
 							  bool inFromCl);
 extern RangeTblEntry *addRangeTableEntryForJoin(ParseState *pstate,
 						  List *colnames,
@@ -43,7 +43,7 @@ extern RangeTblEntry *addRangeTableEntryForJoin(ParseState *pstate,
 						  List *coltypmods,
 						  List *leftcols,
 						  List *rightcols,
-						  Attr *alias,
+						  Alias *alias,
 						  bool inFromCl);
 extern void addRTEtoQuery(ParseState *pstate, RangeTblEntry *rte,
 			  bool addToJoinList, bool addToNameSpace);
diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out
index 0e01eeaef5a5412e725cc4298ecb2cc7c0d2a9a5..ae5a7f4f635fbc99d6a1cf17086d614ae7241e81 100644
--- a/src/test/regress/expected/alter_table.out
+++ b/src/test/regress/expected/alter_table.out
@@ -396,7 +396,7 @@ drop table atacc1;
 create table atacc1 ( test int );
 -- add a check constraint (fails)
 alter table atacc1 add constraint atacc_test1 check (test1>3);
-ERROR:  Attribute 'test1' not found
+ERROR:  Attribute "test1" not found
 drop table atacc1;
 -- something a little more complicated
 create table atacc1 ( test int, test2 int, test3 int);
diff --git a/src/test/regress/expected/errors.out b/src/test/regress/expected/errors.out
index f767c875a9b47632e3f81cc93859a2c0e1146b00..625c6d7499d8ac8f3585e37cf016ad00a35c3f05 100644
--- a/src/test/regress/expected/errors.out
+++ b/src/test/regress/expected/errors.out
@@ -22,19 +22,19 @@ select * from nonesuch;
 ERROR:  parser: parse error at or near "select"
 -- bad name in target list
 select nonesuch from pg_database;
-ERROR:  Attribute 'nonesuch' not found
+ERROR:  Attribute "nonesuch" not found
 -- bad attribute name on lhs of operator
 select * from pg_database where nonesuch = pg_database.datname;
-ERROR:  Attribute 'nonesuch' not found
+ERROR:  Attribute "nonesuch" not found
 -- bad attribute name on rhs of operator
 select * from pg_database where pg_database.datname = nonesuch;
-ERROR:  Attribute 'nonesuch' not found
+ERROR:  Attribute "nonesuch" not found
 -- bad select distinct on syntax, distinct attribute missing
 select distinct on (foobar) from pg_database;
 ERROR:  parser: parse error at or near "from"
 -- bad select distinct on syntax, distinct attribute not in target list
 select distinct on (foobar) * from pg_database;
-ERROR:  Attribute 'foobar' not found
+ERROR:  Attribute "foobar" not found
 --
 -- DELETE
  
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 4f54ed3a7cc2fd616408b624c83d1c1330fc17c7..8633aa56708abdcdc1d2aeb2d457b40117295858 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1177,7 +1177,7 @@ drop rule foorule;
 -- this should fail because f1 is not exposed for unqualified reference:
 create rule foorule as on insert to foo where f1 < 100
 do instead insert into foo2 values (f1);
-ERROR:  Attribute 'f1' not found
+ERROR:  Attribute "f1" not found
 -- this is the correct way:
 create rule foorule as on insert to foo where f1 < 100
 do instead insert into foo2 values (new.f1);
diff --git a/src/test/regress/expected/union.out b/src/test/regress/expected/union.out
index fb24220156004d9688ed212c6a7d33711e99ae70..0adad8c119d314a4572789ba47287651fdade9ee 100644
--- a/src/test/regress/expected/union.out
+++ b/src/test/regress/expected/union.out
@@ -406,7 +406,7 @@ ORDER BY q2,q1;
 
 -- This should fail, because q2 isn't a name of an EXCEPT output column
 SELECT q1 FROM int8_tbl EXCEPT SELECT q2 FROM int8_tbl ORDER BY q2 LIMIT 1;
-ERROR:  Attribute 'q2' not found
+ERROR:  Attribute "q2" not found
 -- But this should work:
 SELECT q1 FROM int8_tbl EXCEPT (((SELECT q2 FROM int8_tbl ORDER BY q2 LIMIT 1)));
         q1        
diff --git a/src/test/regress/input/misc.source b/src/test/regress/input/misc.source
index 9c7a707f1c0efd498c591035f787a5ebdd9d15c3..18bf4e8af7d778be8a4cf7ddbdb496068b405034 100644
--- a/src/test/regress/input/misc.source
+++ b/src/test/regress/input/misc.source
@@ -170,44 +170,44 @@ SELECT class, aa, a FROM a_star*;
 -- joe and sally play basketball, and
 -- everyone else does nothing.
 --
-SELECT p.name, p.hobbies.name FROM ONLY person p;
+SELECT p.name, name(p.hobbies) FROM ONLY person p;
 
 --
 -- as above, but jeff also does post_hacking.
 --
-SELECT p.name, p.hobbies.name FROM person* p;
+SELECT p.name, name(p.hobbies) FROM person* p;
 
 --
 -- the next two queries demonstrate how functions generate bogus duplicates.
 -- this is a "feature" ..
 --
-SELECT DISTINCT hobbies_r.name, hobbies_r.equipment.name FROM hobbies_r;
+SELECT DISTINCT hobbies_r.name, name(hobbies_r.equipment) FROM hobbies_r;
 
-SELECT hobbies_r.name, hobbies_r.equipment.name FROM hobbies_r;
+SELECT hobbies_r.name, (hobbies_r.equipment).name FROM hobbies_r;
 
 --
 -- mike needs advil and peet's coffee,
 -- joe and sally need hightops, and
 -- everyone else is fine.
 --
-SELECT p.name, p.hobbies.name, p.hobbies.equipment.name FROM ONLY person p;
+SELECT p.name, name(p.hobbies), name(equipment(p.hobbies)) FROM ONLY person p;
 
 --
 -- as above, but jeff needs advil and peet's coffee as well.
 --
-SELECT p.name, p.hobbies.name, p.hobbies.equipment.name FROM person* p;
+SELECT p.name, name(p.hobbies), name(equipment(p.hobbies)) FROM person* p;
 
 --
 -- just like the last two, but make sure that the target list fixup and
 -- unflattening is being done correctly.
 --
-SELECT p.hobbies.equipment.name, p.name, p.hobbies.name FROM ONLY person p;
+SELECT name(equipment(p.hobbies)), p.name, name(p.hobbies) FROM ONLY person p;
 
-SELECT p.hobbies.equipment.name, p.name, p.hobbies.name FROM person* p;
+SELECT (p.hobbies).equipment.name, p.name, name(p.hobbies) FROM person* p;
 
-SELECT p.hobbies.equipment.name, p.hobbies.name, p.name FROM ONLY person p;
+SELECT (p.hobbies).equipment.name, name(p.hobbies), p.name FROM ONLY person p;
 
-SELECT p.hobbies.equipment.name, p.hobbies.name, p.name FROM person* p;
+SELECT name(equipment(p.hobbies)), name(p.hobbies), p.name FROM person* p;
 
 SELECT user_relns() AS user_relns
    ORDER BY user_relns;
diff --git a/src/test/regress/output/misc.source b/src/test/regress/output/misc.source
index e3a5109a02c7c79ac3a267ac3fbd7c96c2f4ac54..971ccfca10c72514032ce146db2370b91a862ba2 100644
--- a/src/test/regress/output/misc.source
+++ b/src/test/regress/output/misc.source
@@ -442,7 +442,7 @@ SELECT class, aa, a FROM a_star*;
 -- joe and sally play basketball, and
 -- everyone else does nothing.
 --
-SELECT p.name, p.hobbies.name FROM ONLY person p;
+SELECT p.name, name(p.hobbies) FROM ONLY person p;
  name  |    name     
 -------+-------------
  mike  | posthacking
@@ -453,7 +453,7 @@ SELECT p.name, p.hobbies.name FROM ONLY person p;
 --
 -- as above, but jeff also does post_hacking.
 --
-SELECT p.name, p.hobbies.name FROM person* p;
+SELECT p.name, name(p.hobbies) FROM person* p;
  name  |    name     
 -------+-------------
  mike  | posthacking
@@ -466,7 +466,7 @@ SELECT p.name, p.hobbies.name FROM person* p;
 -- the next two queries demonstrate how functions generate bogus duplicates.
 -- this is a "feature" ..
 --
-SELECT DISTINCT hobbies_r.name, hobbies_r.equipment.name FROM hobbies_r;
+SELECT DISTINCT hobbies_r.name, name(hobbies_r.equipment) FROM hobbies_r;
     name     |     name      
 -------------+---------------
  basketball  | hightops
@@ -475,7 +475,7 @@ SELECT DISTINCT hobbies_r.name, hobbies_r.equipment.name FROM hobbies_r;
  skywalking  | guts
 (4 rows)
 
-SELECT hobbies_r.name, hobbies_r.equipment.name FROM hobbies_r;
+SELECT hobbies_r.name, (hobbies_r.equipment).name FROM hobbies_r;
     name     |     name      
 -------------+---------------
  posthacking | advil
@@ -492,7 +492,7 @@ SELECT hobbies_r.name, hobbies_r.equipment.name FROM hobbies_r;
 -- joe and sally need hightops, and
 -- everyone else is fine.
 --
-SELECT p.name, p.hobbies.name, p.hobbies.equipment.name FROM ONLY person p;
+SELECT p.name, name(p.hobbies), name(equipment(p.hobbies)) FROM ONLY person p;
  name  |    name     |     name      
 -------+-------------+---------------
  mike  | posthacking | advil
@@ -504,7 +504,7 @@ SELECT p.name, p.hobbies.name, p.hobbies.equipment.name FROM ONLY person p;
 --
 -- as above, but jeff needs advil and peet's coffee as well.
 --
-SELECT p.name, p.hobbies.name, p.hobbies.equipment.name FROM person* p;
+SELECT p.name, name(p.hobbies), name(equipment(p.hobbies)) FROM person* p;
  name  |    name     |     name      
 -------+-------------+---------------
  mike  | posthacking | advil
@@ -519,7 +519,7 @@ SELECT p.name, p.hobbies.name, p.hobbies.equipment.name FROM person* p;
 -- just like the last two, but make sure that the target list fixup and
 -- unflattening is being done correctly.
 --
-SELECT p.hobbies.equipment.name, p.name, p.hobbies.name FROM ONLY person p;
+SELECT name(equipment(p.hobbies)), p.name, name(p.hobbies) FROM ONLY person p;
      name      | name  |    name     
 ---------------+-------+-------------
  advil         | mike  | posthacking
@@ -528,7 +528,7 @@ SELECT p.hobbies.equipment.name, p.name, p.hobbies.name FROM ONLY person p;
  hightops      | sally | basketball
 (4 rows)
 
-SELECT p.hobbies.equipment.name, p.name, p.hobbies.name FROM person* p;
+SELECT (p.hobbies).equipment.name, p.name, name(p.hobbies) FROM person* p;
      name      | name  |    name     
 ---------------+-------+-------------
  advil         | mike  | posthacking
@@ -539,7 +539,7 @@ SELECT p.hobbies.equipment.name, p.name, p.hobbies.name FROM person* p;
  peet's coffee | jeff  | posthacking
 (6 rows)
 
-SELECT p.hobbies.equipment.name, p.hobbies.name, p.name FROM ONLY person p;
+SELECT (p.hobbies).equipment.name, name(p.hobbies), p.name FROM ONLY person p;
      name      |    name     | name  
 ---------------+-------------+-------
  advil         | posthacking | mike
@@ -548,7 +548,7 @@ SELECT p.hobbies.equipment.name, p.hobbies.name, p.name FROM ONLY person p;
  hightops      | basketball  | sally
 (4 rows)
 
-SELECT p.hobbies.equipment.name, p.hobbies.name, p.name FROM person* p;
+SELECT name(equipment(p.hobbies)), name(p.hobbies), p.name FROM person* p;
      name      |    name     | name  
 ---------------+-------------+-------
  advil         | posthacking | mike