diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index bfda05394d6492c623fa57c521278227bc889705..91acebc37295e7addb2c6f98c6bf977bfefa1d8f 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -661,6 +661,7 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
 	int			parentRTindex = rti;
 	List	   *live_childrels = NIL;
 	List	   *subpaths = NIL;
+	bool		subpaths_valid = true;
 	List	   *all_child_pathkeys = NIL;
 	List	   *all_child_outers = NIL;
 	ListCell   *l;
@@ -699,19 +700,21 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
 		if (IS_DUMMY_REL(childrel))
 			continue;
 
-		/* XXX need to figure out what to do for LATERAL */
-		if (childrel->cheapest_total_path == NULL)
-			elog(ERROR, "LATERAL within an append relation is not supported yet");
+		/*
+		 * Child is live, so add it to the live_childrels list for use below.
+		 */
+		live_childrels = lappend(live_childrels, childrel);
 
 		/*
-		 * Child is live, so add its cheapest access path to the Append path
-		 * we are constructing for the parent.
+		 * If child has an unparameterized cheapest-total path, add that to
+		 * the unparameterized Append path we are constructing for the parent.
+		 * If not, there's no workable unparameterized path.
 		 */
-		subpaths = accumulate_append_subpath(subpaths,
+		if (childrel->cheapest_total_path)
+			subpaths = accumulate_append_subpath(subpaths,
 											 childrel->cheapest_total_path);
-
-		/* Remember which childrels are live, for logic below */
-		live_childrels = lappend(live_childrels, childrel);
+		else
+			subpaths_valid = false;
 
 		/*
 		 * Collect lists of all the available path orderings and
@@ -779,17 +782,20 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
 	}
 
 	/*
-	 * Next, build an unordered, unparameterized Append path for the rel.
-	 * (Note: this is correct even if we have zero or one live subpath due to
-	 * constraint exclusion.)
+	 * If we found unparameterized paths for all children, build an unordered,
+	 * unparameterized Append path for the rel.  (Note: this is correct even
+	 * if we have zero or one live subpath due to constraint exclusion.)
 	 */
-	add_path(rel, (Path *) create_append_path(rel, subpaths, NULL));
+	if (subpaths_valid)
+		add_path(rel, (Path *) create_append_path(rel, subpaths, NULL));
 
 	/*
-	 * Build unparameterized MergeAppend paths based on the collected list of
-	 * child pathkeys.
+	 * Also build unparameterized MergeAppend paths based on the collected
+	 * list of child pathkeys.
 	 */
-	generate_mergeappend_paths(root, rel, live_childrels, all_child_pathkeys);
+	if (subpaths_valid)
+		generate_mergeappend_paths(root, rel, live_childrels,
+								   all_child_pathkeys);
 
 	/*
 	 * Build Append paths for each parameterization seen among the child rels.
@@ -807,11 +813,11 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
 	foreach(l, all_child_outers)
 	{
 		Relids		required_outer = (Relids) lfirst(l);
-		bool		ok = true;
 		ListCell   *lcr;
 
 		/* Select the child paths for an Append with this parameterization */
 		subpaths = NIL;
+		subpaths_valid = true;
 		foreach(lcr, live_childrels)
 		{
 			RelOptInfo *childrel = (RelOptInfo *) lfirst(lcr);
@@ -831,7 +837,7 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
 													 required_outer, 1.0);
 				if (cheapest_total == NULL)
 				{
-					ok = false;
+					subpaths_valid = false;
 					break;
 				}
 			}
@@ -839,7 +845,7 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
 			subpaths = accumulate_append_subpath(subpaths, cheapest_total);
 		}
 
-		if (ok)
+		if (subpaths_valid)
 			add_path(rel, (Path *)
 					 create_append_path(rel, subpaths, required_outer));
 	}
