From d62d4a40dc52ab05416446d19eaf53125d33aa4b 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. The memory consumed by paths even
after the plan is created. For a simple 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 allocated 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.
---
 src/backend/optimizer/path/allpaths.c  |   25 ++++-----
 src/backend/optimizer/path/joinpath.c  |    2 +-
 src/backend/optimizer/path/joinrels.c  |   22 ++++----
 src/backend/optimizer/plan/planner.c   |   16 +++++-
 src/backend/optimizer/prep/prepunion.c |    4 +-
 src/backend/optimizer/util/pathnode.c  |   91 +++++++++++++++++++-------------
 src/include/nodes/relation.h           |    2 +
 src/include/optimizer/pathnode.h       |   10 ++--
 src/include/optimizer/paths.h          |    2 +-
 9 files changed, 104 insertions(+), 70 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..ff493b3 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);
@@ -1178,7 +1178,7 @@ is_dummy_rel(RelOptInfo *rel)
  * context the given RelOptInfo is in.
  */
 static void
-mark_dummy_rel(RelOptInfo *rel)
+mark_dummy_rel(PlannerInfo *root, RelOptInfo *rel)
 {
 	MemoryContext oldcontext;
 
@@ -1197,7 +1197,7 @@ 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);
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..b91b25e 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -928,6 +928,18 @@ add_partial_path_precheck(RelOptInfo *parent_rel, Cost total_cost,
 /*****************************************************************************
  *		PATH NODE CREATION ROUTINES
  *****************************************************************************/
+#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
@@ -938,7 +950,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 +974,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 +1030,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 +1082,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 +1112,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 +1148,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 +1183,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 +1211,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 +1274,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 +1361,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 +1397,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 +1466,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 +1682,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 +1720,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 +1748,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 +1774,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 +1799,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 +1825,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 +1864,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 +1970,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 +2060,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 +2122,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 +2179,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 +2346,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 +2414,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 +2460,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 +2516,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 +2573,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 +2638,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 +2751,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 +2812,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 +2879,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 +2939,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 +2978,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 +3040,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 +3135,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

