From ea57eb88096287fe55251903081adced4d1f3bc4 Mon Sep 17 00:00:00 2001
From: James Hunter <james.hunter.pg@gmail.com>
Date: Thu, 20 Feb 2025 17:33:48 +0000
Subject: [PATCH 2/4] Store non-init-plan SubPlan objects in Plan list

We currently track SubPlan objects, on Plans, via either the plan->initPlan
list, for init plans; or via whatever expression contains the SubPlan, for
regular sub plans.

A SubPlan object can itself use working memory, if it uses a hash table.
This hash table is associated with the SubPlan itself, and not with the
Plan to which the SubPlan points.

To allow us to assign working memory to an individual SubPlan, this commit
stores a link to the regular SubPlan, inside a new plan->subPlan list,
when we finalize the (parent) Plan whose expression contains the regular
SubPlan.

Unlike the existing plan->initPlan list, we will not use the new plan->
subPlan list to initialize SubPlan nodes -- that must be done when we
initialize the expression that contains the SubPlan. Instead, we will use
it, during InitPlan() but before ExecInitNode(), to assign a working-
memory limit to the SubPlan.
---
 src/backend/optimizer/plan/setrefs.c | 284 +++++++++++++++++----------
 src/include/nodes/plannodes.h        |   2 +
 2 files changed, 177 insertions(+), 109 deletions(-)

diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index 999a5a8ab5a..8a4e77baa90 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -58,6 +58,7 @@ typedef struct
 typedef struct
 {
 	PlannerInfo *root;
+	Plan	   *plan;
 	int			rtoffset;
 	double		num_exec;
 } fix_scan_expr_context;
