From 7e00d4e2e08d999f7df8c893e731ef5b6e775fae Mon Sep 17 00:00:00 2001
From: Richard Guo <guofenglinux@gmail.com>
Date: Thu, 2 Feb 2023 19:56:51 +0800
Subject: [PATCH v1] Draft patch to fix postponed quals

---
 src/backend/optimizer/plan/initsplan.c | 65 ++++++++++++++++++--------
 1 file changed, 45 insertions(+), 20 deletions(-)

diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 35b2dc1034..835319f99a 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -74,6 +74,9 @@ typedef struct JoinTreeItem
 	/* Fields filled during deconstruct_distribute: */
 	SpecialJoinInfo *sjinfo;	/* if outer join, its SpecialJoinInfo */
 	List	   *oj_joinclauses; /* outer join quals not yet distributed */
+
+	List	   *children;
+	List	   *postponed_qual_list;
 } JoinTreeItem;
 
 /* Elements of the postponed_qual_list used during deconstruct_distribute */
@@ -89,8 +92,7 @@ static void extract_lateral_references(PlannerInfo *root, RelOptInfo *brel,
 static List *deconstruct_recurse(PlannerInfo *root, Node *jtnode,
 								 JoinDomain *parent_domain,
 								 List **item_list);
-static void deconstruct_distribute(PlannerInfo *root, JoinTreeItem *jtitem,
-								   List **postponed_qual_list);
+static void deconstruct_distribute(PlannerInfo *root, JoinTreeItem *jtitem);
 static void process_security_barrier_quals(PlannerInfo *root,
 										   int rti, Relids qualscope,
 										   JoinDomain *jdomain);
@@ -742,7 +744,6 @@ deconstruct_jointree(PlannerInfo *root)
 	List	   *result;
 	JoinDomain *top_jdomain;
 	List	   *item_list = NIL;
-	List	   *postponed_qual_list = NIL;
 	ListCell   *lc;
 
 	/*
@@ -780,13 +781,9 @@ deconstruct_jointree(PlannerInfo *root)
 	{
 		JoinTreeItem *jtitem = (JoinTreeItem *) lfirst(lc);
 
-		deconstruct_distribute(root, jtitem,
-							   &postponed_qual_list);
+		deconstruct_distribute(root, jtitem);
 	}
 
-	/* Shouldn't be any leftover postponed quals */
-	Assert(postponed_qual_list == NIL);
-
 	/*
 	 * However, if there were any special joins then we may have some
 	 * postponed LEFT JOIN clauses to deal with.
@@ -882,6 +879,7 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode,
 											   parent_domain,
 											   item_list);
 			sub_item = (JoinTreeItem *) llast(*item_list);
+			jtitem->children = lappend(jtitem->children, sub_item);
 			jtitem->qualscope = bms_add_members(jtitem->qualscope,
 												sub_item->qualscope);
 			jtitem->inner_join_rels = sub_item->inner_join_rels;
@@ -929,6 +927,8 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode,
 													item_list);
 				right_item = (JoinTreeItem *) llast(*item_list);
 				/* Compute qualscope etc */
+				jtitem->children = lappend(jtitem->children, left_item);
+				jtitem->children = lappend(jtitem->children, right_item);
 				jtitem->qualscope = bms_union(left_item->qualscope,
 											  right_item->qualscope);
 				jtitem->inner_join_rels = jtitem->qualscope;
@@ -954,6 +954,8 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode,
 													item_list);
 				right_item = (JoinTreeItem *) llast(*item_list);
 				/* Compute join domain contents, qualscope etc */
+				jtitem->children = lappend(jtitem->children, left_item);
+				jtitem->children = lappend(jtitem->children, right_item);
 				parent_domain->jd_relids =
 					bms_add_members(parent_domain->jd_relids,
 									child_domain->jd_relids);
@@ -991,6 +993,8 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode,
 													item_list);
 				right_item = (JoinTreeItem *) llast(*item_list);
 				/* Compute qualscope etc */
+				jtitem->children = lappend(jtitem->children, left_item);
+				jtitem->children = lappend(jtitem->children, right_item);
 				jtitem->qualscope = bms_union(left_item->qualscope,
 											  right_item->qualscope);
 				/* SEMI join never has rtindex, so don't add to anything */
@@ -1024,6 +1028,8 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode,
 													item_list);
 				right_item = (JoinTreeItem *) llast(*item_list);
 				/* Compute qualscope etc */
