From 21b6132417644a07054a85b52e402c31d5c23420 Mon Sep 17 00:00:00 2001
From: Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
Date: Mon, 17 Jul 2023 10:57:30 +0530
Subject: [PATCH 3/4] Actual code to use pathnode referencing infrastructure

The commit uses the infrastructure built by the previous commit to references,
unreference and free paths.

The code is not completely mature. There are TODOs.
---
 src/backend/optimizer/util/pathnode.c | 126 +++++++++++++++-----------
 1 file changed, 71 insertions(+), 55 deletions(-)

diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index 09745d19b1..65469637b2 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -586,12 +586,8 @@ add_path(RelOptInfo *parent_rel, Path *new_path)
 		{
 			parent_rel->pathlist = foreach_delete_current(parent_rel->pathlist,
 														  p1);
-
-			/*
-			 * Delete the data pointed-to by the deleted cell, if possible
-			 */
-			if (!IsA(old_path, IndexPath))
-				pfree(old_path);
+			/* TODO: write a routine to unlink a path from the list node and delete the list node  */
+			unlink_path(&old_path);
 		}
 		else
 		{
@@ -614,12 +610,12 @@ add_path(RelOptInfo *parent_rel, Path *new_path)
 		/* Accept the new path: insert it at proper place in pathlist */
 		parent_rel->pathlist =
 			list_insert_nth(parent_rel->pathlist, insert_at, new_path);
+		new_path->ref_count++;
+		/* TODO: write a function to link_path in a List */
 	}
 	else
 	{
-		/* Reject and recycle the new path */
-		if (!IsA(new_path, IndexPath))
-			pfree(new_path);
+		free_path(new_path);
 	}
 }
 
@@ -822,7 +818,8 @@ add_partial_path(RelOptInfo *parent_rel, Path *new_path)
 		{
 			parent_rel->partial_pathlist =
 				foreach_delete_current(parent_rel->partial_pathlist, p1);
-			pfree(old_path);
+			/* TODO use routine to unlink a path from the linked list */
+			unlink_path(&old_path);
 		}
 		else
 		{
@@ -845,11 +842,13 @@ add_partial_path(RelOptInfo *parent_rel, Path *new_path)
 		/* Accept the new path: insert it at proper place */
 		parent_rel->partial_pathlist =
 			list_insert_nth(parent_rel->partial_pathlist, insert_at, new_path);
+		new_path->ref_count++;
+		/* TODO create a routine to link path in a list at a given place */
 	}
 	else
 	{
 		/* Reject and recycle the new path */
-		pfree(new_path);
+		free_path(new_path);
 	}
 }
 
