From 02bca46338c9623735b466ccda52265fece6cafe Mon Sep 17 00:00:00 2001
From: Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
Date: Wed, 1 Mar 2017 11:07:28 +0530
Subject: [PATCH 1/3] Free up memory consumed by the paths.

Optimizer creates many paths while planning the query. Only one path
tree gets converted to the plan. Paths continue to occupy memory even
after the plan is created. For an un-PREPAREd query, it means that the
memory remains occupied till the end of the execution. Since plan node
copies the relevant information from the corresponding path, paths are
not needed after plan is created. We can free up that memory.

While creating global planner structure (PlannerGlob) we allocate a
separate memory context for creating paths. Every create_*_path()
function allocates path node in this context. The context is freed at
the end of planning cycle after creating PlannedStmt.

Ideally paths are not required after creating plan, so we should be
able to free the context right after the call to create_plan(). But we
need dummy paths while creating flat rtable in
set_plan_references()->add_rtes_to_flat_rtable(). There might be other
corner cases where we need paths. So free the path context at the end
of planning cycle.

Now that we have separate memory context to hold paths, we don't need
to switch contexts in make_dummy_rel().
---
 src/backend/optimizer/path/allpaths.c  |   25 ++++----
 src/backend/optimizer/path/joinpath.c  |    2 +-
 src/backend/optimizer/path/joinrels.c  |   37 ++++--------
 src/backend/optimizer/plan/planner.c   |   16 ++++-
 src/backend/optimizer/prep/prepunion.c |    4 +-
 src/backend/optimizer/util/pathnode.c  |  100 ++++++++++++++++++++------------
 src/include/nodes/relation.h           |    2 +
 src/include/optimizer/pathnode.h       |   10 +++-
 src/include/optimizer/paths.h          |    2 +-
 9 files changed, 113 insertions(+), 85 deletions(-)

diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 633b5c1..e22817e 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -325,7 +325,7 @@ set_rel_size(PlannerInfo *root, RelOptInfo *rel,
 		 * we don't have a convention for marking a rel as dummy except by
 		 * assigning a dummy path to it.
 		 */
-		set_dummy_rel_pathlist(rel);
+		set_dummy_rel_pathlist(root, rel);
 	}
 	else if (rte->inh)
 	{
@@ -769,7 +769,7 @@ set_tablesample_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *
 		 bms_membership(root->all_baserels) != BMS_SINGLETON) &&
 	 !(GetTsmRoutine(rte->tablesample->tsmhandler)->repeatable_across_scans))
 	{
-		path = (Path *) create_material_path(rel, path);
+		path = (Path *) create_material_path(root, rel, path);
 	}
 
 	add_path(rel, path);
@@ -993,7 +993,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
 			 * Some restriction clause reduced to constant FALSE or NULL after
 			 * substitution, so this child need not be scanned.
 			 */
-			set_dummy_rel_pathlist(childrel);
+			set_dummy_rel_pathlist(root, childrel);
 			continue;
 		}
 
@@ -1003,7 +1003,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
 			 * This child need not be scanned, so we can omit it from the
 			 * appendrel.
 			 */
-			set_dummy_rel_pathlist(childrel);
+			set_dummy_rel_pathlist(root, childrel);
 			continue;
 		}
 
@@ -1153,7 +1153,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
 		 * appendrel dummy.  We must do this in this phase so that the rel's
 		 * dummy-ness is visible when we generate paths for other rels.
 		 */
-		set_dummy_rel_pathlist(rel);
+		set_dummy_rel_pathlist(root, rel);
 	}
 
 	pfree(parent_attrsizes);
@@ -1314,7 +1314,8 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
 	 * if we have zero or one live subpath due to constraint exclusion.)
 	 */
 	if (subpaths_valid)
-		add_path(rel, (Path *) create_append_path(rel, subpaths, NULL, 0));
+		add_path(rel, (Path *) create_append_path(root, rel, subpaths, NULL,
+												  0));
 
 	/*
 	 * Consider an append of partial unordered, unparameterized partial paths.
@@ -1340,7 +1341,7 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
 		Assert(parallel_workers > 0);
 
 		/* Generate a partial append path. */
-		appendpath = create_append_path(rel, partial_subpaths, NULL,
+		appendpath = create_append_path(root, rel, partial_subpaths, NULL,
 										parallel_workers);
 		add_partial_path(rel, (Path *) appendpath);
 	}
