diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index dfa6201..666548b 100644
*** a/contrib/postgres_fdw/expected/postgres_fdw.out
--- b/contrib/postgres_fdw/expected/postgres_fdw.out
*************** SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2
*** 1701,1725 ****
                 Output: t1.c1, t2.c1, t1.c3, t1.*, t2.*
                 Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
                 Remote SQL: SELECT r1."C 1", r2."C 1", r1.c3, CASE WHEN (r1.*)::text IS NOT NULL THEN ROW(r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8) END, CASE WHEN (r2.*)::text IS NOT NULL THEN ROW(r2."C 1", r2.c2, r2.c3, r2.c4, r2.c5, r2.c6, r2.c7, r2.c8) END FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1")))) ORDER BY r1.c3 ASC NULLS LAST, r1."C 1" ASC NULLS LAST FOR UPDATE OF r1
!                ->  Sort
!                      Output: t1.c1, t1.c3, t1.*, t2.c1, t2.*
!                      Sort Key: t1.c3 USING <, t1.c1
!                      ->  Merge Join
                             Output: t1.c1, t1.c3, t1.*, t2.c1, t2.*
!                            Merge Cond: (t1.c1 = t2.c1)
!                            ->  Sort
!                                  Output: t1.c1, t1.c3, t1.*
!                                  Sort Key: t1.c1
!                                  ->  Foreign Scan on public.ft1 t1
                                         Output: t1.c1, t1.c3, t1.*
!                                        Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" FOR UPDATE
!                            ->  Sort
!                                  Output: t2.c1, t2.*
!                                  Sort Key: t2.c1
!                                  ->  Foreign Scan on public.ft2 t2
                                         Output: t2.c1, t2.*
!                                        Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1"
! (26 rows)
  
  SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c3, t1.c1 OFFSET 100 LIMIT 10 FOR UPDATE OF t1;
   c1  | c1  
--- 1701,1727 ----
                 Output: t1.c1, t2.c1, t1.c3, t1.*, t2.*
                 Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
                 Remote SQL: SELECT r1."C 1", r2."C 1", r1.c3, CASE WHEN (r1.*)::text IS NOT NULL THEN ROW(r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8) END, CASE WHEN (r2.*)::text IS NOT NULL THEN ROW(r2."C 1", r2.c2, r2.c3, r2.c4, r2.c5, r2.c6, r2.c7, r2.c8) END FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1")))) ORDER BY r1.c3 ASC NULLS LAST, r1."C 1" ASC NULLS LAST FOR UPDATE OF r1
!                ->  Result
!                      Output: t1.c1, t2.c1, t1.c3, t1.*, t2.*
!                      ->  Sort
                             Output: t1.c1, t1.c3, t1.*, t2.c1, t2.*
!                            Sort Key: t1.c3, t1.c1
!                            ->  Merge Join
!                                  Output: t1.c1, t1.c3, t1.*, t2.c1, t2.*
!                                  Merge Cond: (t1.c1 = t2.c1)
!                                  ->  Sort
                                         Output: t1.c1, t1.c3, t1.*
!                                        Sort Key: t1.c1
!                                        ->  Foreign Scan on public.ft1 t1
!                                              Output: t1.c1, t1.c3, t1.*
!                                              Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" FOR UPDATE
!                                  ->  Sort
                                         Output: t2.c1, t2.*
!                                        Sort Key: t2.c1
!                                        ->  Foreign Scan on public.ft2 t2
!                                              Output: t2.c1, t2.*
!                                              Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1"
! (28 rows)
  
  SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c3, t1.c1 OFFSET 100 LIMIT 10 FOR UPDATE OF t1;
   c1  | c1  
*************** SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2
*** 1748,1772 ****
                 Output: t1.c1, t2.c1, t1.c3, t1.*, t2.*
                 Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
                 Remote SQL: SELECT r1."C 1", r2."C 1", r1.c3, CASE WHEN (r1.*)::text IS NOT NULL THEN ROW(r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8) END, CASE WHEN (r2.*)::text IS NOT NULL THEN ROW(r2."C 1", r2.c2, r2.c3, r2.c4, r2.c5, r2.c6, r2.c7, r2.c8) END FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1")))) ORDER BY r1.c3 ASC NULLS LAST, r1."C 1" ASC NULLS LAST FOR UPDATE OF r1 FOR UPDATE OF r2
