From e493597e84fb795f9aa0db07c8f24e08183187ab Mon Sep 17 00:00:00 2001
From: Richard Guo <guofenglinux@gmail.com>
Date: Thu, 16 Feb 2023 18:02:41 +0800
Subject: [PATCH v1] Fix variable-free clause distribution

---
 src/backend/optimizer/plan/initsplan.c | 23 +++++++++++++++++++----
 1 file changed, 19 insertions(+), 4 deletions(-)

diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index fe4c8c63c9..3edc38048d 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -64,6 +64,9 @@ typedef struct JoinTreeItem
 	JoinDomain *jdomain;		/* join domain for its ON/WHERE clauses */
 	struct JoinTreeItem *jti_parent;	/* JoinTreeItem for this node's
 										 * parent, or NULL if it's the top */
+	bool		below_outer_join;		/* true if this node is within the
+										 * nullable side of a higher-level
+										 * outer join */
 	Relids		qualscope;		/* base+OJ Relids syntactically included in
 								 * this jointree node */
 	Relids		inner_join_rels;	/* base+OJ Relids syntactically included
@@ -84,6 +87,7 @@ typedef struct JoinTreeItem
 static void extract_lateral_references(PlannerInfo *root, RelOptInfo *brel,
 									   Index rtindex);
 static List *deconstruct_recurse(PlannerInfo *root, Node *jtnode,
+								 bool below_outer_join,
 								 JoinDomain *parent_domain,
 								 JoinTreeItem *parent_jtitem,
 								 List **item_list);
@@ -758,7 +762,7 @@ deconstruct_jointree(PlannerInfo *root)
 	root->outer_join_rels = NULL;
 
 	/* Perform the initial scan of the jointree */
-	result = deconstruct_recurse(root, (Node *) root->parse->jointree,
+	result = deconstruct_recurse(root, (Node *) root->parse->jointree, false,
 								 top_jdomain, NULL,
 								 &item_list);
 
@@ -813,7 +817,7 @@ deconstruct_jointree(PlannerInfo *root)
  * Return value is the appropriate joinlist for this jointree node.
  */
 static List *
-deconstruct_recurse(PlannerInfo *root, Node *jtnode,
+deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
 					JoinDomain *parent_domain,
 					JoinTreeItem *parent_jtitem,
 					List **item_list)
@@ -827,6 +831,7 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode,
 	jtitem = palloc0_object(JoinTreeItem);
 	jtitem->jtnode = jtnode;
 	jtitem->jti_parent = parent_jtitem;
+	jtitem->below_outer_join = below_outer_join;
 
 	if (IsA(jtnode, RangeTblRef))
 	{
@@ -871,6 +876,7 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode,
 			int			sub_members;
 
 			sub_joinlist = deconstruct_recurse(root, lfirst(l),
+											   below_outer_join,
 											   parent_domain,
 											   jtitem,
 											   item_list);
@@ -914,11 +920,13 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode,
 				jtitem->jdomain = parent_domain;
 				/* Recurse */
 				leftjoinlist = deconstruct_recurse(root, j->larg,
+												   below_outer_join,
 												   parent_domain,
 												   jtitem,
 												   item_list);
 				left_item = (JoinTreeItem *) llast(*item_list);
 				rightjoinlist = deconstruct_recurse(root, j->rarg,
+													below_outer_join,
 													parent_domain,
 													jtitem,
 													item_list);
@@ -941,11 +949,13 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode,
 				jtitem->jdomain = child_domain;
 				/* Recurse */
 				leftjoinlist = deconstruct_recurse(root, j->larg,
+												   below_outer_join,
 												   parent_domain,
 												   jtitem,
 												   item_list);
 				left_item = (JoinTreeItem *) llast(*item_list);
 				rightjoinlist = deconstruct_recurse(root, j->rarg,
+													true,
 													child_domain,
 													jtitem,
 													item_list);
@@ -980,11 +990,13 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode,
 				jtitem->jdomain = parent_domain;
 				/* Recurse */
 				leftjoinlist = deconstruct_recurse(root, j->larg,
+												   below_outer_join,
 												   parent_domain,
 												   jtitem,
 												   item_list);
 				left_item = (JoinTreeItem *) llast(*item_list);
 				rightjoinlist = deconstruct_recurse(root, j->rarg,
+													below_outer_join,
 													parent_domain,
 													jtitem,
 													item_list);
@@ -1011,6 +1023,7 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode,
 				child_domain->jd_relids = NULL; /* filled by recursion */
 				root->join_domains = lappend(root->join_domains, child_domain);
 				leftjoinlist = deconstruct_recurse(root, j->larg,
+												   true,
 												   child_domain,
 												   jtitem,
 												   item_list);
@@ -1020,6 +1033,7 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode,
 				child_domain->jd_relids = NULL; /* filled by recursion */
 				root->join_domains = lappend(root->join_domains, child_domain);
 				rightjoinlist = deconstruct_recurse(root, j->rarg,
+													true,
 													child_domain,
 													jtitem,
 													item_list);
@@ -2269,8 +2283,9 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
 		}
 		else
 		{
-			/* eval at join domain level */
-			relids = bms_copy(jtitem->jdomain->jd_relids);
+			/* eval at join domain level if not below outer join */
+			relids = jtitem->below_outer_join ?
+					 bms_copy(qualscope) : bms_copy(jtitem->jdomain->jd_relids);
 			/* mark as gating qual */
 			pseudoconstant = true;
 			/* tell createplan.c to check for gating quals */
-- 
2.31.0