@@ -1196,7 +1195,7 @@ create_bitmap_heap_path(PlannerInfo *root,
 	pathnode->path.parallel_workers = parallel_degree;
 	pathnode->path.pathkeys = NIL;	/* always unordered */
 
-	pathnode->bitmapqual = bitmapqual;
+	link_path(&(pathnode->bitmapqual), bitmapqual);
 
 	cost_bitmap_heap_scan(&pathnode->path, root, rel,
 						  pathnode->path.param_info,
@@ -1231,6 +1230,8 @@ create_bitmap_and_path(PlannerInfo *root,
 	{
 		Path	   *bitmapqual = (Path *) lfirst(lc);
 
+		/* TODO: find a better way to link a path in a linked list */
+		bitmapqual->ref_count++;
 		required_outer = bms_add_members(required_outer,
 										 PATH_REQ_OUTER(bitmapqual));
 	}
@@ -1283,6 +1284,8 @@ create_bitmap_or_path(PlannerInfo *root,
 	{
 		Path	   *bitmapqual = (Path *) lfirst(lc);
 
+		/* TODO: find a better way to link a path in a linked list */
+		bitmapqual->ref_count++;
 		required_outer = bms_add_members(required_outer,
 										 PATH_REQ_OUTER(bitmapqual));
 	}
@@ -1452,6 +1455,8 @@ create_append_path(PlannerInfo *root,
 	{
 		Path	   *subpath = (Path *) lfirst(l);
 
+		/* TODO: we should use the routine to link path to list */
+		subpath->ref_count++;
 		pathnode->path.parallel_safe = pathnode->path.parallel_safe &&
 			subpath->parallel_safe;
 
@@ -1587,6 +1592,9 @@ create_merge_append_path(PlannerInfo *root,
 	{
 		Path	   *subpath = (Path *) lfirst(l);
 
+		/* TODO: use routine which links a path into a list */
+		subpath->ref_count++;
+
 		pathnode->path.rows += subpath->rows;
 		pathnode->path.parallel_safe = pathnode->path.parallel_safe &&
 			subpath->parallel_safe;
@@ -1713,7 +1721,7 @@ create_material_path(RelOptInfo *rel, Path *subpath)
 	pathnode->path.parallel_workers = subpath->parallel_workers;
 	pathnode->path.pathkeys = subpath->pathkeys;
 
-	pathnode->subpath = subpath;
+	link_path(&pathnode->subpath, subpath);
 
 	cost_material(&pathnode->path,
 				  subpath->startup_cost,
@@ -1747,7 +1755,7 @@ create_memoize_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath,
 	pathnode->path.parallel_workers = subpath->parallel_workers;
 	pathnode->path.pathkeys = subpath->pathkeys;
 
-	pathnode->subpath = subpath;
+	link_path(&pathnode->subpath, subpath);
 	pathnode->hash_operators = hash_operators;
 	pathnode->param_exprs = param_exprs;
 	pathnode->singlerow = singlerow;
@@ -1838,7 +1846,7 @@ create_unique_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath,
 	 */
 	pathnode->path.pathkeys = NIL;
 
-	pathnode->subpath = subpath;
+	link_path(&(pathnode->subpath), subpath);
 	pathnode->in_operators = sjinfo->semi_operators;
 	pathnode->uniq_exprs = sjinfo->semi_rhs_exprs;
 
@@ -1859,7 +1867,8 @@ create_unique_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath,
 		pathnode->path.total_cost = subpath->total_cost;
 		pathnode->path.pathkeys = subpath->pathkeys;
 
-		rel->cheapest_unique_path = (Path *) pathnode;
+		/* TODO: Do we need to make sure that cheapest_unique_path is NULL. */
+		link_path(&(rel->cheapest_unique_path), (Path *) pathnode);
 
 		MemoryContextSwitchTo(oldcontext);
 
@@ -1897,7 +1906,7 @@ create_unique_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath,
 				pathnode->path.total_cost = subpath->total_cost;
 				pathnode->path.pathkeys = subpath->pathkeys;
 
-				rel->cheapest_unique_path = (Path *) pathnode;
+				link_path(&(rel->cheapest_unique_path), (Path *) pathnode);
 
 				MemoryContextSwitchTo(oldcontext);
 
@@ -1992,7 +2001,7 @@ create_unique_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath,
 		pathnode->path.total_cost = sort_path.total_cost;
 	}
 
-	rel->cheapest_unique_path = (Path *) pathnode;
+	link_path(&(rel->cheapest_unique_path), (Path *) pathnode);
 
 	MemoryContextSwitchTo(oldcontext);
 
@@ -2023,7 +2032,7 @@ create_gather_merge_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath,
 														  required_outer);
 	pathnode->path.parallel_aware = false;
 
-	pathnode->subpath = subpath;
+	link_path(&pathnode->subpath, subpath);
 	pathnode->num_workers = subpath->parallel_workers;
 	pathnode->path.pathkeys = pathkeys;
 	pathnode->path.pathtarget = target ? target : rel->reltarget;
@@ -2114,7 +2123,7 @@ create_gather_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath,
 	pathnode->path.parallel_workers = 0;
 	pathnode->path.pathkeys = NIL;	/* Gather has unordered result */
 
-	pathnode->subpath = subpath;
+	link_path(&(pathnode->subpath), subpath);
 	pathnode->num_workers = subpath->parallel_workers;
 	pathnode->single_copy = false;
 
@@ -2157,7 +2166,7 @@ create_subqueryscan_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath,
 		subpath->parallel_safe;
 	pathnode->path.parallel_workers = subpath->parallel_workers;
 	pathnode->path.pathkeys = pathkeys;
-	pathnode->subpath = subpath;
+	link_path(&pathnode->subpath, subpath);
 
 	cost_subqueryscan(pathnode, root, rel, pathnode->path.param_info,
 					  trivial_pathtarget);
@@ -2385,7 +2394,7 @@ create_foreignscan_path(PlannerInfo *root, RelOptInfo *rel,
 	pathnode->path.total_cost = total_cost;
 	pathnode->path.pathkeys = pathkeys;
 
-	pathnode->fdw_outerpath = fdw_outerpath;
+	link_path(&pathnode->fdw_outerpath, fdw_outerpath);
 	pathnode->fdw_private = fdw_private;
 
 	return pathnode;
@@ -2435,7 +2444,7 @@ create_foreign_join_path(PlannerInfo *root, RelOptInfo *rel,
 	pathnode->path.total_cost = total_cost;
 	pathnode->path.pathkeys = pathkeys;
 
-	pathnode->fdw_outerpath = fdw_outerpath;
+	link_path(&pathnode->fdw_outerpath, fdw_outerpath);
 	pathnode->fdw_private = fdw_private;
 
 	return pathnode;
@@ -2480,7 +2489,7 @@ create_foreign_upper_path(PlannerInfo *root, RelOptInfo *rel,
 	pathnode->path.total_cost = total_cost;
 	pathnode->path.pathkeys = pathkeys;
 
-	pathnode->fdw_outerpath = fdw_outerpath;
+	link_path(&pathnode->fdw_outerpath, fdw_outerpath);
 	pathnode->fdw_private = fdw_private;
 
 	return pathnode;
@@ -2610,8 +2619,8 @@ create_nestloop_path(PlannerInfo *root,
 	pathnode->jpath.path.pathkeys = pathkeys;
 	pathnode->jpath.jointype = jointype;
 	pathnode->jpath.inner_unique = extra->inner_unique;
-	pathnode->jpath.outerjoinpath = outer_path;
-	pathnode->jpath.innerjoinpath = inner_path;
+	link_path(&(pathnode->jpath.outerjoinpath), outer_path);
+	link_path(&(pathnode->jpath.innerjoinpath), inner_path);
 	pathnode->jpath.joinrestrictinfo = restrict_clauses;
 
 	final_cost_nestloop(root, pathnode, workspace, extra);
@@ -2674,8 +2683,8 @@ create_mergejoin_path(PlannerInfo *root,
 	pathnode->jpath.path.pathkeys = pathkeys;
 	pathnode->jpath.jointype = jointype;
 	pathnode->jpath.inner_unique = extra->inner_unique;
-	pathnode->jpath.outerjoinpath = outer_path;
-	pathnode->jpath.innerjoinpath = inner_path;
+	link_path(&(pathnode->jpath.outerjoinpath), outer_path);
+	link_path(&(pathnode->jpath.innerjoinpath), inner_path);
 	pathnode->jpath.joinrestrictinfo = restrict_clauses;
 	pathnode->path_mergeclauses = mergeclauses;
 	pathnode->outersortkeys = outersortkeys;
@@ -2751,8 +2760,8 @@ create_hashjoin_path(PlannerInfo *root,
 	pathnode->jpath.path.pathkeys = NIL;
 	pathnode->jpath.jointype = jointype;
 	pathnode->jpath.inner_unique = extra->inner_unique;
-	pathnode->jpath.outerjoinpath = outer_path;
-	pathnode->jpath.innerjoinpath = inner_path;
+	link_path(&(pathnode->jpath.outerjoinpath), outer_path);
+	link_path(&(pathnode->jpath.innerjoinpath), inner_path);
 	pathnode->jpath.joinrestrictinfo = restrict_clauses;
 	pathnode->path_hashclauses = hashclauses;
 	/* final_cost_hashjoin will fill in pathnode->num_batches */
@@ -2793,6 +2802,9 @@ create_projection_path(PlannerInfo *root,
 		Assert(subpp->path.parent == rel);
 		subpath = subpp->subpath;
 		Assert(!IsA(subpath, ProjectionPath));
+
+		/* Free it if not used anywhere else. */
+		unlink_path((Path **) &subpp);
 	}
 
 	pathnode->path.pathtype = T_Result;
@@ -2808,7 +2820,7 @@ create_projection_path(PlannerInfo *root,
 	/* Projection does not change the sort order */
 	pathnode->path.pathkeys = subpath->pathkeys;
 
-	pathnode->subpath = subpath;
+	link_path(&pathnode->subpath, subpath);
 
 	/*
 	 * We might not need a separate Result node.  If the input plan node type
@@ -2927,21 +2939,21 @@ apply_projection_to_path(PlannerInfo *root,
 		{
 			GatherPath *gpath = (GatherPath *) path;
 
-			gpath->subpath = (Path *)
-				create_projection_path(root,
-									   gpath->subpath->parent,
-									   gpath->subpath,
-									   target);
+			link_path(&gpath->subpath, 
+						(Path *) create_projection_path(root,
+											   			gpath->subpath->parent,
+											   			gpath->subpath,
+											   			target));
 		}
 		else
 		{
 			GatherMergePath *gmpath = (GatherMergePath *) path;
 
-			gmpath->subpath = (Path *)
-				create_projection_path(root,
-									   gmpath->subpath->parent,
-									   gmpath->subpath,
-									   target);
+			link_path(&gmpath->subpath, 
+						(Path *) create_projection_path(root,
+															gmpath->subpath->parent,
+															gmpath->subpath,
+															target));
 		}
 	}
 	else if (path->parallel_safe &&
@@ -2990,7 +3002,7 @@ create_set_projection_path(PlannerInfo *root,
 	/* Projection does not change the sort order XXX? */
 	pathnode->path.pathkeys = subpath->pathkeys;
 
-	pathnode->subpath = subpath;
+	link_path(&pathnode->subpath, subpath);
 
 	/*
 	 * Estimate number of rows produced by SRFs for each row of input; if
@@ -3059,7 +3071,7 @@ create_incremental_sort_path(PlannerInfo *root,
 	pathnode->path.parallel_workers = subpath->parallel_workers;
 	pathnode->path.pathkeys = pathkeys;
 
-	pathnode->subpath = subpath;
+	link_path(&pathnode->subpath, subpath);
 
 	cost_incremental_sort(&pathnode->path,
 						  root, pathkeys, presorted_keys,
@@ -3106,7 +3118,7 @@ create_sort_path(PlannerInfo *root,
 	pathnode->path.parallel_workers = subpath->parallel_workers;
 	pathnode->path.pathkeys = pathkeys;
 
-	pathnode->subpath = subpath;
+	link_path(&pathnode->subpath, subpath);
 
 	cost_sort(&pathnode->path, root, pathkeys,
 			  subpath->total_cost,
@@ -3152,7 +3164,7 @@ create_group_path(PlannerInfo *root,
 	/* Group doesn't change sort ordering */
 	pathnode->path.pathkeys = subpath->pathkeys;
 
-	pathnode->subpath = subpath;
+	link_path(&pathnode->subpath, subpath);
 
 	pathnode->groupClause = groupClause;
 	pathnode->qual = qual;
@@ -3210,7 +3222,7 @@ create_upper_unique_path(PlannerInfo *root,
 	/* Unique doesn't change the input ordering */
 	pathnode->path.pathkeys = subpath->pathkeys;
 
-	pathnode->subpath = subpath;
+	link_path(&pathnode->subpath, subpath);
 	pathnode->numkeys = numCols;
 
 	/*
@@ -3267,7 +3279,7 @@ create_agg_path(PlannerInfo *root,
 		pathnode->path.pathkeys = subpath->pathkeys;	/* preserves order */
 	else
 		pathnode->path.pathkeys = NIL;	/* output is unordered */
-	pathnode->subpath = subpath;
+	link_path(&pathnode->subpath, subpath);
 
 	pathnode->aggstrategy = aggstrategy;
 	pathnode->aggsplit = aggsplit;
@@ -3330,7 +3342,7 @@ create_groupingsets_path(PlannerInfo *root,
 	pathnode->path.parallel_safe = rel->consider_parallel &&
 		subpath->parallel_safe;
 	pathnode->path.parallel_workers = subpath->parallel_workers;
-	pathnode->subpath = subpath;
+	link_path(&pathnode->subpath, subpath);
 
 	/*
 	 * Simplify callers by downgrading AGG_SORTED to AGG_PLAIN, and AGG_MIXED
@@ -3568,7 +3580,7 @@ create_windowagg_path(PlannerInfo *root,
 	/* WindowAgg preserves the input sort order */
 	pathnode->path.pathkeys = subpath->pathkeys;
 
-	pathnode->subpath = subpath;
+	link_path(&pathnode->subpath, subpath);
 	pathnode->winclause = winclause;
 	pathnode->qual = qual;
 	pathnode->topwindow = topwindow;
@@ -3638,7 +3650,7 @@ create_setop_path(PlannerInfo *root,
 	pathnode->path.pathkeys =
 		(strategy == SETOP_SORTED) ? subpath->pathkeys : NIL;
 
-	pathnode->subpath = subpath;
+	link_path(&pathnode->subpath, subpath);
 	pathnode->cmd = cmd;
 	pathnode->strategy = strategy;
 	pathnode->distinctList = distinctList;
@@ -3697,8 +3709,8 @@ create_recursiveunion_path(PlannerInfo *root,
 	/* RecursiveUnion result is always unsorted */
 	pathnode->path.pathkeys = NIL;
 
-	pathnode->leftpath = leftpath;
-	pathnode->rightpath = rightpath;
+	link_path(&pathnode->leftpath, leftpath);
+	link_path(&pathnode->rightpath, rightpath);
 	pathnode->distinctList = distinctList;
 	pathnode->wtParam = wtParam;
 	pathnode->numGroups = numGroups;
@@ -3740,7 +3752,7 @@ create_lockrows_path(PlannerInfo *root, RelOptInfo *rel,
 	 */
 	pathnode->path.pathkeys = NIL;
 
-	pathnode->subpath = subpath;
+	link_path(&pathnode->subpath, subpath);
 	pathnode->rowMarks = rowMarks;
 	pathnode->epqParam = epqParam;
 
@@ -3843,7 +3855,7 @@ create_modifytable_path(PlannerInfo *root, RelOptInfo *rel,
 		pathnode->path.pathtarget->width = 0;
 	}
 
-	pathnode->subpath = subpath;
+	link_path(&pathnode->subpath, subpath);
 	pathnode->operation = operation;
 	pathnode->canSetTag = canSetTag;
 	pathnode->nominalRelation = nominalRelation;
@@ -3901,7 +3913,7 @@ create_limit_path(PlannerInfo *root, RelOptInfo *rel,
 	pathnode->path.startup_cost = subpath->startup_cost;
 	pathnode->path.total_cost = subpath->total_cost;
 	pathnode->path.pathkeys = subpath->pathkeys;
-	pathnode->subpath = subpath;
+	link_path(&pathnode->subpath, subpath);
 	pathnode->limitOffset = limitOffset;
 	pathnode->limitCount = limitCount;
 	pathnode->limitOption = limitOption;
@@ -4182,6 +4194,7 @@ do { \
 	(path) = reparameterize_path_by_child(root, (path), child_rel); \
 	if ((path) == NULL) \
 		return NULL; \
+	link_path(&(path), (path)); \
 } while(0)
 
 #define REPARAMETERIZE_CHILD_PATH_LIST(pathlist) \
@@ -4469,11 +4482,14 @@ reparameterize_pathlist_by_child(PlannerInfo *root,
 
 		if (path == NULL)
 		{
+			/* TODO: unlink paths in the list */
 			list_free(result);
 			return NIL;
 		}
 
+		/* TODO: need a routine to link a path into a linked list */
 		result = lappend(result, path);
+		path->ref_count++;
 	}
 
 	return result;
-- 
2.25.1