!                ->  Sort
!                      Output: t1.c1, t1.c3, t1.*, t2.c1, t2.*
!                      Sort Key: t1.c3 USING <, t1.c1
!                      ->  Merge Join
                             Output: t1.c1, t1.c3, t1.*, t2.c1, t2.*
!                            Merge Cond: (t1.c1 = t2.c1)
!                            ->  Sort
!                                  Output: t1.c1, t1.c3, t1.*
!                                  Sort Key: t1.c1
!                                  ->  Foreign Scan on public.ft1 t1
                                         Output: t1.c1, t1.c3, t1.*
!                                        Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" FOR UPDATE
!                            ->  Sort
!                                  Output: t2.c1, t2.*
!                                  Sort Key: t2.c1
!                                  ->  Foreign Scan on public.ft2 t2
                                         Output: t2.c1, t2.*
!                                        Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" FOR UPDATE
! (26 rows)
  
  SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c3, t1.c1 OFFSET 100 LIMIT 10 FOR UPDATE;
   c1  | c1  
--- 1750,1776 ----
                 Output: t1.c1, t2.c1, t1.c3, t1.*, t2.*
                 Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
                 Remote SQL: SELECT r1."C 1", r2."C 1", r1.c3, CASE WHEN (r1.*)::text IS NOT NULL THEN ROW(r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8) END, CASE WHEN (r2.*)::text IS NOT NULL THEN ROW(r2."C 1", r2.c2, r2.c3, r2.c4, r2.c5, r2.c6, r2.c7, r2.c8) END FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1")))) ORDER BY r1.c3 ASC NULLS LAST, r1."C 1" ASC NULLS LAST FOR UPDATE OF r1 FOR UPDATE OF r2
!                ->  Result
!                      Output: t1.c1, t2.c1, t1.c3, t1.*, t2.*
!                      ->  Sort
                             Output: t1.c1, t1.c3, t1.*, t2.c1, t2.*
!                            Sort Key: t1.c3, t1.c1
!                            ->  Merge Join
!                                  Output: t1.c1, t1.c3, t1.*, t2.c1, t2.*
!                                  Merge Cond: (t1.c1 = t2.c1)
!                                  ->  Sort
                                         Output: t1.c1, t1.c3, t1.*
!                                        Sort Key: t1.c1
!                                        ->  Foreign Scan on public.ft1 t1
!                                              Output: t1.c1, t1.c3, t1.*
!                                              Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" FOR UPDATE
!                                  ->  Sort
                                         Output: t2.c1, t2.*
!                                        Sort Key: t2.c1
!                                        ->  Foreign Scan on public.ft2 t2
!                                              Output: t2.c1, t2.*
!                                              Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" FOR UPDATE
! (28 rows)
  
  SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c3, t1.c1 OFFSET 100 LIMIT 10 FOR UPDATE;
   c1  | c1  
*************** SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2
*** 1796,1820 ****
                 Output: t1.c1, t2.c1, t1.c3, t1.*, t2.*
                 Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
                 Remote SQL: SELECT r1."C 1", r2."C 1", r1.c3, CASE WHEN (r1.*)::text IS NOT NULL THEN ROW(r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8) END, CASE WHEN (r2.*)::text IS NOT NULL THEN ROW(r2."C 1", r2.c2, r2.c3, r2.c4, r2.c5, r2.c6, r2.c7, r2.c8) END FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1")))) ORDER BY r1.c3 ASC NULLS LAST, r1."C 1" ASC NULLS LAST FOR SHARE OF r1
!                ->  Sort
!                      Output: t1.c1, t1.c3, t1.*, t2.c1, t2.*
!                      Sort Key: t1.c3 USING <, t1.c1
!                      ->  Merge Join
                             Output: t1.c1, t1.c3, t1.*, t2.c1, t2.*
!                            Merge Cond: (t1.c1 = t2.c1)
!                            ->  Sort
!                                  Output: t1.c1, t1.c3, t1.*
!                                  Sort Key: t1.c1
!                                  ->  Foreign Scan on public.ft1 t1
                                         Output: t1.c1, t1.c3, t1.*
