diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 10116364560acd50856cf663f444b5a5e30f24ea..458ab68749dd25e9a6437d497fda51fc8d8980f8 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.118 2002/08/26 17:53:58 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.119 2002/08/29 01:19:41 tgl Exp $
  *
  *	  This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -61,6 +61,7 @@
 #include "parser/parse_expr.h"
 #include "parser/parse_func.h"
 #include "parser/parse_oper.h"
+#include "parser/parse_type.h"
 #include "parser/parsetree.h"
 #include "rewrite/rewriteManip.h"
 #include "rewrite/rewriteSupport.h"
@@ -157,6 +158,8 @@ static void get_sublink_expr(Node *node, deparse_context *context);
 static void get_from_clause(Query *query, deparse_context *context);
 static void get_from_clause_item(Node *jtnode, Query *query,
 					 deparse_context *context);
+static void get_from_clause_coldeflist(List *coldeflist,
+									   deparse_context *context);
 static void get_opclass_name(Oid opclass, Oid actual_datatype,
 				 StringInfo buf);
 static bool tleIsArrayAssign(TargetEntry *tle);
@@ -2749,6 +2752,8 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
 	{
 		int			varno = ((RangeTblRef *) jtnode)->rtindex;
 		RangeTblEntry *rte = rt_fetch(varno, query->rtable);
+		List	   *coldeflist = NIL;
+		bool		gavealias = false;
 
 		switch (rte->rtekind)
 		{
@@ -2767,6 +2772,8 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
 			case RTE_FUNCTION:
 				/* Function RTE */
 				get_rule_expr(rte->funcexpr, context);
+				/* might need to emit column list for RECORD function */
+				coldeflist = rte->coldeflist;
 				break;
 			default:
 				elog(ERROR, "unexpected rte kind %d", (int) rte->rtekind);
@@ -2776,7 +2783,8 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
 		{
 			appendStringInfo(buf, " %s",
 							 quote_identifier(rte->alias->aliasname));
-			if (rte->alias->colnames != NIL)
+			gavealias = true;
+			if (rte->alias->colnames != NIL && coldeflist == NIL)
 			{
 				List	   *col;
 
@@ -2802,6 +2810,13 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
 			 */
 			appendStringInfo(buf, " %s",
 							 quote_identifier(rte->eref->aliasname));
+			gavealias = true;
+		}
+		if (coldeflist != NIL)
+		{
+			if (!gavealias)
+				appendStringInfo(buf, " AS ");
+			get_from_clause_coldeflist(coldeflist, context);
 		}
 	}
 	else if (IsA(jtnode, JoinExpr))
@@ -2887,6 +2902,43 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
 			 nodeTag(jtnode));
 }
 
+/*
+ * get_from_clause_coldeflist - reproduce FROM clause coldeflist
+ *
+ * The coldeflist is appended immediately (no space) to buf.  Caller is
+ * responsible for ensuring that an alias or AS is present before it.
+ */
+static void
+get_from_clause_coldeflist(List *coldeflist, deparse_context *context)
+{
+	StringInfo	buf = context->buf;
+	List	   *col;
+	int			i = 0;
+
+	appendStringInfoChar(buf, '(');
+
+	foreach(col, coldeflist)
+	{
+		ColumnDef  *n = lfirst(col);
+		char	   *attname;
+		Oid			atttypeid;
+		int32		atttypmod;
+
+		attname = n->colname;
+		atttypeid = typenameTypeId(n->typename);
+		atttypmod = n->typename->typmod;
+
+		if (i > 0)
+			appendStringInfo(buf, ", ");
+		appendStringInfo(buf, "%s %s",
+						 quote_identifier(attname),
+						 format_type_with_typemod(atttypeid, atttypmod));
+		i++;
+	}
+
+	appendStringInfoChar(buf, ')');
+}
+
 /*
  * get_opclass_name			- fetch name of an index operator class
  *
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index a8a1a9b24a15d54e9e8af49b156de7cda75d47fc..77420cd2b2dc266ece14661ba4a67c0d806e7280 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1268,9 +1268,9 @@ SELECT viewname, definition FROM pg_views ORDER BY viewname;
 --------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  iexit                    | SELECT ih.name, ih.thepath, interpt_pp(ih.thepath, r.thepath) AS exit FROM ihighway ih, ramp r WHERE (ih.thepath ## r.thepath);
  pg_indexes               | SELECT n.nspname AS schemaname, c.relname AS tablename, i.relname AS indexname, pg_get_indexdef(i.oid) AS indexdef FROM (((pg_index x JOIN pg_class c ON ((c.oid = x.indrelid))) JOIN pg_class i ON ((i.oid = x.indexrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE ((c.relkind = 'r'::"char") AND (i.relkind = 'i'::"char"));
- pg_locks                 | SELECT l.relation, l."database", l.backendpid, l."mode", l.isgranted FROM pg_lock_status() l;
+ pg_locks                 | SELECT l.relation, l."database", l.backendpid, l."mode", l.isgranted FROM pg_lock_status() l(relation oid, "database" oid, backendpid integer, "mode" text, isgranted boolean);
  pg_rules                 | SELECT n.nspname AS schemaname, c.relname AS tablename, r.rulename, pg_get_ruledef(r.oid) AS definition FROM ((pg_rewrite r JOIN pg_class c ON ((c.oid = r.ev_class))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (r.rulename <> '_RETURN'::name);
- pg_settings              | SELECT a.name, a.setting FROM pg_show_all_settings() a;
+ pg_settings              | SELECT a.name, a.setting FROM pg_show_all_settings() a(name text, setting text);
  pg_stat_activity         | SELECT d.oid AS datid, d.datname, pg_stat_get_backend_pid(s.backendid) AS procpid, pg_stat_get_backend_userid(s.backendid) AS usesysid, u.usename, pg_stat_get_backend_activity(s.backendid) AS current_query FROM pg_database d, (SELECT pg_stat_get_backend_idset() AS backendid) s, pg_shadow u WHERE ((pg_stat_get_backend_dbid(s.backendid) = d.oid) AND (pg_stat_get_backend_userid(s.backendid) = u.usesysid));
  pg_stat_all_indexes      | SELECT c.oid AS relid, i.oid AS indexrelid, n.nspname AS schemaname, c.relname, i.relname AS indexrelname, pg_stat_get_numscans(i.oid) AS idx_scan, pg_stat_get_tuples_returned(i.oid) AS idx_tup_read, pg_stat_get_tuples_fetched(i.oid) AS idx_tup_fetch FROM (((pg_class c JOIN pg_index x ON ((c.oid = x.indrelid))) JOIN pg_class i ON ((i.oid = x.indexrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (c.relkind = 'r'::"char");
  pg_stat_all_tables       | SELECT c.oid AS relid, n.nspname AS schemaname, c.relname, pg_stat_get_numscans(c.oid) AS seq_scan, pg_stat_get_tuples_returned(c.oid) AS seq_tup_read, sum(pg_stat_get_numscans(i.indexrelid)) AS idx_scan, sum(pg_stat_get_tuples_fetched(i.indexrelid)) AS idx_tup_fetch, pg_stat_get_tuples_inserted(c.oid) AS n_tup_ins, pg_stat_get_tuples_updated(c.oid) AS n_tup_upd, pg_stat_get_tuples_deleted(c.oid) AS n_tup_del FROM ((pg_class c LEFT JOIN pg_index i ON ((c.oid = i.indrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (c.relkind = 'r'::"char") GROUP BY c.oid, n.nspname, c.relname;