diff --git a/src/backend/nodes/print.c b/src/backend/nodes/print.c
index 7bf78e134bc3968e35c174a73498d4fc69374acd..3f48cb0b9eb3369cdbcf2e3bed4d7833ee024ba3 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.40 2000/09/12 21:06:49 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.41 2000/09/25 18:14:55 tgl Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -172,11 +172,13 @@ print_expr(Node *expr, List *rtable)
 				break;
 			default:
 				{
-					RangeTblEntry *rt;
+					RangeTblEntry *rte;
 
-					rt = rt_fetch(var->varno, rtable);
-					relname = rt->eref->relname;
-					attname = get_attname(rt->relid, var->varattno);
+					Assert(var->varno > 0 &&
+						   (int) var->varno <= length(rtable));
+					rte = rt_fetch(var->varno, rtable);
+					relname = rte->eref->relname;
+					attname = get_rte_attribute_name(rte, var->varattno);
 				}
 				break;
 		}
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 36c7abd85b53de76b720f6ac6a7fc0fc2a58baa5..9f371ff739fe068d68c0fc4f1365651004ec6dfa 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.74 2000/09/12 21:06:58 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.75 2000/09/25 18:14:55 tgl Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -584,12 +584,9 @@ check_subplans_for_ungrouped_vars_walker(Node *node,
 				char	   *attname;
 
 				Assert(var->varno > 0 &&
-					   var->varno <= length(context->rtable));
+					   (int) var->varno <= length(context->rtable));
 				rte = rt_fetch(var->varno, context->rtable);
-				attname = get_attname(rte->relid, var->varattno);
-				if (!attname)
-					elog(ERROR, "cache lookup of attribute %d in relation %u failed",
-						 var->varattno, rte->relid);
+				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);
 			}
diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c
index 955be022e4e235b7ad401dc9a64ffec798880c48..c3ac417365c4299838c058c57223c39654e9e0f4 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.40 2000/09/12 21:07:02 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.41 2000/09/25 18:14:54 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -113,10 +113,7 @@ check_ungrouped_columns_walker(Node *node,
 		Assert(var->varno > 0 &&
 			   (int) var->varno <= length(context->pstate->p_rtable));
 		rte = rt_fetch(var->varno, context->pstate->p_rtable);
-		attname = get_attname(rte->relid, var->varattno);
-		if (!attname)
-			elog(ERROR, "cache lookup of attribute %d in relation %u failed",
-				 var->varattno, rte->relid);
+		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);
 	}
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index 491cbc5ef08780cfec069a90d487b1e187f34630..baae0a578cf49d54ed795840cb6e64d49b53b546 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.47 2000/09/12 21:07:02 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.48 2000/09/25 18:14:54 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -713,6 +713,43 @@ expandNamesVars(ParseState *pstate, List *names, List *vars)
 	return te_list;
 }
 
