diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c
index 0e2a220..45d82da 100644
*** a/src/backend/optimizer/prep/prepjointree.c
--- b/src/backend/optimizer/prep/prepjointree.c
*************** pull_up_simple_subquery(PlannerInfo *roo
*** 1003,1013 ****
  
  	/*
  	 * The subquery's targetlist items are now in the appropriate form to
! 	 * insert into the top query, but if we are under an outer join then
! 	 * non-nullable items and lateral references may have to be turned into
! 	 * PlaceHolderVars.  If we are dealing with an appendrel member then
! 	 * anything that's not a simple Var has to be turned into a
! 	 * PlaceHolderVar.  Set up required context data for pullup_replace_vars.
  	 */
  	rvcontext.root = root;
  	rvcontext.targetlist = subquery->targetList;
--- 1003,1010 ----
  
  	/*
  	 * The subquery's targetlist items are now in the appropriate form to
! 	 * insert into the top query, except that we may need to wrap them in
! 	 * PlaceHolderVars.  Set up required context data for pullup_replace_vars.
  	 */
  	rvcontext.root = root;
  	rvcontext.targetlist = subquery->targetList;
*************** pull_up_simple_subquery(PlannerInfo *roo
*** 1019,1032 ****
  		rvcontext.relids = NULL;
  	rvcontext.outer_hasSubLinks = &parse->hasSubLinks;
  	rvcontext.varno = varno;
! 	rvcontext.need_phvs = (lowest_nulling_outer_join != NULL ||
! 						   containing_appendrel != NULL);
! 	rvcontext.wrap_non_vars = (containing_appendrel != NULL);
  	/* initialize cache array with indexes 0 .. length(tlist) */
  	rvcontext.rv_cache = palloc0((list_length(subquery->targetList) + 1) *
  								 sizeof(Node *));
  
  	/*
  	 * Replace all of the top query's references to the subquery's outputs
  	 * with copies of the adjusted subtlist items, being careful not to
  	 * replace any of the jointree structure. (This'd be a lot cleaner if we
--- 1016,1064 ----
  		rvcontext.relids = NULL;
  	rvcontext.outer_hasSubLinks = &parse->hasSubLinks;
  	rvcontext.varno = varno;
! 	/* these flags will be set below, if needed */
! 	rvcontext.need_phvs = false;
! 	rvcontext.wrap_non_vars = false;
  	/* initialize cache array with indexes 0 .. length(tlist) */
  	rvcontext.rv_cache = palloc0((list_length(subquery->targetList) + 1) *
  								 sizeof(Node *));
  
  	/*
+ 	 * If we are under an outer join then non-nullable items and lateral
+ 	 * references may have to be turned into PlaceHolderVars.
+ 	 */
+ 	if (lowest_nulling_outer_join != NULL)
+ 		rvcontext.need_phvs = true;
+ 
+ 	/*
+ 	 * If we are dealing with an appendrel member then anything that's not a
+ 	 * simple Var has to be turned into a PlaceHolderVar.  We force this to
+ 	 * ensure that what we pull up doesn't get merged into a surrounding
+ 	 * expression during later processing and then fail to match the
+ 	 * expression actually available from the appendrel.
+ 	 */
+ 	if (containing_appendrel != NULL)
+ 	{
+ 		rvcontext.need_phvs = true;
+ 		rvcontext.wrap_non_vars = true;
+ 	}
+ 
+ 	/*
+ 	 * If the parent query uses grouping sets, we need a PlaceHolderVar for
+ 	 * anything that's not a simple Var.  Again, this ensures that expressions
+ 	 * retain their separate identity so that they will match grouping set
+ 	 * columns when appropriate.  (It'd be sufficient to wrap values used in
+ 	 * grouping set columns, and do so only in non-aggregated portions of the
+ 	 * tlist and havingQual, but that would require a lot of infrastructure
+ 	 * that pullup_replace_vars hasn't currently got.)
+ 	 */
+ 	if (parse->groupingSets)
+ 	{
+ 		rvcontext.need_phvs = true;
+ 		rvcontext.wrap_non_vars = true;
+ 	}
+ 
+ 	/*
  	 * Replace all of the top query's references to the subquery's outputs
  	 * with copies of the adjusted subtlist items, being careful not to
  	 * replace any of the jointree structure. (This'd be a lot cleaner if we
diff --git a/src/test/regress/expected/groupingsets.out b/src/test/regress/expected/groupingsets.out
index 833d515..cbfdbfd 100644
*** a/src/test/regress/expected/groupingsets.out
--- b/src/test/regress/expected/groupingsets.out
*************** select g as alias1, g as alias2
*** 389,394 ****
--- 389,439 ----
        3 |       
  (6 rows)
  
+ -- check that pulled-up subquery outputs still go to null when appropriate
+ select four, x
+   from (select four, ten, 'foo'::text as x from tenk1) as t
+   group by grouping sets (four, x)
+   having x = 'foo';
+  four |  x  
+ ------+-----
+       | foo
+ (1 row)
+ 
+ select four, x || 'x'
+   from (select four, ten, 'foo'::text as x from tenk1) as t
+   group by grouping sets (four, x)
+   order by four;
+  four | ?column? 
+ ------+----------
+     0 | 
+     1 | 
+     2 | 
+     3 | 
+       | foox
+ (5 rows)
+ 
+ select (x+y)*1, sum(z)
+  from (select 1 as x, 2 as y, 3 as z) s
+  group by grouping sets (x+y, x);
+  ?column? | sum 
+ ----------+-----
+         3 |   3
+           |   3
+ (2 rows)
+ 
+ select x, not x as not_x, q2 from
+   (select *, q1 = 1 as x from int8_tbl i1) as t
+   group by grouping sets(x, q2)
+   order by x, q2;
+  x | not_x |        q2         
+ ---+-------+-------------------
+  f | t     |                  
+    |       | -4567890123456789
+    |       |               123
+    |       |               456
+    |       |  4567890123456789
+ (5 rows)
+ 
  -- simple rescan tests
  select a, b, sum(v.x)
    from (values (1),(2)) v(x), gstest_data(v.x)
diff --git a/src/test/regress/sql/groupingsets.sql b/src/test/regress/sql/groupingsets.sql
index 2b4ab69..b28d821 100644
*** a/src/test/regress/sql/groupingsets.sql
--- b/src/test/regress/sql/groupingsets.sql
*************** select g as alias1, g as alias2
*** 152,157 ****
--- 152,177 ----
    from generate_series(1,3) g
   group by alias1, rollup(alias2);
  
+ -- check that pulled-up subquery outputs still go to null when appropriate
+ select four, x
+   from (select four, ten, 'foo'::text as x from tenk1) as t
+   group by grouping sets (four, x)
+   having x = 'foo';
+ 
+ select four, x || 'x'
+   from (select four, ten, 'foo'::text as x from tenk1) as t
+   group by grouping sets (four, x)
+   order by four;
+ 
+ select (x+y)*1, sum(z)
+  from (select 1 as x, 2 as y, 3 as z) s
+  group by grouping sets (x+y, x);
+ 
+ select x, not x as not_x, q2 from
+   (select *, q1 = 1 as x from int8_tbl i1) as t
+   group by grouping sets(x, q2)
+   order by x, q2;
+ 
  -- simple rescan tests
  
  select a, b, sum(v.x)