!                                        Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" FOR SHARE
!                            ->  Sort
!                                  Output: t2.c1, t2.*
!                                  Sort Key: t2.c1
!                                  ->  Foreign Scan on public.ft2 t2
                                         Output: t2.c1, t2.*
!                                        Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1"
! (26 rows)
  
  SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c3, t1.c1 OFFSET 100 LIMIT 10 FOR SHARE OF t1;
   c1  | c1  
--- 1800,1826 ----
                 Output: t1.c1, t2.c1, t1.c3, t1.*, t2.*
                 Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
                 Remote SQL: SELECT r1."C 1", r2."C 1", r1.c3, CASE WHEN (r1.*)::text IS NOT NULL THEN ROW(r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8) END, CASE WHEN (r2.*)::text IS NOT NULL THEN ROW(r2."C 1", r2.c2, r2.c3, r2.c4, r2.c5, r2.c6, r2.c7, r2.c8) END FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1")))) ORDER BY r1.c3 ASC NULLS LAST, r1."C 1" ASC NULLS LAST FOR SHARE OF r1
!                ->  Result
!                      Output: t1.c1, t2.c1, t1.c3, t1.*, t2.*
!                      ->  Sort
                             Output: t1.c1, t1.c3, t1.*, t2.c1, t2.*
!                            Sort Key: t1.c3, t1.c1
!                            ->  Merge Join
!                                  Output: t1.c1, t1.c3, t1.*, t2.c1, t2.*
!                                  Merge Cond: (t1.c1 = t2.c1)
!                                  ->  Sort
                                         Output: t1.c1, t1.c3, t1.*
!                                        Sort Key: t1.c1
!                                        ->  Foreign Scan on public.ft1 t1
!                                              Output: t1.c1, t1.c3, t1.*
!                                              Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" FOR SHARE
!                                  ->  Sort
                                         Output: t2.c1, t2.*
!                                        Sort Key: t2.c1
!                                        ->  Foreign Scan on public.ft2 t2
!                                              Output: t2.c1, t2.*
!                                              Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1"
! (28 rows)
  
  SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c3, t1.c1 OFFSET 100 LIMIT 10 FOR SHARE OF t1;
   c1  | c1  
*************** SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2
*** 1843,1867 ****
                 Output: t1.c1, t2.c1, t1.c3, t1.*, t2.*
                 Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
                 Remote SQL: SELECT r1."C 1", r2."C 1", r1.c3, CASE WHEN (r1.*)::text IS NOT NULL THEN ROW(r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8) END, CASE WHEN (r2.*)::text IS NOT NULL THEN ROW(r2."C 1", r2.c2, r2.c3, r2.c4, r2.c5, r2.c6, r2.c7, r2.c8) END FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1")))) ORDER BY r1.c3 ASC NULLS LAST, r1."C 1" ASC NULLS LAST FOR SHARE OF r1 FOR SHARE OF r2
!                ->  Sort
!                      Output: t1.c1, t1.c3, t1.*, t2.c1, t2.*
!                      Sort Key: t1.c3 USING <, t1.c1
!                      ->  Merge Join
                             Output: t1.c1, t1.c3, t1.*, t2.c1, t2.*
!                            Merge Cond: (t1.c1 = t2.c1)
!                            ->  Sort
!                                  Output: t1.c1, t1.c3, t1.*
!                                  Sort Key: t1.c1
!                                  ->  Foreign Scan on public.ft1 t1
                                         Output: t1.c1, t1.c3, t1.*
!                                        Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" FOR SHARE
!                            ->  Sort
!                                  Output: t2.c1, t2.*
!                                  Sort Key: t2.c1
!                                  ->  Foreign Scan on public.ft2 t2
                                         Output: t2.c1, t2.*
!                                        Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" FOR SHARE
! (26 rows)
  
  SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c3, t1.c1 OFFSET 100 LIMIT 10 FOR SHARE;
   c1  | c1  
--- 1849,1875 ----
                 Output: t1.c1, t2.c1, t1.c3, t1.*, t2.*
                 Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
                 Remote SQL: SELECT r1."C 1", r2."C 1", r1.c3, CASE WHEN (r1.*)::text IS NOT NULL THEN ROW(r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8) END, CASE WHEN (r2.*)::text IS NOT NULL THEN ROW(r2."C 1", r2.c2, r2.c3, r2.c4, r2.c5, r2.c6, r2.c7, r2.c8) END FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1")))) ORDER BY r1.c3 ASC NULLS LAST, r1."C 1" ASC NULLS LAST FOR SHARE OF r1 FOR SHARE OF r2