@@ -65,6 +66,7 @@ typedef struct
 typedef struct
 {
 	PlannerInfo *root;
+	Plan	   *plan;
 	indexed_tlist *outer_itlist;
 	indexed_tlist *inner_itlist;
 	Index		acceptable_rel;
@@ -76,6 +78,7 @@ typedef struct
 typedef struct
 {
 	PlannerInfo *root;
+	Plan	   *plan;
 	indexed_tlist *subplan_itlist;
 	int			newvarno;
 	int			rtoffset;
@@ -127,8 +130,8 @@ typedef struct
 	(((con)->consttype == REGCLASSOID || (con)->consttype == OIDOID) && \
 	 !(con)->constisnull)
 
-#define fix_scan_list(root, lst, rtoffset, num_exec) \
-	((List *) fix_scan_expr(root, (Node *) (lst), rtoffset, num_exec))
+#define fix_scan_list(root, plan, lst, rtoffset, num_exec) \
+	((List *) fix_scan_expr(root, plan, (Node *) (lst), rtoffset, num_exec))
 
 static void add_rtes_to_flat_rtable(PlannerInfo *root, bool recursing);
 static void flatten_unplanned_rtes(PlannerGlobal *glob, RangeTblEntry *rte);
@@ -157,7 +160,7 @@ static Plan *set_mergeappend_references(PlannerInfo *root,
 										int rtoffset);
 static void set_hash_references(PlannerInfo *root, Plan *plan, int rtoffset);
 static Relids offset_relid_set(Relids relids, int rtoffset);
-static Node *fix_scan_expr(PlannerInfo *root, Node *node,
+static Node *fix_scan_expr(PlannerInfo *root, Plan *plan, Node *node,
 						   int rtoffset, double num_exec);
 static Node *fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context);
 static bool fix_scan_expr_walker(Node *node, fix_scan_expr_context *context);
@@ -183,7 +186,7 @@ static Var *search_indexed_tlist_for_sortgroupref(Expr *node,
 												  Index sortgroupref,
 												  indexed_tlist *itlist,
 												  int newvarno);
-static List *fix_join_expr(PlannerInfo *root,
+static List *fix_join_expr(PlannerInfo *root, Plan *plan,
 						   List *clauses,
 						   indexed_tlist *outer_itlist,
 						   indexed_tlist *inner_itlist,
@@ -193,7 +196,7 @@ static List *fix_join_expr(PlannerInfo *root,
 						   double num_exec);
 static Node *fix_join_expr_mutator(Node *node,
 								   fix_join_expr_context *context);
-static Node *fix_upper_expr(PlannerInfo *root,
+static Node *fix_upper_expr(PlannerInfo *root, Plan *plan,
 							Node *node,
 							indexed_tlist *subplan_itlist,
 							int newvarno,
@@ -202,7 +205,7 @@ static Node *fix_upper_expr(PlannerInfo *root,
 							double num_exec);
 static Node *fix_upper_expr_mutator(Node *node,
 									fix_upper_expr_context *context);
-static List *set_returning_clause_references(PlannerInfo *root,
+static List *set_returning_clause_references(PlannerInfo *root, Plan *plan,
 											 List *rlist,
 											 Plan *topplan,
 											 Index resultRelation,
@@ -633,10 +636,10 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
 
 				splan->scan.scanrelid += rtoffset;
 				splan->scan.plan.targetlist =
-					fix_scan_list(root, splan->scan.plan.targetlist,
+					fix_scan_list(root, plan, splan->scan.plan.targetlist,
 								  rtoffset, NUM_EXEC_TLIST(plan));
 				splan->scan.plan.qual =
-					fix_scan_list(root, splan->scan.plan.qual,
+					fix_scan_list(root, plan, splan->scan.plan.qual,
 								  rtoffset, NUM_EXEC_QUAL(plan));
 			}
 			break;
@@ -646,13 +649,13 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
 
 				splan->scan.scanrelid += rtoffset;
 				splan->scan.plan.targetlist =
-					fix_scan_list(root, splan->scan.plan.targetlist,
+					fix_scan_list(root, plan, splan->scan.plan.targetlist,
 								  rtoffset, NUM_EXEC_TLIST(plan));
 				splan->scan.plan.qual =
-					fix_scan_list(root, splan->scan.plan.qual,
+					fix_scan_list(root, plan, splan->scan.plan.qual,
 								  rtoffset, NUM_EXEC_QUAL(plan));
 				splan->tablesample = (TableSampleClause *)
-					fix_scan_expr(root, (Node *) splan->tablesample,
+					fix_scan_expr(root, plan, (Node *) splan->tablesample,
 								  rtoffset, 1);
 			}
 			break;
@@ -662,22 +665,22 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
 
 				splan->scan.scanrelid += rtoffset;
 				splan->scan.plan.targetlist =
-					fix_scan_list(root, splan->scan.plan.targetlist,
+					fix_scan_list(root, plan, splan->scan.plan.targetlist,
 								  rtoffset, NUM_EXEC_TLIST(plan));
 				splan->scan.plan.qual =
-					fix_scan_list(root, splan->scan.plan.qual,
+					fix_scan_list(root, plan, splan->scan.plan.qual,
 								  rtoffset, NUM_EXEC_QUAL(plan));
 				splan->indexqual =
-					fix_scan_list(root, splan->indexqual,
+					fix_scan_list(root, plan, splan->indexqual,
 								  rtoffset, 1);
 				splan->indexqualorig =
-					fix_scan_list(root, splan->indexqualorig,
+					fix_scan_list(root, plan, splan->indexqualorig,
 								  rtoffset, NUM_EXEC_QUAL(plan));
 				splan->indexorderby =
-					fix_scan_list(root, splan->indexorderby,
+					fix_scan_list(root, plan, splan->indexorderby,
 								  rtoffset, 1);
 				splan->indexorderbyorig =
-					fix_scan_list(root, splan->indexorderbyorig,
+					fix_scan_list(root, plan, splan->indexorderbyorig,
 								  rtoffset, NUM_EXEC_QUAL(plan));
 			}
 			break;
@@ -697,9 +700,9 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
 				Assert(splan->scan.plan.targetlist == NIL);
 				Assert(splan->scan.plan.qual == NIL);
 				splan->indexqual =
-					fix_scan_list(root, splan->indexqual, rtoffset, 1);
+					fix_scan_list(root, plan, splan->indexqual, rtoffset, 1);
 				splan->indexqualorig =
-					fix_scan_list(root, splan->indexqualorig,
+					fix_scan_list(root, plan, splan->indexqualorig,
 								  rtoffset, NUM_EXEC_QUAL(plan));
 			}
 			break;
@@ -709,13 +712,13 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
 
 				splan->scan.scanrelid += rtoffset;
 				splan->scan.plan.targetlist =
-					fix_scan_list(root, splan->scan.plan.targetlist,
+					fix_scan_list(root, plan, splan->scan.plan.targetlist,
 								  rtoffset, NUM_EXEC_TLIST(plan));
 				splan->scan.plan.qual =
-					fix_scan_list(root, splan->scan.plan.qual,
+					fix_scan_list(root, plan, splan->scan.plan.qual,
 								  rtoffset, NUM_EXEC_QUAL(plan));
 				splan->bitmapqualorig =
-					fix_scan_list(root, splan->bitmapqualorig,
+					fix_scan_list(root, plan, splan->bitmapqualorig,
 								  rtoffset, NUM_EXEC_QUAL(plan));
 			}
 			break;
@@ -725,13 +728,13 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
 
 				splan->scan.scanrelid += rtoffset;
 				splan->scan.plan.targetlist =
-					fix_scan_list(root, splan->scan.plan.targetlist,
+					fix_scan_list(root, plan, splan->scan.plan.targetlist,
 								  rtoffset, NUM_EXEC_TLIST(plan));
 				splan->scan.plan.qual =
-					fix_scan_list(root, splan->scan.plan.qual,
+					fix_scan_list(root, plan, splan->scan.plan.qual,
 								  rtoffset, NUM_EXEC_QUAL(plan));
 				splan->tidquals =
-					fix_scan_list(root, splan->tidquals,
+					fix_scan_list(root, plan, splan->tidquals,
 								  rtoffset, 1);
 			}
 			break;
@@ -741,13 +744,13 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
 
 				splan->scan.scanrelid += rtoffset;
 				splan->scan.plan.targetlist =
-					fix_scan_list(root, splan->scan.plan.targetlist,
+					fix_scan_list(root, plan, splan->scan.plan.targetlist,
 								  rtoffset, NUM_EXEC_TLIST(plan));
 				splan->scan.plan.qual =
-					fix_scan_list(root, splan->scan.plan.qual,
+					fix_scan_list(root, plan, splan->scan.plan.qual,
 								  rtoffset, NUM_EXEC_QUAL(plan));
 				splan->tidrangequals =
-					fix_scan_list(root, splan->tidrangequals,
+					fix_scan_list(root, plan, splan->tidrangequals,
 								  rtoffset, 1);
 			}
 			break;
@@ -762,13 +765,13 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
 
 				splan->scan.scanrelid += rtoffset;
 				splan->scan.plan.targetlist =
-					fix_scan_list(root, splan->scan.plan.targetlist,
+					fix_scan_list(root, plan, splan->scan.plan.targetlist,
 								  rtoffset, NUM_EXEC_TLIST(plan));
 				splan->scan.plan.qual =
-					fix_scan_list(root, splan->scan.plan.qual,
+					fix_scan_list(root, plan, splan->scan.plan.qual,
 								  rtoffset, NUM_EXEC_QUAL(plan));
 				splan->functions =
-					fix_scan_list(root, splan->functions, rtoffset, 1);
+					fix_scan_list(root, plan, splan->functions, rtoffset, 1);
 			}
 			break;
 		case T_TableFuncScan:
@@ -777,13 +780,13 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
 
 				splan->scan.scanrelid += rtoffset;
 				splan->scan.plan.targetlist =
-					fix_scan_list(root, splan->scan.plan.targetlist,
+					fix_scan_list(root, plan, splan->scan.plan.targetlist,
 								  rtoffset, NUM_EXEC_TLIST(plan));
 				splan->scan.plan.qual =
-					fix_scan_list(root, splan->scan.plan.qual,
+					fix_scan_list(root, plan, splan->scan.plan.qual,
 								  rtoffset, NUM_EXEC_QUAL(plan));
 				splan->tablefunc = (TableFunc *)
-					fix_scan_expr(root, (Node *) splan->tablefunc,
+					fix_scan_expr(root, plan, (Node *) splan->tablefunc,
 								  rtoffset, 1);
 			}
 			break;
@@ -793,13 +796,13 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
 
 				splan->scan.scanrelid += rtoffset;
 				splan->scan.plan.targetlist =
-					fix_scan_list(root, splan->scan.plan.targetlist,
+					fix_scan_list(root, plan, splan->scan.plan.targetlist,
 								  rtoffset, NUM_EXEC_TLIST(plan));
 				splan->scan.plan.qual =
-					fix_scan_list(root, splan->scan.plan.qual,
+					fix_scan_list(root, plan, splan->scan.plan.qual,
 								  rtoffset, NUM_EXEC_QUAL(plan));
 				splan->values_lists =
-					fix_scan_list(root, splan->values_lists,
+					fix_scan_list(root, plan, splan->values_lists,
 								  rtoffset, 1);
 			}
 			break;
@@ -809,10 +812,10 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
 
 				splan->scan.scanrelid += rtoffset;
 				splan->scan.plan.targetlist =
-					fix_scan_list(root, splan->scan.plan.targetlist,
+					fix_scan_list(root, plan, splan->scan.plan.targetlist,
 								  rtoffset, NUM_EXEC_TLIST(plan));
 				splan->scan.plan.qual =
-					fix_scan_list(root, splan->scan.plan.qual,
+					fix_scan_list(root, plan, splan->scan.plan.qual,
 								  rtoffset, NUM_EXEC_QUAL(plan));
 			}
 			break;
@@ -822,10 +825,10 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
 
 				splan->scan.scanrelid += rtoffset;
 				splan->scan.plan.targetlist =
-					fix_scan_list(root, splan->scan.plan.targetlist,
+					fix_scan_list(root, plan, splan->scan.plan.targetlist,
 								  rtoffset, NUM_EXEC_TLIST(plan));
 				splan->scan.plan.qual =
-					fix_scan_list(root, splan->scan.plan.qual,
+					fix_scan_list(root, plan, splan->scan.plan.qual,
 								  rtoffset, NUM_EXEC_QUAL(plan));
 			}
 			break;
@@ -835,10 +838,10 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
 
 				splan->scan.scanrelid += rtoffset;
 				splan->scan.plan.targetlist =
-					fix_scan_list(root, splan->scan.plan.targetlist,
+					fix_scan_list(root, plan, splan->scan.plan.targetlist,
 								  rtoffset, NUM_EXEC_TLIST(plan));
 				splan->scan.plan.qual =
-					fix_scan_list(root, splan->scan.plan.qual,
+					fix_scan_list(root, plan, splan->scan.plan.qual,
 								  rtoffset, NUM_EXEC_QUAL(plan));
 			}
 			break;
@@ -877,7 +880,7 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
 				 */
 				set_dummy_tlist_references(plan, rtoffset);
 
-				mplan->param_exprs = fix_scan_list(root, mplan->param_exprs,
+				mplan->param_exprs = fix_scan_list(root, plan, mplan->param_exprs,
 												   rtoffset,
 												   NUM_EXEC_TLIST(plan));
 				break;
@@ -939,9 +942,9 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
 				Assert(splan->plan.qual == NIL);
 
 				splan->limitOffset =
-					fix_scan_expr(root, splan->limitOffset, rtoffset, 1);
+					fix_scan_expr(root, plan, splan->limitOffset, rtoffset, 1);
 				splan->limitCount =
-					fix_scan_expr(root, splan->limitCount, rtoffset, 1);
+					fix_scan_expr(root, plan, splan->limitCount, rtoffset, 1);
 			}
 			break;
 		case T_Agg:
@@ -994,14 +997,14 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
 				 * variable refs, so fix_scan_expr works for them.
 				 */
 				wplan->startOffset =
-					fix_scan_expr(root, wplan->startOffset, rtoffset, 1);
+					fix_scan_expr(root, plan, wplan->startOffset, rtoffset, 1);
 				wplan->endOffset =
-					fix_scan_expr(root, wplan->endOffset, rtoffset, 1);
-				wplan->runCondition = fix_scan_list(root,
+					fix_scan_expr(root, plan, wplan->endOffset, rtoffset, 1);
+				wplan->runCondition = fix_scan_list(root, plan,
 													wplan->runCondition,
 													rtoffset,
 													NUM_EXEC_TLIST(plan));
-				wplan->runConditionOrig = fix_scan_list(root,
+				wplan->runConditionOrig = fix_scan_list(root, plan,
 														wplan->runConditionOrig,
 														rtoffset,
 														NUM_EXEC_TLIST(plan));
@@ -1043,15 +1046,16 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
 					}
 
 					splan->plan.targetlist =
-						fix_scan_list(root, splan->plan.targetlist,
+						fix_scan_list(root, plan, splan->plan.targetlist,
 									  rtoffset, NUM_EXEC_TLIST(plan));
 					splan->plan.qual =
-						fix_scan_list(root, splan->plan.qual,
+						fix_scan_list(root, plan, splan->plan.qual,
 									  rtoffset, NUM_EXEC_QUAL(plan));
 				}
 				/* resconstantqual can't contain any subplan variable refs */
 				splan->resconstantqual =
-					fix_scan_expr(root, splan->resconstantqual, rtoffset, 1);
+					fix_scan_expr(root, plan, splan->resconstantqual, rtoffset,
+								  1);
 			}
 			break;
 		case T_ProjectSet:
@@ -1066,7 +1070,7 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
 				Assert(splan->plan.qual == NIL);
 
 				splan->withCheckOptionLists =
-					fix_scan_list(root, splan->withCheckOptionLists,
+					fix_scan_list(root, plan, splan->withCheckOptionLists,
 								  rtoffset, 1);
 
 				if (splan->returningLists)
@@ -1086,7 +1090,7 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
 						List	   *rlist = (List *) lfirst(lcrl);
 						Index		resultrel = lfirst_int(lcrr);
 
-						rlist = set_returning_clause_references(root,
+						rlist = set_returning_clause_references(root, plan,
 																rlist,
 																subplan,
 																resultrel,
@@ -1121,13 +1125,13 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
 					itlist = build_tlist_index(splan->exclRelTlist);
 
 					splan->onConflictSet =
-						fix_join_expr(root, splan->onConflictSet,
+						fix_join_expr(root, plan, splan->onConflictSet,
 									  NULL, itlist,
 									  linitial_int(splan->resultRelations),
 									  rtoffset, NRM_EQUAL, NUM_EXEC_QUAL(plan));
 
 					splan->onConflictWhere = (Node *)
-						fix_join_expr(root, (List *) splan->onConflictWhere,
+						fix_join_expr(root, plan, (List *) splan->onConflictWhere,
 									  NULL, itlist,
 									  linitial_int(splan->resultRelations),
 									  rtoffset, NRM_EQUAL, NUM_EXEC_QUAL(plan));
@@ -1135,7 +1139,7 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
 					pfree(itlist);
 
 					splan->exclRelTlist =
-						fix_scan_list(root, splan->exclRelTlist, rtoffset, 1);
+						fix_scan_list(root, plan, splan->exclRelTlist, rtoffset, 1);
 				}
 
 				/*
@@ -1186,7 +1190,7 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
 							MergeAction *action = (MergeAction *) lfirst(l);
 
 							/* Fix targetList of each action. */
-							action->targetList = fix_join_expr(root,
+							action->targetList = fix_join_expr(root, plan,
 															   action->targetList,
 															   NULL, itlist,
 															   resultrel,
@@ -1195,7 +1199,7 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
 															   NUM_EXEC_TLIST(plan));
 
 							/* Fix quals too. */
-							action->qual = (Node *) fix_join_expr(root,
+							action->qual = (Node *) fix_join_expr(root, plan,
 																  (List *) action->qual,
 																  NULL, itlist,
 																  resultrel,
@@ -1206,7 +1210,7 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
 
 						/* Fix join condition too. */
 						mergeJoinCondition = (Node *)
-							fix_join_expr(root,
+							fix_join_expr(root, plan,
 										  (List *) mergeJoinCondition,
 										  NULL, itlist,
 										  resultrel,
@@ -1353,7 +1357,7 @@ set_indexonlyscan_references(PlannerInfo *root,
 
 	plan->scan.scanrelid += rtoffset;
 	plan->scan.plan.targetlist = (List *)
-		fix_upper_expr(root,
+		fix_upper_expr(root, (Plan *) plan,
 					   (Node *) plan->scan.plan.targetlist,
 					   index_itlist,
 					   INDEX_VAR,
@@ -1361,7 +1365,7 @@ set_indexonlyscan_references(PlannerInfo *root,
 					   NRM_EQUAL,
 					   NUM_EXEC_TLIST((Plan *) plan));
 	plan->scan.plan.qual = (List *)
-		fix_upper_expr(root,
+		fix_upper_expr(root, (Plan *) plan,
 					   (Node *) plan->scan.plan.qual,
 					   index_itlist,
 					   INDEX_VAR,
@@ -1369,7 +1373,7 @@ set_indexonlyscan_references(PlannerInfo *root,
 					   NRM_EQUAL,
 					   NUM_EXEC_QUAL((Plan *) plan));
 	plan->recheckqual = (List *)
-		fix_upper_expr(root,
+		fix_upper_expr(root, (Plan *) plan,
 					   (Node *) plan->recheckqual,
 					   index_itlist,
 					   INDEX_VAR,
@@ -1377,13 +1381,13 @@ set_indexonlyscan_references(PlannerInfo *root,
 					   NRM_EQUAL,
 					   NUM_EXEC_QUAL((Plan *) plan));
 	/* indexqual is already transformed to reference index columns */
-	plan->indexqual = fix_scan_list(root, plan->indexqual,
+	plan->indexqual = fix_scan_list(root, (Plan *) plan, plan->indexqual,
 									rtoffset, 1);
 	/* indexorderby is already transformed to reference index columns */
-	plan->indexorderby = fix_scan_list(root, plan->indexorderby,
+	plan->indexorderby = fix_scan_list(root, (Plan *) plan, plan->indexorderby,
 									   rtoffset, 1);
 	/* indextlist must NOT be transformed to reference index columns */
-	plan->indextlist = fix_scan_list(root, plan->indextlist,
+	plan->indextlist = fix_scan_list(root, (Plan *) plan, plan->indextlist,
 									 rtoffset, NUM_EXEC_TLIST((Plan *) plan));
 
 	pfree(index_itlist);
@@ -1430,10 +1434,10 @@ set_subqueryscan_references(PlannerInfo *root,
 		 */
 		plan->scan.scanrelid += rtoffset;
 		plan->scan.plan.targetlist =
-			fix_scan_list(root, plan->scan.plan.targetlist,
+			fix_scan_list(root, (Plan *) plan, plan->scan.plan.targetlist,
 						  rtoffset, NUM_EXEC_TLIST((Plan *) plan));
 		plan->scan.plan.qual =
-			fix_scan_list(root, plan->scan.plan.qual,
+			fix_scan_list(root, (Plan *) plan, plan->scan.plan.qual,
 						  rtoffset, NUM_EXEC_QUAL((Plan *) plan));
 
 		result = (Plan *) plan;
@@ -1599,7 +1603,7 @@ set_foreignscan_references(PlannerInfo *root,
 		indexed_tlist *itlist = build_tlist_index(fscan->fdw_scan_tlist);
 
 		fscan->scan.plan.targetlist = (List *)
-			fix_upper_expr(root,
+			fix_upper_expr(root, (Plan *) fscan,
 						   (Node *) fscan->scan.plan.targetlist,
 						   itlist,
 						   INDEX_VAR,
@@ -1607,7 +1611,7 @@ set_foreignscan_references(PlannerInfo *root,
 						   NRM_EQUAL,
 						   NUM_EXEC_TLIST((Plan *) fscan));
 		fscan->scan.plan.qual = (List *)
-			fix_upper_expr(root,
+			fix_upper_expr(root, (Plan *) fscan,
 						   (Node *) fscan->scan.plan.qual,
 						   itlist,
 						   INDEX_VAR,
@@ -1615,7 +1619,7 @@ set_foreignscan_references(PlannerInfo *root,
 						   NRM_EQUAL,
 						   NUM_EXEC_QUAL((Plan *) fscan));
 		fscan->fdw_exprs = (List *)
-			fix_upper_expr(root,
+			fix_upper_expr(root, (Plan *) fscan,
 						   (Node *) fscan->fdw_exprs,
 						   itlist,
 						   INDEX_VAR,
@@ -1623,7 +1627,7 @@ set_foreignscan_references(PlannerInfo *root,
 						   NRM_EQUAL,
 						   NUM_EXEC_QUAL((Plan *) fscan));
 		fscan->fdw_recheck_quals = (List *)
-			fix_upper_expr(root,
+			fix_upper_expr(root, (Plan *) fscan,
 						   (Node *) fscan->fdw_recheck_quals,
 						   itlist,
 						   INDEX_VAR,
@@ -1633,7 +1637,7 @@ set_foreignscan_references(PlannerInfo *root,
 		pfree(itlist);
 		/* fdw_scan_tlist itself just needs fix_scan_list() adjustments */
 		fscan->fdw_scan_tlist =
-			fix_scan_list(root, fscan->fdw_scan_tlist,
+			fix_scan_list(root, (Plan *) fscan, fscan->fdw_scan_tlist,
 						  rtoffset, NUM_EXEC_TLIST((Plan *) fscan));
 	}
 	else
@@ -1643,16 +1647,16 @@ set_foreignscan_references(PlannerInfo *root,
 		 * way
 		 */
 		fscan->scan.plan.targetlist =
-			fix_scan_list(root, fscan->scan.plan.targetlist,
+			fix_scan_list(root, (Plan *) fscan, fscan->scan.plan.targetlist,
 						  rtoffset, NUM_EXEC_TLIST((Plan *) fscan));
 		fscan->scan.plan.qual =
-			fix_scan_list(root, fscan->scan.plan.qual,
+			fix_scan_list(root, (Plan *) fscan, fscan->scan.plan.qual,
 						  rtoffset, NUM_EXEC_QUAL((Plan *) fscan));
 		fscan->fdw_exprs =
-			fix_scan_list(root, fscan->fdw_exprs,
+			fix_scan_list(root, (Plan *) fscan, fscan->fdw_exprs,
 						  rtoffset, NUM_EXEC_QUAL((Plan *) fscan));
 		fscan->fdw_recheck_quals =
-			fix_scan_list(root, fscan->fdw_recheck_quals,
+			fix_scan_list(root, (Plan *) fscan, fscan->fdw_recheck_quals,
 						  rtoffset, NUM_EXEC_QUAL((Plan *) fscan));
 	}
 
@@ -1685,7 +1689,7 @@ set_customscan_references(PlannerInfo *root,
 		indexed_tlist *itlist = build_tlist_index(cscan->custom_scan_tlist);
 
 		cscan->scan.plan.targetlist = (List *)
-			fix_upper_expr(root,
+			fix_upper_expr(root, (Plan *) cscan,
 						   (Node *) cscan->scan.plan.targetlist,
 						   itlist,
 						   INDEX_VAR,
@@ -1693,7 +1697,7 @@ set_customscan_references(PlannerInfo *root,
 						   NRM_EQUAL,
 						   NUM_EXEC_TLIST((Plan *) cscan));
 		cscan->scan.plan.qual = (List *)
-			fix_upper_expr(root,
+			fix_upper_expr(root, (Plan *) cscan,
 						   (Node *) cscan->scan.plan.qual,
 						   itlist,
 						   INDEX_VAR,
@@ -1701,7 +1705,7 @@ set_customscan_references(PlannerInfo *root,
 						   NRM_EQUAL,
 						   NUM_EXEC_QUAL((Plan *) cscan));
 		cscan->custom_exprs = (List *)
-			fix_upper_expr(root,
+			fix_upper_expr(root, (Plan *) cscan,
 						   (Node *) cscan->custom_exprs,
 						   itlist,
 						   INDEX_VAR,
@@ -1711,20 +1715,20 @@ set_customscan_references(PlannerInfo *root,
 		pfree(itlist);
 		/* custom_scan_tlist itself just needs fix_scan_list() adjustments */
 		cscan->custom_scan_tlist =
-			fix_scan_list(root, cscan->custom_scan_tlist,
+			fix_scan_list(root, (Plan *) cscan, cscan->custom_scan_tlist,
 						  rtoffset, NUM_EXEC_TLIST((Plan *) cscan));
 	}
 	else
 	{
 		/* Adjust tlist, qual, custom_exprs in the standard way */
 		cscan->scan.plan.targetlist =
-			fix_scan_list(root, cscan->scan.plan.targetlist,
+			fix_scan_list(root, (Plan *) cscan, cscan->scan.plan.targetlist,
 						  rtoffset, NUM_EXEC_TLIST((Plan *) cscan));
 		cscan->scan.plan.qual =
-			fix_scan_list(root, cscan->scan.plan.qual,
+			fix_scan_list(root, (Plan *) cscan, cscan->scan.plan.qual,
 						  rtoffset, NUM_EXEC_QUAL((Plan *) cscan));
 		cscan->custom_exprs =
-			fix_scan_list(root, cscan->custom_exprs,
+			fix_scan_list(root, (Plan *) cscan, cscan->custom_exprs,
 						  rtoffset, NUM_EXEC_QUAL((Plan *) cscan));
 	}
 
@@ -1752,7 +1756,8 @@ set_customscan_references(PlannerInfo *root,
  * startup time.
  */
 static int
-register_partpruneinfo(PlannerInfo *root, int part_prune_index, int rtoffset)
+register_partpruneinfo(PlannerInfo *root, Plan *plan, int part_prune_index,
+					   int rtoffset)
 {
 	PlannerGlobal *glob = root->glob;
 	PartitionPruneInfo *pinfo;
@@ -1776,10 +1781,10 @@ register_partpruneinfo(PlannerInfo *root, int part_prune_index, int rtoffset)
 
 			prelinfo->rtindex += rtoffset;
 			prelinfo->initial_pruning_steps =
-				fix_scan_list(root, prelinfo->initial_pruning_steps,
+				fix_scan_list(root, plan, prelinfo->initial_pruning_steps,
 							  rtoffset, 1);
 			prelinfo->exec_pruning_steps =
-				fix_scan_list(root, prelinfo->exec_pruning_steps,
+				fix_scan_list(root, plan, prelinfo->exec_pruning_steps,
 							  rtoffset, 1);
 
 			for (i = 0; i < prelinfo->nparts; i++)
@@ -1863,7 +1868,8 @@ set_append_references(PlannerInfo *root,
 	 */
 	if (aplan->part_prune_index >= 0)
 		aplan->part_prune_index =
-			register_partpruneinfo(root, aplan->part_prune_index, rtoffset);
+			register_partpruneinfo(root, (Plan *) aplan,
+								   aplan->part_prune_index, rtoffset);
 
 	/* We don't need to recurse to lefttree or righttree ... */
 	Assert(aplan->plan.lefttree == NULL);
@@ -1931,7 +1937,8 @@ set_mergeappend_references(PlannerInfo *root,
 	 */
 	if (mplan->part_prune_index >= 0)
 		mplan->part_prune_index =
-			register_partpruneinfo(root, mplan->part_prune_index, rtoffset);
+			register_partpruneinfo(root, (Plan *) mplan,
+								   mplan->part_prune_index, rtoffset);
 
 	/* We don't need to recurse to lefttree or righttree ... */
 	Assert(mplan->plan.lefttree == NULL);
@@ -1958,7 +1965,7 @@ set_hash_references(PlannerInfo *root, Plan *plan, int rtoffset)
 	 */
 	outer_itlist = build_tlist_index(outer_plan->targetlist);
 	hplan->hashkeys = (List *)
-		fix_upper_expr(root,
+		fix_upper_expr(root, plan,
 					   (Node *) hplan->hashkeys,
 					   outer_itlist,
 					   OUTER_VAR,
@@ -2194,7 +2201,8 @@ fix_alternative_subplan(PlannerInfo *root, AlternativeSubPlan *asplan,
  * replacing Aggref nodes that should be replaced by initplan output Params,
  * choosing the best implementation for AlternativeSubPlans,
  * looking up operator opcode info for OpExpr and related nodes,
- * and adding OIDs from regclass Const nodes into root->glob->relationOids.
+ * adding OIDs from regclass Const nodes into root->glob->relationOids, and
+ * recording Subplans that use hash tables.
  *
  * 'node': the expression to be modified
  * 'rtoffset': how much to increment varnos by
@@ -2204,11 +2212,13 @@ fix_alternative_subplan(PlannerInfo *root, AlternativeSubPlan *asplan,
  * if that seems safe.
  */
 static Node *
-fix_scan_expr(PlannerInfo *root, Node *node, int rtoffset, double num_exec)
+fix_scan_expr(PlannerInfo *root, Plan *plan, Node *node, int rtoffset,
+			  double num_exec)
 {
 	fix_scan_expr_context context;
 
 	context.root = root;
+	context.plan = plan;
 	context.rtoffset = rtoffset;
 	context.num_exec = num_exec;
 
@@ -2299,8 +2309,21 @@ fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context)
 															 (AlternativeSubPlan *) node,
 															 context->num_exec),
 									 context);
+
 	fix_expr_common(context->root, node);
-	return expression_tree_mutator(node, fix_scan_expr_mutator, context);
+	node = expression_tree_mutator(node, fix_scan_expr_mutator, context);
+
+	if (IsA(node, SubPlan))
+	{
+		/*
+		 * Track this (mutated) SubPlan so that we can assign working memory
+		 * to it, if needed.
+		 */
+		if (context->plan)
+			context->plan->subPlan = lappend(context->plan->subPlan, node);
+	}
+
+	return node;
 }
 
 static bool
@@ -2312,6 +2335,17 @@ fix_scan_expr_walker(Node *node, fix_scan_expr_context *context)
 	Assert(!IsA(node, PlaceHolderVar));
 	Assert(!IsA(node, AlternativeSubPlan));
 	fix_expr_common(context->root, node);
+
+	if (IsA(node, SubPlan))
+	{
+		/*
+		 * Track this SubPlan so that we can assign working memory to it (if
+		 * needed).
+		 */
+		if (context->plan)
+			context->plan->subPlan = lappend(context->plan->subPlan, node);
+	}
+
 	return expression_tree_walker(node, fix_scan_expr_walker, context);
 }
 
@@ -2341,7 +2375,7 @@ set_join_references(PlannerInfo *root, Join *join, int rtoffset)
 	 * NestLoopParams now, because those couldn't refer to nullable
 	 * subexpressions.
 	 */
-	join->joinqual = fix_join_expr(root,
+	join->joinqual = fix_join_expr(root, (Plan *) join,
 								   join->joinqual,
 								   outer_itlist,
 								   inner_itlist,
@@ -2371,7 +2405,7 @@ set_join_references(PlannerInfo *root, Join *join, int rtoffset)
 			 * make things match up perfectly seems well out of proportion to
 			 * the value.
 			 */
-			nlp->paramval = (Var *) fix_upper_expr(root,
+			nlp->paramval = (Var *) fix_upper_expr(root, (Plan *) join,
 												   (Node *) nlp->paramval,
 												   outer_itlist,
 												   OUTER_VAR,
@@ -2388,7 +2422,7 @@ set_join_references(PlannerInfo *root, Join *join, int rtoffset)
 	{
 		MergeJoin  *mj = (MergeJoin *) join;
 
-		mj->mergeclauses = fix_join_expr(root,
+		mj->mergeclauses = fix_join_expr(root, (Plan *) join,
 										 mj->mergeclauses,
 										 outer_itlist,
 										 inner_itlist,
@@ -2401,7 +2435,7 @@ set_join_references(PlannerInfo *root, Join *join, int rtoffset)
 	{
 		HashJoin   *hj = (HashJoin *) join;
 
-		hj->hashclauses = fix_join_expr(root,
+		hj->hashclauses = fix_join_expr(root, (Plan *) join,
 										hj->hashclauses,
 										outer_itlist,
 										inner_itlist,
@@ -2414,7 +2448,7 @@ set_join_references(PlannerInfo *root, Join *join, int rtoffset)
 		 * HashJoin's hashkeys are used to look for matching tuples from its
 		 * outer plan (not the Hash node!) in the hashtable.
 		 */
-		hj->hashkeys = (List *) fix_upper_expr(root,
+		hj->hashkeys = (List *) fix_upper_expr(root, (Plan *) join,
 											   (Node *) hj->hashkeys,
 											   outer_itlist,
 											   OUTER_VAR,
@@ -2433,7 +2467,7 @@ set_join_references(PlannerInfo *root, Join *join, int rtoffset)
 	 * be, so we just tell fix_join_expr to accept superset nullingrels
 	 * matches instead of exact ones.
 	 */
-	join->plan.targetlist = fix_join_expr(root,
+	join->plan.targetlist = fix_join_expr(root, (Plan *) join,
 										  join->plan.targetlist,
 										  outer_itlist,
 										  inner_itlist,
@@ -2441,7 +2475,7 @@ set_join_references(PlannerInfo *root, Join *join, int rtoffset)
 										  rtoffset,
 										  (join->jointype == JOIN_INNER ? NRM_EQUAL : NRM_SUPERSET),
 										  NUM_EXEC_TLIST((Plan *) join));
-	join->plan.qual = fix_join_expr(root,
+	join->plan.qual = fix_join_expr(root, (Plan *) join,
 									join->plan.qual,
 									outer_itlist,
 									inner_itlist,
@@ -2519,7 +2553,7 @@ set_upper_references(PlannerInfo *root, Plan *plan, int rtoffset)
 													  subplan_itlist,
 													  OUTER_VAR);
 			if (!newexpr)
-				newexpr = fix_upper_expr(root,
+				newexpr = fix_upper_expr(root, plan,
 										 (Node *) tle->expr,
 										 subplan_itlist,
 										 OUTER_VAR,
@@ -2528,7 +2562,7 @@ set_upper_references(PlannerInfo *root, Plan *plan, int rtoffset)
 										 NUM_EXEC_TLIST(plan));
 		}
 		else
-			newexpr = fix_upper_expr(root,
+			newexpr = fix_upper_expr(root, plan,
 									 (Node *) tle->expr,
 									 subplan_itlist,
 									 OUTER_VAR,
@@ -2542,7 +2576,7 @@ set_upper_references(PlannerInfo *root, Plan *plan, int rtoffset)
 	plan->targetlist = output_targetlist;
 
 	plan->qual = (List *)
-		fix_upper_expr(root,
+		fix_upper_expr(root, plan,
 					   (Node *) plan->qual,
 					   subplan_itlist,
 					   OUTER_VAR,
@@ -3081,6 +3115,7 @@ search_indexed_tlist_for_sortgroupref(Expr *node,
  *    the source relation elements, outer_itlist = NULL and acceptable_rel
  *    the target relation.
  *
+ * 'plan' is the Plan node to which the clauses belong
  * 'clauses' is the targetlist or list of join clauses
  * 'outer_itlist' is the indexed target list of the outer join relation,
  *		or NULL
@@ -3097,6 +3132,7 @@ search_indexed_tlist_for_sortgroupref(Expr *node,
  */
 static List *
 fix_join_expr(PlannerInfo *root,
+			  Plan *plan,
 			  List *clauses,
 			  indexed_tlist *outer_itlist,
 			  indexed_tlist *inner_itlist,
@@ -3108,6 +3144,7 @@ fix_join_expr(PlannerInfo *root,
 	fix_join_expr_context context;
 
 	context.root = root;
+	context.plan = plan;
 	context.outer_itlist = outer_itlist;
 	context.inner_itlist = inner_itlist;
 	context.acceptable_rel = acceptable_rel;
@@ -3234,7 +3271,19 @@ fix_join_expr_mutator(Node *node, fix_join_expr_context *context)
 															 context->num_exec),
 									 context);
 	fix_expr_common(context->root, node);
-	return expression_tree_mutator(node, fix_join_expr_mutator, context);
+	node = expression_tree_mutator(node, fix_join_expr_mutator, context);
+
+	if (IsA(node, SubPlan))
+	{
+		/*
+		 * Track this (mutated) SubPlan so that we can assign working memory
+		 * to it, if needed.
+		 */
+		if (context->plan)
+			context->plan->subPlan = lappend(context->plan->subPlan, node);
+	}
+
+	return node;
 }
 
 /*
@@ -3258,6 +3307,7 @@ fix_join_expr_mutator(Node *node, fix_join_expr_context *context)
  * expensive, so we don't want to try it in the common case where the
  * subplan tlist is just a flattened list of Vars.)
  *
+ * 'plan': the Plan node to which the expression belongs
  * 'node': the tree to be fixed (a target item or qual)
  * 'subplan_itlist': indexed target list for subplan (or index)
  * 'newvarno': varno to use for Vars referencing tlist elements
@@ -3271,6 +3321,7 @@ fix_join_expr_mutator(Node *node, fix_join_expr_context *context)
  */
 static Node *
 fix_upper_expr(PlannerInfo *root,
+			   Plan *plan,
 			   Node *node,
 			   indexed_tlist *subplan_itlist,
 			   int newvarno,
@@ -3281,6 +3332,7 @@ fix_upper_expr(PlannerInfo *root,
 	fix_upper_expr_context context;
 
 	context.root = root;
+	context.plan = plan;
 	context.subplan_itlist = subplan_itlist;
 	context.newvarno = newvarno;
 	context.rtoffset = rtoffset;
@@ -3358,8 +3410,21 @@ fix_upper_expr_mutator(Node *node, fix_upper_expr_context *context)
 															  (AlternativeSubPlan *) node,
 															  context->num_exec),
 									  context);
+
 	fix_expr_common(context->root, node);
-	return expression_tree_mutator(node, fix_upper_expr_mutator, context);
+	node = expression_tree_mutator(node, fix_upper_expr_mutator, context);
+
+	if (IsA(node, SubPlan))
+	{
+		/*
+		 * Track this (mutated) SubPlan so that we can assign working memory
+		 * to it, if needed.
+		 */
+		if (context->plan)
+			context->plan->subPlan = lappend(context->plan->subPlan, node);
+	}
+
+	return node;
 }
 
 /*
@@ -3377,9 +3442,10 @@ fix_upper_expr_mutator(Node *node, fix_upper_expr_context *context)
  * We also must perform opcode lookup and add regclass OIDs to
  * root->glob->relationOids.
  *
+ * 'plan': the ModifyTable node itself
  * 'rlist': the RETURNING targetlist to be fixed
  * 'topplan': the top subplan node that will be just below the ModifyTable
- *		node (note it's not yet passed through set_plan_refs)
+ *		node
  * 'resultRelation': RT index of the associated result relation
  * 'rtoffset': how much to increment varnos by
  *
@@ -3391,7 +3457,7 @@ fix_upper_expr_mutator(Node *node, fix_upper_expr_context *context)
  * Note: resultRelation is not yet adjusted by rtoffset.
  */
 static List *
-set_returning_clause_references(PlannerInfo *root,
+set_returning_clause_references(PlannerInfo *root, Plan *plan,
 								List *rlist,
 								Plan *topplan,
 								Index resultRelation,
@@ -3415,7 +3481,7 @@ set_returning_clause_references(PlannerInfo *root,
 	 */
 	itlist = build_tlist_index_other_vars(topplan->targetlist, resultRelation);
 
-	rlist = fix_join_expr(root,
+	rlist = fix_join_expr(root, plan,
 						  rlist,
 						  itlist,
 						  NULL,
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index 67da7f091b5..d3f8fd7bd6c 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -206,6 +206,8 @@ typedef struct Plan
 	struct Plan *righttree;
 	/* Init Plan nodes (un-correlated expr subselects) */
 	List	   *initPlan;
+	/* Regular Sub Plan nodes (cf. "initPlan", above) */
+	List	   *subPlan;
 
 	/*
 	 * Information for management of parameter-change-driven rescanning
-- 
2.47.1