+/* ----------
+ * get_rte_attribute_name
+ *		Get an attribute name from a RangeTblEntry
+ *
+ * This is unlike get_attname() because we use aliases if available.
+ * In particular, it will work on an RTE for a subselect, whereas
+ * get_attname() only works on real relations.
+ * ----------
+ */
+char *
+get_rte_attribute_name(RangeTblEntry *rte, AttrNumber attnum)
+{
+	char	   *attname;
+
+	/*
+	 * If there is an alias, use it
+	 */
+	if (attnum > 0 && attnum <= length(rte->eref->attrs))
+		return strVal(nth(attnum-1, rte->eref->attrs));
+	/*
+	 * Can get here for a system attribute (which never has an alias),
+	 * or if alias name list is too short (which probably can't happen
+	 * anymore).  Neither of these cases is valid for a subselect RTE.
+	 */
+	if (rte->relid == InvalidOid)
+		elog(ERROR, "Invalid attnum %d for rangetable entry %s",
+			 attnum, rte->eref->relname);
+	/*
+	 * Use the real name of the table's column
+	 */
+	attname = get_attname(rte->relid, attnum);
+	if (attname == NULL)
+		elog(ERROR, "cache lookup of attribute %d in relation %u failed",
+			 attnum, rte->relid);
+	return attname;
+}
+
 /*
  *	given relation and att name, return id of variable
  *
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 45282fd94c848546af1674902f8cba6e30af3d49..2eaef859f48d6973a3b6563e5c38ccf7b78e977e 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.62 2000/09/18 20:14:23 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.63 2000/09/25 18:14:54 tgl Exp $
  *
  *	  This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -110,7 +110,6 @@ static bool tleIsArrayAssign(TargetEntry *tle);
 static char *quote_identifier(char *ident);
 static char *get_relation_name(Oid relid);
 static char *get_relid_attribute_name(Oid relid, AttrNumber attnum);
-static char *get_rte_attribute_name(RangeTblEntry *rte, AttrNumber attnum);
 
 #define only_marker(rte)  ((rte)->inh ? "" : "ONLY ")
 
@@ -2020,33 +2019,3 @@ get_relid_attribute_name(Oid relid, AttrNumber attnum)
 			 attnum, relid);
 	return attname;
 }
-
-/* ----------
- * get_rte_attribute_name
- *		Get an attribute name from a RangeTblEntry
- *
- * This is unlike get_relid_attribute_name() because we use aliases if
- * available.
- * ----------
- */
-static char *
-get_rte_attribute_name(RangeTblEntry *rte, AttrNumber attnum)
-{
-	/*
-	 * If there is an alias, use it
-	 */
-	if (attnum > 0 && attnum <= length(rte->eref->attrs))
-		return strVal(nth(attnum-1, rte->eref->attrs));
-	/*
-	 * Can get here for a system attribute (which never has an alias),
-	 * or if alias name list is too short (which probably can't happen
-	 * anymore).  Neither of these cases is valid for a subselect RTE.
-	 */
-	if (rte->relid == InvalidOid)
-		elog(ERROR, "Invalid attnum %d for rangetable entry %s",
-			 attnum, rte->eref->relname);
-	/*
-	 * Use the real name of the table's column
-	 */
-	return get_relid_attribute_name(rte->relid, attnum);
-}
diff --git a/src/include/parser/parsetree.h b/src/include/parser/parsetree.h
index ff727cfd07a6229f26852d09f7ed3125b393deb4..4936bbdb47c9ba5e2db81e9b662c3d69468e9e75 100644
--- a/src/include/parser/parsetree.h
+++ b/src/include/parser/parsetree.h
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parsetree.h,v 1.11 2000/09/12 21:07:12 tgl Exp $
+ * $Id: parsetree.h,v 1.12 2000/09/25 18:14:53 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -16,12 +16,8 @@
 #define PARSETREE_H
 
 #include "nodes/parsenodes.h"
-#include "nodes/pg_list.h"
+#include "nodes/pg_list.h"		/* for nth(), etc */
 
-/* ----------------
- *		need pg_list.h for definitions of nth(), etc.
- * ----------------
- */
 
 /* ----------------
  *		range table macros
@@ -33,10 +29,9 @@
  *		rt_store
  *
  *		Access and (destructively) replace rangetable entries.
- *
  */
 #define rt_fetch(rangetable_index, rangetable) \
-	((RangeTblEntry*) nth((rangetable_index)-1, rangetable))
+	((RangeTblEntry *) nth((rangetable_index)-1, rangetable))
 
 #define rt_store(rangetable_index, rangetable, rt) \
 	set_nth(rangetable, (rangetable_index)-1, rt)
@@ -45,9 +40,16 @@
  *		getrelid
  *
  *		Given the range index of a relation, return the corresponding
- *		relation OID.
+ *		relation OID.  Note that InvalidOid will be returned if the
+ *		RTE is for a sub-select rather than a relation.
  */
 #define getrelid(rangeindex,rangetable) \
 	(rt_fetch(rangeindex, rangetable)->relid)
 
+/*
+ * Given an RTE and an attribute number, return the appropriate
+ * variable name or alias for that attribute of that RTE.
+ */
+extern char *get_rte_attribute_name(RangeTblEntry *rte, AttrNumber attnum);
+
 #endif	 /* PARSETREE_H */