!                ->  Result
!                      Output: t1.c1, t2.c1, t1.c3, t1.*, t2.*
!                      ->  Sort
                             Output: t1.c1, t1.c3, t1.*, t2.c1, t2.*
!                            Sort Key: t1.c3, t1.c1
!                            ->  Merge Join
!                                  Output: t1.c1, t1.c3, t1.*, t2.c1, t2.*
!                                  Merge Cond: (t1.c1 = t2.c1)
!                                  ->  Sort
                                         Output: t1.c1, t1.c3, t1.*
!                                        Sort Key: t1.c1
!                                        ->  Foreign Scan on public.ft1 t1
!                                              Output: t1.c1, t1.c3, t1.*
!                                              Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" FOR SHARE
!                                  ->  Sort
                                         Output: t2.c1, t2.*
!                                        Sort Key: t2.c1
!                                        ->  Foreign Scan on public.ft2 t2
!                                              Output: t2.c1, t2.*
!                                              Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" FOR SHARE
! (28 rows)
  
  SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c3, t1.c1 OFFSET 100 LIMIT 10 FOR SHARE;
   c1  | c1  
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index 674eb98..2ac9d7b 100644
*** a/contrib/postgres_fdw/postgres_fdw.c
--- b/contrib/postgres_fdw/postgres_fdw.c
*************** postgresGetForeignPlan(PlannerInfo *root
*** 1229,1239 ****
  
  		/*
  		 * Ensure that the outer plan produces a tuple whose descriptor
! 		 * matches our scan tuple slot. This is safe because all scans and
! 		 * joins support projection, so we never need to insert a Result node.
! 		 * Also, remove the local conditions from outer plan's quals, lest
! 		 * they will be evaluated twice, once by the local plan and once by
! 		 * the scan.
  		 */
  		if (outer_plan)
  		{
--- 1229,1237 ----
  
  		/*
  		 * Ensure that the outer plan produces a tuple whose descriptor
! 		 * matches our scan tuple slot.  Also, remove the local conditions
! 		 * from outer plan's quals, lest they be evaluated twice, once by the
! 		 * local plan and once by the scan.
  		 */
  		if (outer_plan)
  		{
*************** postgresGetForeignPlan(PlannerInfo *root
*** 1246,1268 ****
  			 */
  			Assert(!IS_UPPER_REL(foreignrel));
  
! 			outer_plan->targetlist = fdw_scan_tlist;
! 
  			foreach(lc, local_exprs)
  			{
- 				Join	   *join_plan = (Join *) outer_plan;
  				Node	   *qual = lfirst(lc);
  
  				outer_plan->qual = list_delete(outer_plan->qual, qual);
  
  				/*
  				 * For an inner join the local conditions of foreign scan plan
! 				 * can be part of the joinquals as well.
  				 */
! 				if (join_plan->jointype == JOIN_INNER)
! 					join_plan->joinqual = list_delete(join_plan->joinqual,
! 													  qual);
  			}
  		}
  	}
  
--- 1244,1285 ----
  			 */
  			Assert(!IS_UPPER_REL(foreignrel));
  
! 			/*
! 			 * First, update the plan's qual list if possible.  In some cases
! 			 * the quals might be enforced below the topmost plan level, in
! 			 * which case we'll fail to remove them; it's not worth working
! 			 * harder than this.
! 			 */
  			foreach(lc, local_exprs)
  			{
  				Node	   *qual = lfirst(lc);
  
  				outer_plan->qual = list_delete(outer_plan->qual, qual);
  
  				/*
  				 * For an inner join the local conditions of foreign scan plan
! 				 * can be part of the joinquals as well.  (They might also be
! 				 * in the mergequals or hashquals, but we can't touch those
! 				 * without breaking the plan.)
  				 */
! 				if (IsA(outer_plan, NestLoop) ||
! 					IsA(outer_plan, MergeJoin) ||
! 					IsA(outer_plan, HashJoin))
! 				{
! 					Join	   *join_plan = (Join *) outer_plan;
! 
! 					if (join_plan->jointype == JOIN_INNER)
! 						join_plan->joinqual = list_delete(join_plan->joinqual,
! 														  qual);
! 				}
  			}
+ 
+ 			/*
+ 			 * Now fix the subplan's tlist --- this might result in inserting
+ 			 * a Result node atop the plan tree.
+ 			 */
+ 			outer_plan = change_plan_targetlist(outer_plan, fdw_scan_tlist,
+ 												best_path->path.parallel_safe);
  		}
  	}
  
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index da7a920..91cf782 100644
*** a/src/backend/optimizer/plan/createplan.c
--- b/src/backend/optimizer/plan/createplan.c
*************** create_unique_plan(PlannerInfo *root, Un
*** 1407,1426 ****
  		}
  	}
  
  	if (newitems || best_path->umethod == UNIQUE_PATH_SORT)