@@ -1392,8 +1393,8 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
 		}
 
 		if (subpaths_valid)
-			add_path(rel, (Path *)
-					 create_append_path(rel, subpaths, required_outer, 0));
+			add_path(rel, (Path *) create_append_path(root, rel, subpaths,
+													  required_outer, 0));
 	}
 }
 
@@ -1613,7 +1614,7 @@ accumulate_append_subpath(List *subpaths, Path *path)
  * This is exported because inheritance_planner() has need for it.
  */
 void
-set_dummy_rel_pathlist(RelOptInfo *rel)
+set_dummy_rel_pathlist(PlannerInfo *root, RelOptInfo *rel)
 {
 	/* Set dummy size estimates --- we leave attr_widths[] as zeroes */
 	rel->rows = 0;
@@ -1623,7 +1624,7 @@ set_dummy_rel_pathlist(RelOptInfo *rel)
 	rel->pathlist = NIL;
 	rel->partial_pathlist = NIL;
 
-	add_path(rel, (Path *) create_append_path(rel, NIL, NULL, 0));
+	add_path(rel, (Path *) create_append_path(root, rel, NIL, NULL, 0));
 
 	/*
 	 * We set the cheapest path immediately, to ensure that IS_DUMMY_REL()
@@ -1808,7 +1809,7 @@ set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel,
 
 	if (IS_DUMMY_REL(sub_final_rel))
 	{
-		set_dummy_rel_pathlist(rel);
+		set_dummy_rel_pathlist(root, rel);
 		return;
 	}
 
diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c
index 2897245..2a0f6d9 100644
--- a/src/backend/optimizer/path/joinpath.c
+++ b/src/backend/optimizer/path/joinpath.c
@@ -1124,7 +1124,7 @@ match_unsorted_outer(PlannerInfo *root,
 		if (enable_material && inner_cheapest_total != NULL &&
 			!ExecMaterializesOutput(inner_cheapest_total->pathtype))
 			matpath = (Path *)
-				create_material_path(innerrel, inner_cheapest_total);
+				create_material_path(root, innerrel, inner_cheapest_total);
 	}
 
 	foreach(lc1, outerrel->pathlist)
diff --git a/src/backend/optimizer/path/joinrels.c b/src/backend/optimizer/path/joinrels.c
index 0d00683..f0c8b62 100644
--- a/src/backend/optimizer/path/joinrels.c
+++ b/src/backend/optimizer/path/joinrels.c
@@ -29,7 +29,7 @@ static void make_rels_by_clauseless_joins(PlannerInfo *root,
 static bool has_join_restriction(PlannerInfo *root, RelOptInfo *rel);
 static bool has_legal_joinclause(PlannerInfo *root, RelOptInfo *rel);
 static bool is_dummy_rel(RelOptInfo *rel);
-static void mark_dummy_rel(RelOptInfo *rel);
+static void mark_dummy_rel(PlannerInfo *root, RelOptInfo *rel);
 static bool restriction_is_constant_false(List *restrictlist,
 							  bool only_pushed_down);
 
@@ -748,7 +748,7 @@ make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2)
 			if (is_dummy_rel(rel1) || is_dummy_rel(rel2) ||
 				restriction_is_constant_false(restrictlist, false))
 			{
-				mark_dummy_rel(joinrel);
+				mark_dummy_rel(root, joinrel);
 				break;
 			}
 			add_paths_to_joinrel(root, joinrel, rel1, rel2,
@@ -762,12 +762,12 @@ make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2)
 			if (is_dummy_rel(rel1) ||
 				restriction_is_constant_false(restrictlist, true))
 			{
-				mark_dummy_rel(joinrel);
+				mark_dummy_rel(root, joinrel);
 				break;
 			}
 			if (restriction_is_constant_false(restrictlist, false) &&
 				bms_is_subset(rel2->relids, sjinfo->syn_righthand))
-				mark_dummy_rel(rel2);
+				mark_dummy_rel(root, rel2);
 			add_paths_to_joinrel(root, joinrel, rel1, rel2,
 								 JOIN_LEFT, sjinfo,
 								 restrictlist);
@@ -779,7 +779,7 @@ make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2)
 			if ((is_dummy_rel(rel1) && is_dummy_rel(rel2)) ||
 				restriction_is_constant_false(restrictlist, true))
 			{
-				mark_dummy_rel(joinrel);
+				mark_dummy_rel(root, joinrel);
 				break;
 			}
 			add_paths_to_joinrel(root, joinrel, rel1, rel2,
@@ -815,7 +815,7 @@ make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2)
 				if (is_dummy_rel(rel1) || is_dummy_rel(rel2) ||
 					restriction_is_constant_false(restrictlist, false))
 				{
-					mark_dummy_rel(joinrel);
+					mark_dummy_rel(root, joinrel);
 					break;
 				}
 				add_paths_to_joinrel(root, joinrel, rel1, rel2,
@@ -838,7 +838,7 @@ make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2)
 				if (is_dummy_rel(rel1) || is_dummy_rel(rel2) ||
 					restriction_is_constant_false(restrictlist, false))
 				{
-					mark_dummy_rel(joinrel);
+					mark_dummy_rel(root, joinrel);
 					break;
 				}
 				add_paths_to_joinrel(root, joinrel, rel1, rel2,
@@ -853,12 +853,12 @@ make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2)
 			if (is_dummy_rel(rel1) ||
 				restriction_is_constant_false(restrictlist, true))
 			{
-				mark_dummy_rel(joinrel);
+				mark_dummy_rel(root, joinrel);
 				break;
 			}
 			if (restriction_is_constant_false(restrictlist, false) &&
 				bms_is_subset(rel2->relids, sjinfo->syn_righthand))
-				mark_dummy_rel(rel2);
+				mark_dummy_rel(root, rel2);
 			add_paths_to_joinrel(root, joinrel, rel1, rel2,
 								 JOIN_ANTI, sjinfo,
 								 restrictlist);
@@ -1168,27 +1168,14 @@ is_dummy_rel(RelOptInfo *rel)
  * During GEQO planning, this can get invoked more than once on the same
  * baserel struct, so it's worth checking to see if the rel is already marked
  * dummy.
- *
- * Also, when called during GEQO join planning, we are in a short-lived
- * memory context.  We must make sure that the dummy path attached to a
- * baserel survives the GEQO cycle, else the baserel is trashed for future
- * GEQO cycles.  On the other hand, when we are marking a joinrel during GEQO,
- * we don't want the dummy path to clutter the main planning context.  Upshot
- * is that the best solution is to explicitly make the dummy path in the same
- * context the given RelOptInfo is in.
  */
 static void
-mark_dummy_rel(RelOptInfo *rel)
+mark_dummy_rel(PlannerInfo *root, RelOptInfo *rel)
 {
-	MemoryContext oldcontext;
-
 	/* Already marked? */
 	if (is_dummy_rel(rel))
 		return;
 
-	/* No, so choose correct context to make the dummy path in */
-	oldcontext = MemoryContextSwitchTo(GetMemoryChunkContext(rel));
-
 	/* Set dummy size estimate */
 	rel->rows = 0;
 
@@ -1197,12 +1184,10 @@ mark_dummy_rel(RelOptInfo *rel)
 	rel->partial_pathlist = NIL;
 
 	/* Set up the dummy path */
-	add_path(rel, (Path *) create_append_path(rel, NIL, NULL, 0));
+	add_path(rel, (Path *) create_append_path(root, rel, NIL, NULL, 0));
 
 	/* Set or update cheapest_total_path and related fields */
 	set_cheapest(rel);
-
-	MemoryContextSwitchTo(oldcontext);
 }
 
 
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index ca0ae78..b74e887 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -54,6 +54,7 @@
 #include "utils/rel.h"
 #include "utils/selfuncs.h"
 #include "utils/lsyscache.h"
+#include "utils/memutils.h"
 #include "utils/syscache.h"
 
 
@@ -218,6 +219,9 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
 	glob->lastPlanNodeId = 0;
 	glob->transientPlan = false;
 	glob->dependsOnRole = false;
+	glob->path_cxt = AllocSetContextCreate(CurrentMemoryContext,
+										   "Path creation temporary context",
+										   ALLOCSET_DEFAULT_SIZES);
 
 	/*
 	 * Assess whether it's feasible to use parallel mode for this query. We
@@ -414,6 +418,13 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
 	result->stmt_location = parse->stmt_location;
 	result->stmt_len = parse->stmt_len;
 
+	/*
+	 * We do not need paths any more, blow those away.
+	 * TODO: probably we should also set the pathlists to NIL.
+	 */
+	MemoryContextResetAndDeleteChildren(glob->path_cxt);
+	glob->path_cxt = NULL;
+
 	return result;
 }
 
