diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 51391f6a4e0d16e4e647f7845425e11795ca7508..3388f7c17ea92e0326859536c980e51cba7c150d 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -391,6 +391,8 @@ static void appendContextKeyword(deparse_context *context, const char *str,
 static void removeStringInfoSpaces(StringInfo str);
 static void get_rule_expr(Node *node, deparse_context *context,
 			  bool showimplicit);
+static void get_rule_expr_toplevel(Node *node, deparse_context *context,
+					   bool showimplicit);
 static void get_oper_expr(OpExpr *expr, deparse_context *context);
 static void get_func_expr(FuncExpr *expr, deparse_context *context,
 			  bool showimplicit);
@@ -4347,10 +4349,10 @@ get_values_def(List *values_lists, deparse_context *context)
 
 			/*
 			 * Strip any top-level nodes representing indirection assignments,
-			 * then print the result.
+			 * then print the result.  Whole-row Vars need special treatment.
 			 */
-			get_rule_expr(processIndirection(col, context, false),
-						  context, false);
+			get_rule_expr_toplevel(processIndirection(col, context, false),
+								   context, false);
 		}
 		appendStringInfoChar(buf, ')');
 	}
@@ -4771,7 +4773,8 @@ get_target_list(List *targetList, deparse_context *context,
 		 * the top level of a SELECT list it's not right (the parser will
 		 * expand that notation into multiple columns, yielding behavior
 		 * different from a whole-row Var).  We need to call get_variable
-		 * directly so that we can tell it to do the right thing.
+		 * directly so that we can tell it to do the right thing, and so that
+		 * we can get the attribute name which is the default AS label.
 		 */
 		if (tle->expr && (IsA(tle->expr, Var)))
 		{
@@ -7515,7 +7518,8 @@ get_rule_expr(Node *node, deparse_context *context,
 						!tupdesc->attrs[i]->attisdropped)
 					{
 						appendStringInfoString(buf, sep);
-						get_rule_expr(e, context, true);
+						/* Whole-row Vars need special treatment here */
+						get_rule_expr_toplevel(e, context, true);
 						sep = ", ";
 					}
 					i++;
@@ -7941,6 +7945,27 @@ get_rule_expr(Node *node, deparse_context *context,
 	}
 }
 
