From: Andrey Rachitskiy <pl0h0yp1@gmail.com>
Subject: [PATCH] Fix SIGSEGV in self-join elimination with LATERAL UNION ALL

SJE rewrites Vars in the Query tree but not in
AppendRelInfo.translated_vars.  A LATERAL UNION ALL can store Vars of
the removed relation there.  After the RTE slot is cleared,
apply_child_basequals() const-simplifies IS NOT NULL on that Var and
crashes in var_is_nonnullable().

Update translated_vars when substituting the removed relid.

diff --git a/src/backend/optimizer/plan/analyzejoins.c b/src/backend/optimizer/plan/analyzejoins.c
index 87a5d9d58b8..4afd969d1dd 100644
--- a/src/backend/optimizer/plan/analyzejoins.c
+++ b/src/backend/optimizer/plan/analyzejoins.c
@@ -2171,6 +2171,10 @@ remove_self_join_rel(PlannerInfo *root, PlanRowMark *kmark, PlanRowMark *rmark,
 	ChangeVarNodesExtended((Node *) root->parse, toRemove->relid, toKeep->relid,
 						   0, replace_relid_callback);
 
+	/* Replace varno in translated_vars, else they keep the removed relid */
+	ChangeVarNodesExtended((Node *) root->append_rel_list, toRemove->relid,
+						   toKeep->relid, 0, replace_relid_callback);
+
 	/* Replace links in the planner info */
 	remove_rel_from_query(root, toRemove->relid, toKeep->relid, NULL, NULL);
 
diff --git a/src/test/regress/expected/join.out b/src/test/regress/expected/join.out
index 05f359d3aa7..332133fcbca 100644
--- a/src/test/regress/expected/join.out
+++ b/src/test/regress/expected/join.out
@@ -8287,6 +8287,24 @@ SELECT a1.a FROM sj a1,sj a2 WHERE (a1.a=a2.a) FOR UPDATE;
          Filter: (a IS NOT NULL)
 (3 rows)
 
+-- Check that SJE rewrites Vars in a flattened LATERAL UNION ALL
+explain (costs off)
+select count(*) from sj p
+inner join lateral (select p.b union all select p.b) s(x) on (s.x is not null)
+where p.a in (select a from sj);
+                       QUERY PLAN                        
+---------------------------------------------------------
+ Aggregate
+   ->  Nested Loop
+         ->  Seq Scan on sj
+               Filter: (a IS NOT NULL)
+         ->  Append
+               ->  Result
+                     One-Time Filter: (sj.b IS NOT NULL)
+               ->  Result
+                     One-Time Filter: (sj.b IS NOT NULL)
+(9 rows)
+
 reset enable_hashjoin;
 reset enable_mergejoin;
 --
diff --git a/src/test/regress/sql/join.sql b/src/test/regress/sql/join.sql
index 450bd5bbf2c..3df7ce58725 100644
--- a/src/test/regress/sql/join.sql
+++ b/src/test/regress/sql/join.sql
@@ -3260,6 +3260,12 @@ ON sj_t1.id = _t2t3t4.id;
 EXPLAIN (COSTS OFF)
 SELECT a1.a FROM sj a1,sj a2 WHERE (a1.a=a2.a) FOR UPDATE;
 
+-- Check that SJE rewrites Vars in a flattened LATERAL UNION ALL
+explain (costs off)
+select count(*) from sj p
+inner join lateral (select p.b union all select p.b) s(x) on (s.x is not null)
+where p.a in (select a from sj);
+
 reset enable_hashjoin;
 reset enable_mergejoin;
 