@@ -1302,7 +1313,7 @@ inheritance_planner(PlannerInfo *root)
 	 */
 	if (subpaths == NIL)
 	{
-		set_dummy_rel_pathlist(final_rel);
+		set_dummy_rel_pathlist(root, final_rel);
 		return;
 	}
 
@@ -3334,7 +3345,7 @@ create_grouping_paths(PlannerInfo *root,
 				paths = lappend(paths, path);
 			}
 			path = (Path *)
-				create_append_path(grouped_rel,
+				create_append_path(root, grouped_rel,
 								   paths,
 								   NULL,
 								   0);
@@ -5261,6 +5272,7 @@ plan_cluster_use_sort(Oid tableOid, Oid indexOid)
 	query->commandType = CMD_SELECT;
 
 	glob = makeNode(PlannerGlobal);
+	glob->path_cxt = CurrentMemoryContext;
 
 	root = makeNode(PlannerInfo);
 	root->parse = query;
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index 1389db1..492f8df 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -566,7 +566,7 @@ generate_union_path(SetOperationStmt *op, PlannerInfo *root,
 	/*
 	 * Append the child results together.
 	 */
-	path = (Path *) create_append_path(result_rel, pathlist, NULL, 0);
+	path = (Path *) create_append_path(root, result_rel, pathlist, NULL, 0);
 
 	/* We have to manually jam the right tlist into the path; ick */
 	path->pathtarget = create_pathtarget(root, tlist);
@@ -678,7 +678,7 @@ generate_nonunion_path(SetOperationStmt *op, PlannerInfo *root,
 	/*
 	 * Append the child results together.
 	 */
-	path = (Path *) create_append_path(result_rel, pathlist, NULL, 0);
+	path = (Path *) create_append_path(root, result_rel, pathlist, NULL, 0);
 
 	/* We have to manually jam the right tlist into the path; ick */
 	path->pathtarget = create_pathtarget(root, tlist);
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index 3248296..3f1184c 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -930,6 +930,27 @@ add_partial_path_precheck(RelOptInfo *parent_rel, Cost total_cost,
  *****************************************************************************/
 
 /*
+ * The memory consumed by paths remains occupied after the plan is created.
+ * For an un-PREPAREd query, it means that the paths continue to occupy the
+ * memory till the end of the execution. Since plan node copies the relevant
+ * information from the corresponding path, paths are not needed after plan is
+ * created. Following macro creates specified Path node in a temporary memory
+ * context allocated while creating PlannerGlobal.  This memory context is
+ * reset at the end of planning to free up any memory consumed by paths.
+ */
+#define makePathNode(root, _type_)		((_type_ *) newPath((root), sizeof(_type_),T_##_type_))
+static Path *
+newPath(PlannerInfo *root, size_t size, NodeTag tag)
+{
+	Path	   *result;
+
+	Assert(sizeof(Path) <= size);
+	result = MemoryContextAllocZero(root->glob->path_cxt, size);
+	result->type = tag;
+	return result;
+}
+
+/*
  * create_seqscan_path
  *	  Creates a path corresponding to a sequential scan, returning the
  *	  pathnode.
@@ -938,7 +959,7 @@ Path *
 create_seqscan_path(PlannerInfo *root, RelOptInfo *rel,
 					Relids required_outer, int parallel_workers)
 {
-	Path	   *pathnode = makeNode(Path);
+	Path	   *pathnode = makePathNode(root, Path);
 
 	pathnode->pathtype = T_SeqScan;
 	pathnode->parent = rel;
@@ -962,7 +983,7 @@ create_seqscan_path(PlannerInfo *root, RelOptInfo *rel,
 Path *
 create_samplescan_path(PlannerInfo *root, RelOptInfo *rel, Relids required_outer)
 {
-	Path	   *pathnode = makeNode(Path);
+	Path	   *pathnode = makePathNode(root, Path);
 
 	pathnode->pathtype = T_SampleScan;
 	pathnode->parent = rel;
@@ -1018,7 +1039,7 @@ create_index_path(PlannerInfo *root,
 				  double loop_count,
 				  bool partial_path)
 {
-	IndexPath  *pathnode = makeNode(IndexPath);
+	IndexPath  *pathnode = makePathNode(root, IndexPath);
 	RelOptInfo *rel = index->rel;
 	List	   *indexquals,
 			   *indexqualcols;
@@ -1070,7 +1091,7 @@ create_bitmap_heap_path(PlannerInfo *root,
 						Relids required_outer,
 						double loop_count)
 {
-	BitmapHeapPath *pathnode = makeNode(BitmapHeapPath);
+	BitmapHeapPath *pathnode = makePathNode(root, BitmapHeapPath);
 
 	pathnode->path.pathtype = T_BitmapHeapScan;
 	pathnode->path.parent = rel;
@@ -1100,7 +1121,7 @@ create_bitmap_and_path(PlannerInfo *root,
 					   RelOptInfo *rel,
 					   List *bitmapquals)
 {
-	BitmapAndPath *pathnode = makeNode(BitmapAndPath);
+	BitmapAndPath *pathnode = makePathNode(root, BitmapAndPath);
 
 	pathnode->path.pathtype = T_BitmapAnd;
 	pathnode->path.parent = rel;
@@ -1136,7 +1157,7 @@ create_bitmap_or_path(PlannerInfo *root,
 					  RelOptInfo *rel,
 					  List *bitmapquals)
 {
-	BitmapOrPath *pathnode = makeNode(BitmapOrPath);
+	BitmapOrPath *pathnode = makePathNode(root, BitmapOrPath);
 
 	pathnode->path.pathtype = T_BitmapOr;
 	pathnode->path.parent = rel;
@@ -1171,7 +1192,7 @@ TidPath *
 create_tidscan_path(PlannerInfo *root, RelOptInfo *rel, List *tidquals,
 					Relids required_outer)
 {
-	TidPath    *pathnode = makeNode(TidPath);
+	TidPath    *pathnode = makePathNode(root, TidPath);
 
 	pathnode->path.pathtype = T_TidScan;
 	pathnode->path.parent = rel;
@@ -1199,10 +1220,13 @@ create_tidscan_path(PlannerInfo *root, RelOptInfo *rel, List *tidquals,
  * Note that we must handle subpaths = NIL, representing a dummy access path.
  */
 AppendPath *
-create_append_path(RelOptInfo *rel, List *subpaths, Relids required_outer,
+create_append_path(PlannerInfo *root,
+				   RelOptInfo *rel,
+				   List *subpaths,
+				   Relids required_outer,
 				   int parallel_workers)
 {
-	AppendPath *pathnode = makeNode(AppendPath);
+	AppendPath *pathnode = makePathNode(root, AppendPath);
 	ListCell   *l;
 
 	pathnode->path.pathtype = T_Append;
@@ -1259,7 +1283,7 @@ create_merge_append_path(PlannerInfo *root,
 						 List *pathkeys,
 						 Relids required_outer)
 {
-	MergeAppendPath *pathnode = makeNode(MergeAppendPath);
+	MergeAppendPath *pathnode = makePathNode(root, MergeAppendPath);
 	Cost		input_startup_cost;
 	Cost		input_total_cost;
 	ListCell   *l;
@@ -1346,7 +1370,7 @@ ResultPath *
 create_result_path(PlannerInfo *root, RelOptInfo *rel,
 				   PathTarget *target, List *resconstantqual)
 {
-	ResultPath *pathnode = makeNode(ResultPath);
+	ResultPath *pathnode = makePathNode(root, ResultPath);
 
 	pathnode->path.pathtype = T_Result;
 	pathnode->path.parent = rel;
@@ -1382,9 +1406,9 @@ create_result_path(PlannerInfo *root, RelOptInfo *rel,
  *	  pathnode.
  */
 MaterialPath *
-create_material_path(RelOptInfo *rel, Path *subpath)
+create_material_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath)
 {
-	MaterialPath *pathnode = makeNode(MaterialPath);
+	MaterialPath *pathnode = makePathNode(root, MaterialPath);
 
 	Assert(subpath->parent == rel);
 
@@ -1451,7 +1475,7 @@ create_unique_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath,
 	 */
 	oldcontext = MemoryContextSwitchTo(root->planner_cxt);
 
-	pathnode = makeNode(UniquePath);
+	pathnode = makePathNode(root, UniquePath);
 
 	pathnode->path.pathtype = T_Unique;
 	pathnode->path.parent = rel;
@@ -1667,7 +1691,7 @@ GatherPath *
 create_gather_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath,
 				   PathTarget *target, Relids required_outer, double *rows)
 {
-	GatherPath *pathnode = makeNode(GatherPath);
+	GatherPath *pathnode = makePathNode(root, GatherPath);
 
 	Assert(subpath->parallel_safe);
 
@@ -1705,7 +1729,7 @@ SubqueryScanPath *
 create_subqueryscan_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath,
 						 List *pathkeys, Relids required_outer)
 {
-	SubqueryScanPath *pathnode = makeNode(SubqueryScanPath);
+	SubqueryScanPath *pathnode = makePathNode(root, SubqueryScanPath);
 
 	pathnode->path.pathtype = T_SubqueryScan;
 	pathnode->path.parent = rel;
@@ -1733,7 +1757,7 @@ Path *
 create_functionscan_path(PlannerInfo *root, RelOptInfo *rel,
 						 List *pathkeys, Relids required_outer)
 {
-	Path	   *pathnode = makeNode(Path);
+	Path	   *pathnode = makePathNode(root, Path);
 
 	pathnode->pathtype = T_FunctionScan;
 	pathnode->parent = rel;
@@ -1759,7 +1783,7 @@ Path *
 create_valuesscan_path(PlannerInfo *root, RelOptInfo *rel,
 					   Relids required_outer)
 {
-	Path	   *pathnode = makeNode(Path);
+	Path	   *pathnode = makePathNode(root, Path);
 
 	pathnode->pathtype = T_ValuesScan;
 	pathnode->parent = rel;
@@ -1784,7 +1808,7 @@ create_valuesscan_path(PlannerInfo *root, RelOptInfo *rel,
 Path *
 create_ctescan_path(PlannerInfo *root, RelOptInfo *rel, Relids required_outer)
 {
-	Path	   *pathnode = makeNode(Path);
+	Path	   *pathnode = makePathNode(root, Path);
 
 	pathnode->pathtype = T_CteScan;
 	pathnode->parent = rel;
@@ -1810,7 +1834,7 @@ Path *
 create_worktablescan_path(PlannerInfo *root, RelOptInfo *rel,
 						  Relids required_outer)
 {
-	Path	   *pathnode = makeNode(Path);
+	Path	   *pathnode = makePathNode(root, Path);
 
 	pathnode->pathtype = T_WorkTableScan;
 	pathnode->parent = rel;
@@ -1849,7 +1873,7 @@ create_foreignscan_path(PlannerInfo *root, RelOptInfo *rel,
 						Path *fdw_outerpath,
 						List *fdw_private)
 {
-	ForeignPath *pathnode = makeNode(ForeignPath);
+	ForeignPath *pathnode = makePathNode(root, ForeignPath);
 
 	pathnode->path.pathtype = T_ForeignScan;
 	pathnode->path.parent = rel;
@@ -1955,7 +1979,7 @@ create_nestloop_path(PlannerInfo *root,
 					 List *pathkeys,
 					 Relids required_outer)
 {
-	NestPath   *pathnode = makeNode(NestPath);
+	NestPath   *pathnode = makePathNode(root, NestPath);
 	Relids		inner_req_outer = PATH_REQ_OUTER(inner_path);
 
 	/*
@@ -2045,7 +2069,7 @@ create_mergejoin_path(PlannerInfo *root,
 					  List *outersortkeys,
 					  List *innersortkeys)
 {
-	MergePath  *pathnode = makeNode(MergePath);
+	MergePath  *pathnode = makePathNode(root, MergePath);
 
 	pathnode->jpath.path.pathtype = T_MergeJoin;
 	pathnode->jpath.path.parent = joinrel;
@@ -2107,7 +2131,7 @@ create_hashjoin_path(PlannerInfo *root,
 					 Relids required_outer,
 					 List *hashclauses)
 {
-	HashPath   *pathnode = makeNode(HashPath);
+	HashPath   *pathnode = makePathNode(root, HashPath);
 
 	pathnode->jpath.path.pathtype = T_HashJoin;
 	pathnode->jpath.path.parent = joinrel;
@@ -2164,7 +2188,7 @@ create_projection_path(PlannerInfo *root,
 					   Path *subpath,
 					   PathTarget *target)
 {
-	ProjectionPath *pathnode = makeNode(ProjectionPath);
+	ProjectionPath *pathnode = makePathNode(root, ProjectionPath);
 	PathTarget *oldtarget = subpath->pathtarget;
 
 	pathnode->path.pathtype = T_Result;
@@ -2331,7 +2355,7 @@ create_set_projection_path(PlannerInfo *root,
 						   Path *subpath,
 						   PathTarget *target)
 {
-	ProjectSetPath *pathnode = makeNode(ProjectSetPath);
+	ProjectSetPath *pathnode = makePathNode(root, ProjectSetPath);
 	double		tlist_rows;
 	ListCell   *lc;
 
@@ -2399,7 +2423,7 @@ create_sort_path(PlannerInfo *root,
 				 List *pathkeys,
 				 double limit_tuples)
 {
-	SortPath   *pathnode = makeNode(SortPath);
+	SortPath   *pathnode = makePathNode(root, SortPath);
 
 	pathnode->path.pathtype = T_Sort;
 	pathnode->path.parent = rel;
@@ -2445,7 +2469,7 @@ create_group_path(PlannerInfo *root,
 				  List *qual,
 				  double numGroups)
 {
-	GroupPath  *pathnode = makeNode(GroupPath);
+	GroupPath  *pathnode = makePathNode(root, GroupPath);
 
 	pathnode->path.pathtype = T_Group;
 	pathnode->path.parent = rel;
@@ -2501,7 +2525,7 @@ create_upper_unique_path(PlannerInfo *root,
 						 int numCols,
 						 double numGroups)
 {
-	UpperUniquePath *pathnode = makeNode(UpperUniquePath);
+	UpperUniquePath *pathnode = makePathNode(root, UpperUniquePath);
 
 	pathnode->path.pathtype = T_Unique;
 	pathnode->path.parent = rel;
@@ -2558,7 +2582,7 @@ create_agg_path(PlannerInfo *root,
 				const AggClauseCosts *aggcosts,
 				double numGroups)
 {
-	AggPath    *pathnode = makeNode(AggPath);
+	AggPath    *pathnode = makePathNode(root, AggPath);
 
 	pathnode->path.pathtype = T_Agg;
 	pathnode->path.parent = rel;
@@ -2623,7 +2647,7 @@ create_groupingsets_path(PlannerInfo *root,
 						 const AggClauseCosts *agg_costs,
 						 double numGroups)
 {
-	GroupingSetsPath *pathnode = makeNode(GroupingSetsPath);
+	GroupingSetsPath *pathnode = makePathNode(root, GroupingSetsPath);
 	int			numGroupCols;
 
 	/* The topmost generated Plan node will be an Agg */
@@ -2736,7 +2760,7 @@ create_minmaxagg_path(PlannerInfo *root,
 					  List *mmaggregates,
 					  List *quals)
 {
-	MinMaxAggPath *pathnode = makeNode(MinMaxAggPath);
+	MinMaxAggPath *pathnode = makePathNode(root, MinMaxAggPath);
 	Cost		initplan_cost;
 	ListCell   *lc;
 
@@ -2797,7 +2821,7 @@ create_windowagg_path(PlannerInfo *root,
 					  WindowClause *winclause,
 					  List *winpathkeys)
 {
-	WindowAggPath *pathnode = makeNode(WindowAggPath);
+	WindowAggPath *pathnode = makePathNode(root, WindowAggPath);
 
 	pathnode->path.pathtype = T_WindowAgg;
 	pathnode->path.parent = rel;
@@ -2864,7 +2888,7 @@ create_setop_path(PlannerInfo *root,
 				  double numGroups,
 				  double outputRows)
 {
-	SetOpPath  *pathnode = makeNode(SetOpPath);
+	SetOpPath  *pathnode = makePathNode(root, SetOpPath);
 
 	pathnode->path.pathtype = T_SetOp;
 	pathnode->path.parent = rel;
@@ -2924,7 +2948,7 @@ create_recursiveunion_path(PlannerInfo *root,
 						   int wtParam,
 						   double numGroups)
 {
-	RecursiveUnionPath *pathnode = makeNode(RecursiveUnionPath);
+	RecursiveUnionPath *pathnode = makePathNode(root, RecursiveUnionPath);
 
 	pathnode->path.pathtype = T_RecursiveUnion;
 	pathnode->path.parent = rel;
@@ -2963,7 +2987,7 @@ LockRowsPath *
 create_lockrows_path(PlannerInfo *root, RelOptInfo *rel,
 					 Path *subpath, List *rowMarks, int epqParam)
 {
-	LockRowsPath *pathnode = makeNode(LockRowsPath);
+	LockRowsPath *pathnode = makePathNode(root, LockRowsPath);
 
 	pathnode->path.pathtype = T_LockRows;
 	pathnode->path.parent = rel;
@@ -3025,7 +3049,7 @@ create_modifytable_path(PlannerInfo *root, RelOptInfo *rel,
 						List *rowMarks, OnConflictExpr *onconflict,
 						int epqParam)
 {
-	ModifyTablePath *pathnode = makeNode(ModifyTablePath);
+	ModifyTablePath *pathnode = makePathNode(root, ModifyTablePath);
 	double		total_size;
 	ListCell   *lc;
 
@@ -3120,7 +3144,7 @@ create_limit_path(PlannerInfo *root, RelOptInfo *rel,
 				  Node *limitOffset, Node *limitCount,
 				  int64 offset_est, int64 count_est)
 {
-	LimitPath  *pathnode = makeNode(LimitPath);
+	LimitPath  *pathnode = makePathNode(root, LimitPath);
 
 	pathnode->path.pathtype = T_Limit;
 	pathnode->path.parent = rel;
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index f7ac6f6..aa2e9b3 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -128,6 +128,8 @@ typedef struct PlannerGlobal
 	bool		parallelModeNeeded;		/* parallel mode actually required? */
 
 	char		maxParallelHazard;		/* worst PROPARALLEL hazard level */
+
+	MemoryContext path_cxt;		/* Temporary context for holding paths. */
 } PlannerGlobal;
 
 /* macro for fetching the Plan associated with a SubPlan node */
diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h
index 53cad24..18591df 100644
--- a/src/include/optimizer/pathnode.h
+++ b/src/include/optimizer/pathnode.h
@@ -62,8 +62,11 @@ extern BitmapOrPath *create_bitmap_or_path(PlannerInfo *root,
 					  List *bitmapquals);
 extern TidPath *create_tidscan_path(PlannerInfo *root, RelOptInfo *rel,
 					List *tidquals, Relids required_outer);
-extern AppendPath *create_append_path(RelOptInfo *rel, List *subpaths,
-				   Relids required_outer, int parallel_workers);
+extern AppendPath *create_append_path(PlannerInfo *root,
+				   RelOptInfo *rel,
+				   List *subpaths,
+				   Relids required_outer,
+				   int parallel_workers);
 extern MergeAppendPath *create_merge_append_path(PlannerInfo *root,
 						 RelOptInfo *rel,
 						 List *subpaths,
@@ -71,7 +74,8 @@ extern MergeAppendPath *create_merge_append_path(PlannerInfo *root,
 						 Relids required_outer);
 extern ResultPath *create_result_path(PlannerInfo *root, RelOptInfo *rel,
 				   PathTarget *target, List *resconstantqual);
-extern MaterialPath *create_material_path(RelOptInfo *rel, Path *subpath);
+extern MaterialPath *create_material_path(PlannerInfo *root, RelOptInfo *rel,
+							Path *subpath);
 extern UniquePath *create_unique_path(PlannerInfo *root, RelOptInfo *rel,
 				   Path *subpath, SpecialJoinInfo *sjinfo);
 extern GatherPath *create_gather_path(PlannerInfo *root,
diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h
index ebda308..733e40d 100644
--- a/src/include/optimizer/paths.h
+++ b/src/include/optimizer/paths.h
@@ -49,7 +49,7 @@ extern PGDLLIMPORT join_search_hook_type join_search_hook;
 
 
 extern RelOptInfo *make_one_rel(PlannerInfo *root, List *joinlist);
-extern void set_dummy_rel_pathlist(RelOptInfo *rel);
+extern void set_dummy_rel_pathlist(PlannerInfo *root, RelOptInfo *rel);
 extern RelOptInfo *standard_join_search(PlannerInfo *root, int levels_needed,
 					 List *initial_rels);
 
-- 
1.7.9.5