+/*
+ * get_rule_expr_toplevel		- Parse back a toplevel expression
+ *
+ * Same as get_rule_expr(), except that if the expr is just a Var, we pass
+ * istoplevel = true not false to get_variable().  This causes whole-row Vars
+ * to get printed with decoration that will prevent expansion of "*".
+ * We need to use this in contexts such as ROW() and VALUES(), where the
+ * parser would expand "foo.*" appearing at top level.  (In principle we'd
+ * use this in get_target_list() too, but that has additional worries about
+ * whether to print AS, so it needs to invoke get_variable() directly anyway.)
+ */
+static void
+get_rule_expr_toplevel(Node *node, deparse_context *context,
+					   bool showimplicit)
+{
+	if (node && IsA(node, Var))
+		(void) get_variable((Var *) node, 0, true, context);
+	else
+		get_rule_expr(node, context, showimplicit);
+}
+
 
 /*
  * get_oper_expr			- Parse back an OpExpr node
diff --git a/src/test/regress/expected/create_view.out b/src/test/regress/expected/create_view.out
index e2d427667593d91154fc7f766707f842d0bf82dd..3e4d424ecadaf6e086b7caad086432f76fd2e220 100644
--- a/src/test/regress/expected/create_view.out
+++ b/src/test/regress/expected/create_view.out
@@ -1384,6 +1384,97 @@ select * from tt14v;
  foo |    | quux
 (1 row)
 
+-- check display of whole-row variables in some corner cases
+create type nestedcomposite as (x int8_tbl);
+create view tt15v as select row(i)::nestedcomposite from int8_tbl i;
+select * from tt15v;
+                   row                    
+------------------------------------------
+ ("(123,456)")
+ ("(123,4567890123456789)")
+ ("(4567890123456789,123)")
+ ("(4567890123456789,4567890123456789)")
+ ("(4567890123456789,-4567890123456789)")
+(5 rows)
+
+select pg_get_viewdef('tt15v', true);
+                    pg_get_viewdef                    
+------------------------------------------------------
+  SELECT ROW(i.*::int8_tbl)::nestedcomposite AS "row"+
+    FROM int8_tbl i;
+(1 row)
+
+select row(i.*::int8_tbl)::nestedcomposite from int8_tbl i;
+                   row                    
+------------------------------------------
+ ("(123,456)")
+ ("(123,4567890123456789)")
+ ("(4567890123456789,123)")
+ ("(4567890123456789,4567890123456789)")
+ ("(4567890123456789,-4567890123456789)")
+(5 rows)
+
+create view tt16v as select * from int8_tbl i, lateral(values(i)) ss;
+select * from tt16v;
+        q1        |        q2         |               column1                
+------------------+-------------------+--------------------------------------
+              123 |               456 | (123,456)
+              123 |  4567890123456789 | (123,4567890123456789)
+ 4567890123456789 |               123 | (4567890123456789,123)
+ 4567890123456789 |  4567890123456789 | (4567890123456789,4567890123456789)
+ 4567890123456789 | -4567890123456789 | (4567890123456789,-4567890123456789)
+(5 rows)
+
+select pg_get_viewdef('tt16v', true);
+              pg_get_viewdef               
+-------------------------------------------
+  SELECT i.q1,                            +
+     i.q2,                                +
+     ss.column1                           +
+    FROM int8_tbl i,                      +
+     LATERAL ( VALUES (i.*::int8_tbl)) ss;
+(1 row)
+
+select * from int8_tbl i, lateral(values(i.*::int8_tbl)) ss;
+        q1        |        q2         |               column1                
+------------------+-------------------+--------------------------------------
+              123 |               456 | (123,456)
+              123 |  4567890123456789 | (123,4567890123456789)
+ 4567890123456789 |               123 | (4567890123456789,123)
+ 4567890123456789 |  4567890123456789 | (4567890123456789,4567890123456789)
+ 4567890123456789 | -4567890123456789 | (4567890123456789,-4567890123456789)
+(5 rows)
+
+create view tt17v as select * from int8_tbl i where i in (values(i));
+select * from tt17v;
+        q1        |        q2         
+------------------+-------------------
+              123 |               456
+              123 |  4567890123456789
+ 4567890123456789 |               123
+ 4567890123456789 |  4567890123456789
+ 4567890123456789 | -4567890123456789
+(5 rows)
+
+select pg_get_viewdef('tt17v', true);
+               pg_get_viewdef                
+---------------------------------------------
+  SELECT i.q1,                              +
+     i.q2                                   +
+    FROM int8_tbl i                         +
+   WHERE (i.* IN ( VALUES (i.*::int8_tbl)));
+(1 row)
+
+select * from int8_tbl i where i.* in (values(i.*::int8_tbl));
+        q1        |        q2         
+------------------+-------------------
+              123 |               456
+              123 |  4567890123456789
+ 4567890123456789 |               123
+ 4567890123456789 |  4567890123456789
+ 4567890123456789 | -4567890123456789
+(5 rows)
+
 -- clean up all the random objects we made above
 set client_min_messages = warning;
 DROP SCHEMA temp_view_test CASCADE;
diff --git a/src/test/regress/sql/create_view.sql b/src/test/regress/sql/create_view.sql
index d3b3f128bb3eb9098d7e4a675885d078bd6f54b7..bcee90d6146921b4d9f0d3d8035f21202e09f067 100644
--- a/src/test/regress/sql/create_view.sql
+++ b/src/test/regress/sql/create_view.sql
@@ -469,6 +469,24 @@ alter table tt14t drop column f3;
 select pg_get_viewdef('tt14v', true);
 select * from tt14v;
 
+-- check display of whole-row variables in some corner cases
+
+create type nestedcomposite as (x int8_tbl);
+create view tt15v as select row(i)::nestedcomposite from int8_tbl i;
+select * from tt15v;
+select pg_get_viewdef('tt15v', true);
+select row(i.*::int8_tbl)::nestedcomposite from int8_tbl i;
+
+create view tt16v as select * from int8_tbl i, lateral(values(i)) ss;
+select * from tt16v;
+select pg_get_viewdef('tt16v', true);
+select * from int8_tbl i, lateral(values(i.*::int8_tbl)) ss;
+
+create view tt17v as select * from int8_tbl i where i in (values(i));
+select * from tt17v;
+select pg_get_viewdef('tt17v', true);
+select * from int8_tbl i where i.* in (values(i.*::int8_tbl));
+
 -- clean up all the random objects we made above
 set client_min_messages = warning;
 DROP SCHEMA temp_view_test CASCADE;