+				jtitem->children = lappend(jtitem->children, left_item);
+				jtitem->children = lappend(jtitem->children, right_item);
 				fj_domain->jd_relids = bms_add_members(fj_domain->jd_relids,
 													   child_domain->jd_relids);
 				parent_domain->jd_relids = bms_add_members(parent_domain->jd_relids,
@@ -1120,11 +1126,12 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode,
  * (because their lateral references are still unsatisfied).
  */
 static void
-deconstruct_distribute(PlannerInfo *root, JoinTreeItem *jtitem,
-					   List **postponed_qual_list)
+deconstruct_distribute(PlannerInfo *root, JoinTreeItem *jtitem)
 {
 	Node	   *jtnode = jtitem->jtnode;
 
+	Assert(jtitem->postponed_qual_list == NIL);
+
 	if (IsA(jtnode, RangeTblRef))
 	{
 		int			varno = ((RangeTblRef *) jtnode)->rtindex;
@@ -1139,14 +1146,23 @@ deconstruct_distribute(PlannerInfo *root, JoinTreeItem *jtitem,
 	else if (IsA(jtnode, FromExpr))
 	{
 		FromExpr   *f = (FromExpr *) jtnode;
-		List	   *new_postponed_quals = NIL;
+		List	   *child_postponed_qual_list = NIL;
 		ListCell   *l;
 
+		foreach(l, jtitem->children)
+		{
+			JoinTreeItem *sub_item = (JoinTreeItem *) lfirst(l);
+
+			child_postponed_qual_list =
+				list_concat(child_postponed_qual_list,
+							sub_item->postponed_qual_list);
+		}
+
 		/*
 		 * Try to process any quals postponed by children.  If they need
 		 * further postponement, add them to my output postponed_qual_list.
 		 */
-		foreach(l, *postponed_qual_list)
+		foreach(l, child_postponed_qual_list)
 		{
 			PostponedQual *pq = (PostponedQual *) lfirst(l);
 
@@ -1159,9 +1175,9 @@ deconstruct_distribute(PlannerInfo *root, JoinTreeItem *jtitem,
 										true, false, false,
 										NULL, NULL);
 			else
-				new_postponed_quals = lappend(new_postponed_quals, pq);
+				jtitem->postponed_qual_list =
+					lappend(jtitem->postponed_qual_list, pq);
 		}
-		*postponed_qual_list = new_postponed_quals;
 
 		/*
 		 * Now process the top-level quals.
@@ -1172,18 +1188,27 @@ deconstruct_distribute(PlannerInfo *root, JoinTreeItem *jtitem,
 								 root->qual_security_level,
 								 jtitem->qualscope, NULL, NULL,
 								 true, false, false,
-								 postponed_qual_list, NULL);
+								 &jtitem->postponed_qual_list, NULL);
 	}
 	else if (IsA(jtnode, JoinExpr))
 	{
 		JoinExpr   *j = (JoinExpr *) jtnode;
-		List	   *new_postponed_quals = NIL;
+		List	   *child_postponed_qual_list = NIL;
 		Relids		ojscope;
 		List	   *my_quals;
 		SpecialJoinInfo *sjinfo;
 		List	  **postponed_oj_qual_list;
 		ListCell   *l;
 
+		foreach(l, jtitem->children)
+		{
+			JoinTreeItem *sub_item = (JoinTreeItem *) lfirst(l);
+
+			child_postponed_qual_list =
+				list_concat(child_postponed_qual_list,
+							sub_item->postponed_qual_list);
+		}
+
 		/*
 		 * Try to process any quals postponed by children.  If they need
 		 * further postponement, add them to my output postponed_qual_list.
@@ -1191,7 +1216,7 @@ deconstruct_distribute(PlannerInfo *root, JoinTreeItem *jtitem,
 		 * that they'll be handled properly in make_outerjoininfo.
 		 */
 		my_quals = NIL;
-		foreach(l, *postponed_qual_list)
+		foreach(l, child_postponed_qual_list)
 		{
 			PostponedQual *pq = (PostponedQual *) lfirst(l);
 
@@ -1204,10 +1229,10 @@ deconstruct_distribute(PlannerInfo *root, JoinTreeItem *jtitem,
 				 * If this Assert fires, pull_up_subqueries() messed up.
 				 */
 				Assert(j->jointype == JOIN_INNER);
-				new_postponed_quals = lappend(new_postponed_quals, pq);
+				jtitem->postponed_qual_list =
+					lappend(jtitem->postponed_qual_list, pq);
 			}
 		}
-		*postponed_qual_list = new_postponed_quals;
 		my_quals = list_concat(my_quals, (List *) j->quals);
 
 		/*
@@ -1275,7 +1300,7 @@ deconstruct_distribute(PlannerInfo *root, JoinTreeItem *jtitem,
 								 ojscope, jtitem->nonnullable_rels,
 								 true,	/* allow_equivalence */
 								 false, false,	/* not clones */
-								 postponed_qual_list,
+								 &jtitem->postponed_qual_list,
 								 postponed_oj_qual_list);
 
 		/* And add the SpecialJoinInfo to join_info_list */
-- 
2.31.0