@@ -911,13 +917,11 @@ generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel,
 			 */
 			if (cheapest_startup == NULL || cheapest_total == NULL)
 			{
-				/* XXX need to figure out what to do for LATERAL */
-				if (childrel->cheapest_total_path == NULL)
-					elog(ERROR, "LATERAL within an append relation is not supported yet");
-
 				cheapest_startup = cheapest_total =
 					childrel->cheapest_total_path;
+				/* Assert we do have an unparameterized path for this child */
 				Assert(cheapest_total != NULL);
+				Assert(cheapest_total->param_info == NULL);
 			}
 
 			/*
diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c
index 06dbe84540444fa4d72b771b0d08137f3c1b4587..07b35f98bd1da5d0ae1b774a5fad1e358587f489 100644
--- a/src/backend/optimizer/prep/prepjointree.c
+++ b/src/backend/optimizer/prep/prepjointree.c
@@ -995,20 +995,45 @@ pull_up_simple_union_all(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte)
 {
 	int			varno = ((RangeTblRef *) jtnode)->rtindex;
 	Query	   *subquery = rte->subquery;
-	int			rtoffset;
+	int			rtoffset = list_length(root->parse->rtable);
 	List	   *rtable;
 
 	/*
-	 * Append child RTEs to parent rtable.
-	 *
+	 * Make a modifiable copy of the subquery's rtable, so we can adjust
+	 * upper-level Vars in it.  There are no such Vars in the setOperations
+	 * tree proper, so fixing the rtable should be sufficient.
+	 */
+	rtable = copyObject(subquery->rtable);
+
+	/*
 	 * Upper-level vars in subquery are now one level closer to their parent
 	 * than before.  We don't have to worry about offsetting varnos, though,
-	 * because any such vars must refer to stuff above the level of the query
-	 * we are pulling into.
+	 * because the UNION leaf queries can't cross-reference each other.
 	 */
-	rtoffset = list_length(root->parse->rtable);
-	rtable = copyObject(subquery->rtable);
 	IncrementVarSublevelsUp_rtable(rtable, -1, 1);
+
+	/*
+	 * If the UNION ALL subquery had a LATERAL marker, propagate that to all
+	 * its children.  The individual children might or might not contain any
+	 * actual lateral cross-references, but we have to mark the pulled-up
+	 * child RTEs so that later planner stages will check for such.
+	 */
+	if (rte->lateral)
+	{
+		ListCell   *rt;
+
+		foreach(rt, rtable)
+		{
+			RangeTblEntry *child_rte = (RangeTblEntry *) lfirst(rt);
+
+			Assert(child_rte->rtekind == RTE_SUBQUERY);
+			child_rte->lateral = true;
+		}
+	}
+
+	/*
+	 * Append child RTEs to parent rtable.
+	 */
 	root->parse->rtable = list_concat(root->parse->rtable, rtable);
 
 	/*
diff --git a/src/test/regress/expected/join.out b/src/test/regress/expected/join.out
index 5e17432198ec81a53d50943636afbb57edb88b72..6503dd1d2f8e7ac6b6c6c97655fdcae2aa609245 100644
--- a/src/test/regress/expected/join.out
+++ b/src/test/regress/expected/join.out
@@ -3109,6 +3109,32 @@ explain (costs off)
          ->  Function Scan on generate_series g
 (4 rows)
 
+-- lateral with UNION ALL subselect
+explain (costs off)
+  select * from generate_series(100,200) g,
+    lateral (select * from int8_tbl a where g = q1 union all
+             select * from int8_tbl b where g = q2) ss;
+                QUERY PLAN                
+------------------------------------------
+ Nested Loop
+   ->  Function Scan on generate_series g
+   ->  Append
+         ->  Seq Scan on int8_tbl a
+               Filter: (g.g = q1)
+         ->  Seq Scan on int8_tbl b
+               Filter: (g.g = q2)
+(7 rows)
+
+select * from generate_series(100,200) g,
+  lateral (select * from int8_tbl a where g = q1 union all
+           select * from int8_tbl b where g = q2) ss;
+  g  |        q1        |        q2        
+-----+------------------+------------------
+ 123 |              123 |              456
+ 123 |              123 | 4567890123456789
+ 123 | 4567890123456789 |              123
+(3 rows)
+
 -- test some error cases where LATERAL should have been used but wasn't
 select f1,g from int4_tbl a, generate_series(0, f1) g;
 ERROR:  column "f1" does not exist
diff --git a/src/test/regress/sql/join.sql b/src/test/regress/sql/join.sql
index 5de98dc0a722c1f855689105b3beacd6e5a810ee..40db5602dd477de7b496ddbabbf4766de08c19fb 100644
--- a/src/test/regress/sql/join.sql
+++ b/src/test/regress/sql/join.sql
@@ -876,6 +876,15 @@ explain (costs off)
 explain (costs off)
   select count(*) from tenk1 a cross join lateral generate_series(1,two) g;
 
+-- lateral with UNION ALL subselect
+explain (costs off)
+  select * from generate_series(100,200) g,
+    lateral (select * from int8_tbl a where g = q1 union all
+             select * from int8_tbl b where g = q2) ss;
+select * from generate_series(100,200) g,
+  lateral (select * from int8_tbl a where g = q1 union all
+           select * from int8_tbl b where g = q2) ss;
+
 -- test some error cases where LATERAL should have been used but wasn't
 select f1,g from int4_tbl a, generate_series(0, f1) g;
 select f1,g from int4_tbl a, generate_series(0, a.f1) g;