! 	{
! 		/*
! 		 * If the top plan node can't do projections and its existing target
! 		 * list isn't already what we need, we need to add a Result node to
! 		 * help it along.
! 		 */
! 		if (!is_projection_capable_plan(subplan) &&
! 			!tlist_same_exprs(newtlist, subplan->targetlist))
! 			subplan = inject_projection_plan(subplan, newtlist,
! 											 best_path->path.parallel_safe);
! 		else
! 			subplan->targetlist = newtlist;
! 	}
  
  	/*
  	 * Build control information showing which subplan output columns are to
--- 1407,1416 ----
  		}
  	}
  
+ 	/* Use change_plan_targetlist in case we need to insert a Result node */
  	if (newitems || best_path->umethod == UNIQUE_PATH_SORT)
! 		subplan = change_plan_targetlist(subplan, newtlist,
! 										 best_path->path.parallel_safe);
  
  	/*
  	 * Build control information showing which subplan output columns are to
*************** inject_projection_plan(Plan *subplan, Li
*** 1763,1768 ****
--- 1753,1792 ----
  }
  
  /*
+  * change_plan_targetlist
+  *	  Externally available wrapper for inject_projection_plan.
+  *
+  * This is meant for use by FDW plan-generation functions, which might
+  * want to adjust the tlist computed by some subplan tree.  In general,
+  * a Result node is needed to compute the new tlist, but we can optimize
+  * some cases.
+  *
+  * In most cases, tlist_parallel_safe can just be passed as the parallel_safe
+  * flag of the FDW's own Path node.
+  */
+ Plan *
+ change_plan_targetlist(Plan *subplan, List *tlist, bool tlist_parallel_safe)
+ {
+ 	/*
+ 	 * If the top plan node can't do projections and its existing target list
+ 	 * isn't already what we need, we need to add a Result node to help it
+ 	 * along.
+ 	 */
+ 	if (!is_projection_capable_plan(subplan) &&
+ 		!tlist_same_exprs(tlist, subplan->targetlist))
+ 		subplan = inject_projection_plan(subplan, tlist,
+ 										 subplan->parallel_safe &&
+ 										 tlist_parallel_safe);
+ 	else
+ 	{
+ 		/* Else we can just replace the plan node's tlist */
+ 		subplan->targetlist = tlist;
+ 		subplan->parallel_safe &= tlist_parallel_safe;
+ 	}
+ 	return subplan;
+ }
+ 
+ /*
   * create_sort_plan
   *
   *	  Create a Sort plan for 'best_path' and (recursively) plans
diff --git a/src/include/optimizer/planmain.h b/src/include/optimizer/planmain.h
index c8ab028..a081ca6 100644
*** a/src/include/optimizer/planmain.h
--- b/src/include/optimizer/planmain.h
*************** extern ForeignScan *make_foreignscan(Lis
*** 53,58 ****
--- 53,60 ----
  				 Index scanrelid, List *fdw_exprs, List *fdw_private,
  				 List *fdw_scan_tlist, List *fdw_recheck_quals,
  				 Plan *outer_plan);
+ extern Plan *change_plan_targetlist(Plan *subplan, List *tlist,
+ 					   bool tlist_parallel_safe);
  extern Plan *materialize_finished_plan(Plan *subplan);
  extern bool is_projection_capable_path(Path *path);
  extern bool is_projection_capable_plan(Plan *plan);
