alternate-v8-0003-changes.nocf

application/octet-stream

Filename: alternate-v8-0003-changes.nocf
Type: application/octet-stream
Part: 0
Message: Re: pg_plan_advice
From 2007bfd7306d824b5c78cfe59ca281850d5becba Mon Sep 17 00:00:00 2001
From: Lukas Fittl <lukas@fittl.com>
Date: Sun, 11 Jan 2026 12:08:22 -0800
Subject: [PATCH] WIP: Rework child append relids to be passed via struct

---
 src/backend/optimizer/path/allpaths.c  | 187 +++++++++++--------------
 src/backend/optimizer/path/joinrels.c  |   5 +-
 src/backend/optimizer/plan/planner.c   |   8 +-
 src/backend/optimizer/prep/prepunion.c |  42 +++---
 src/backend/optimizer/util/pathnode.c  |  27 ++--
 src/include/optimizer/pathnode.h       |  10 +-
 src/tools/pgindent/typedefs.list       |   1 +
 7 files changed, 135 insertions(+), 145 deletions(-)

diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 6b9ad1c8aa7..9ff52685bbf 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -1390,7 +1390,6 @@ set_grouped_rel_pathlist(PlannerInfo *root, RelOptInfo *rel)
 	}
 }
 
-
 /*
  * add_paths_to_append_rel
  *		Generate paths for the given append relation given the set of non-dummy
@@ -1406,26 +1405,21 @@ void
 add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
 						List *live_childrels)
 {
-	List	   *subpaths = NIL;
-	bool		subpaths_valid = true;
-	List	   *subpath_cars = NIL;
-	List	   *startup_subpaths = NIL;
-	bool		startup_subpaths_valid = true;
-	List	   *startup_subpath_cars = NIL;
-	List	   *partial_subpaths = NIL;
-	List	   *partial_subpath_cars = NIL;
-	List	   *pa_partial_subpaths = NIL;
-	List	   *pa_nonpartial_subpaths = NIL;
-	List	   *pa_subpath_cars = NIL;
-	bool		partial_subpaths_valid = true;
-	bool		pa_subpaths_valid;
+	AppendPathInput unparameterized = {0};
+	AppendPathInput startup = {0};
+	AppendPathInput partial_only = {0};
+	AppendPathInput parallel_append = {0};
+	bool		unparameterized_valid = true;
+	bool		startup_valid = true;
+	bool		partial_only_valid = true;
+	bool		parallel_append_valid = true;
 	List	   *all_child_pathkeys = NIL;
 	List	   *all_child_outers = NIL;
 	ListCell   *l;
 	double		partial_rows = -1;
 
 	/* If appropriate, consider parallel append */
-	pa_subpaths_valid = enable_parallel_append && rel->consider_parallel;
+	parallel_append_valid = enable_parallel_append && rel->consider_parallel;
 
 	/*
 	 * For every non-dummy child, remember the cheapest path.  Also, identify
@@ -1449,9 +1443,9 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
 		if (childrel->pathlist != NIL &&
 			childrel->cheapest_total_path->param_info == NULL)
 			accumulate_append_subpath(childrel->cheapest_total_path,
-									  &subpaths, NULL, &subpath_cars);
+									  &unparameterized.subpaths, NULL, &unparameterized.child_append_relid_sets);
 		else
-			subpaths_valid = false;
+			unparameterized_valid = false;
 
 		/*
 		 * When the planner is considering cheap startup plans, we'll also
@@ -1477,12 +1471,12 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
 			/* cheapest_startup_path must not be a parameterized path. */
 			Assert(cheapest_path->param_info == NULL);
 			accumulate_append_subpath(cheapest_path,
-									  &startup_subpaths,
+									  &startup.subpaths,
 									  NULL,
-									  &startup_subpath_cars);
+									  &startup.child_append_relid_sets);
 		}
 		else
-			startup_subpaths_valid = false;
+			startup_valid = false;
 
 
 		/* Same idea, but for a partial plan. */
@@ -1490,17 +1484,17 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
 		{
 			cheapest_partial_path = linitial(childrel->partial_pathlist);
 			accumulate_append_subpath(cheapest_partial_path,
-									  &partial_subpaths, NULL,
-									  &partial_subpath_cars);
+									  &partial_only.partial_subpaths, NULL,
+									  &partial_only.child_append_relid_sets);
 		}
 		else
-			partial_subpaths_valid = false;
+			partial_only_valid = false;
 
 		/*
 		 * Same idea, but for a parallel append mixing partial and non-partial
 		 * paths.
 		 */
-		if (pa_subpaths_valid)
+		if (parallel_append_valid)
 		{
 			Path	   *nppath = NULL;
 
@@ -1510,7 +1504,7 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
 			if (cheapest_partial_path == NULL && nppath == NULL)
 			{
 				/* Neither a partial nor a parallel-safe path?  Forget it. */
-				pa_subpaths_valid = false;
+				parallel_append_valid = false;
 			}
 			else if (nppath == NULL ||
 					 (cheapest_partial_path != NULL &&
@@ -1519,9 +1513,9 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
 				/* Partial path is cheaper or the only option. */
 				Assert(cheapest_partial_path != NULL);
 				accumulate_append_subpath(cheapest_partial_path,
-										  &pa_partial_subpaths,
-										  &pa_nonpartial_subpaths,
-										  &pa_subpath_cars);
+										  &parallel_append.partial_subpaths,
+										  &parallel_append.subpaths,
+										  &parallel_append.child_append_relid_sets);
 			}
 			else
 			{
@@ -1539,9 +1533,9 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
 				 * figure that out.
 				 */
 				accumulate_append_subpath(nppath,
-										  &pa_nonpartial_subpaths,
+										  &parallel_append.subpaths,
 										  NULL,
-										  &pa_subpath_cars);
+										  &parallel_append.child_append_relid_sets);
 			}
 		}
 
@@ -1615,30 +1609,28 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
 	 * unparameterized Append path for the rel.  (Note: this is correct even
 	 * if we have zero or one live subpath due to constraint exclusion.)
 	 */
-	if (subpaths_valid)
-		add_path(rel, (Path *) create_append_path(root, rel, subpaths,
-												  NIL, subpath_cars,
+	if (unparameterized_valid)
+		add_path(rel, (Path *) create_append_path(root, rel, unparameterized,
 												  NIL, NULL, 0, false,
 												  -1));
 
 	/* build an AppendPath for the cheap startup paths, if valid */
-	if (startup_subpaths_valid)
-		add_path(rel, (Path *) create_append_path(root, rel, startup_subpaths,
-												  NIL, startup_subpath_cars,
+	if (startup_valid)
+		add_path(rel, (Path *) create_append_path(root, rel, startup,
 												  NIL, NULL, 0, false, -1));
 
 	/*
 	 * Consider an append of unordered, unparameterized partial paths.  Make
 	 * it parallel-aware if possible.
 	 */
-	if (partial_subpaths_valid && partial_subpaths != NIL)
+	if (partial_only_valid && partial_only.partial_subpaths != NIL)
 	{
 		AppendPath *appendpath;
 		ListCell   *lc;
 		int			parallel_workers = 0;
 
 		/* Find the highest number of workers requested for any subpath. */
-		foreach(lc, partial_subpaths)
+		foreach(lc, partial_only.partial_subpaths)
 		{
 			Path	   *path = lfirst(lc);
 
@@ -1665,8 +1657,7 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
 		Assert(parallel_workers > 0);
 
 		/* Generate a partial append path. */
-		appendpath = create_append_path(root, rel, NIL, partial_subpaths,
-										partial_subpath_cars,
+		appendpath = create_append_path(root, rel, partial_only,
 										NIL, NULL, parallel_workers,
 										enable_parallel_append,
 										-1);
@@ -1687,7 +1678,7 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
 	 * a non-partial path that is substantially cheaper than any partial path;
 	 * otherwise, we should use the append path added in the previous step.)
 	 */
-	if (pa_subpaths_valid && pa_nonpartial_subpaths != NIL)
+	if (parallel_append_valid && parallel_append.subpaths != NIL)
 	{
 		AppendPath *appendpath;
 		ListCell   *lc;
@@ -1697,7 +1688,7 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
 		 * Find the highest number of workers requested for any partial
 		 * subpath.
 		 */
-		foreach(lc, pa_partial_subpaths)
+		foreach(lc, parallel_append.partial_subpaths)
 		{
 			Path	   *path = lfirst(lc);
 
@@ -1715,9 +1706,7 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
 							   max_parallel_workers_per_gather);
 		Assert(parallel_workers > 0);
 
-		appendpath = create_append_path(root, rel, pa_nonpartial_subpaths,
-										pa_partial_subpaths,
-										pa_subpath_cars,
+		appendpath = create_append_path(root, rel, parallel_append,
 										NIL, NULL, parallel_workers, true,
 										partial_rows);
 		add_partial_path(rel, (Path *) appendpath);
@@ -1727,7 +1716,7 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
 	 * Also build unparameterized ordered append paths based on the collected
 	 * list of child pathkeys.
 	 */
-	if (subpaths_valid)
+	if (unparameterized_valid)
 		generate_orderedappend_paths(root, rel, live_childrels,
 									 all_child_pathkeys);
 
@@ -1748,11 +1737,10 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
 	{
 		Relids		required_outer = (Relids) lfirst(l);
 		ListCell   *lcr;
+		AppendPathInput parameterized = {0};
+		bool		parameterized_valid = true;
 
 		/* Select the child paths for an Append with this parameterization */
-		subpaths = NIL;
-		subpath_cars = NIL;
-		subpaths_valid = true;
 		foreach(lcr, live_childrels)
 		{
 			RelOptInfo *childrel = (RelOptInfo *) lfirst(lcr);
@@ -1761,7 +1749,7 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
 			if (childrel->pathlist == NIL)
 			{
 				/* failed to make a suitable path for this child */
-				subpaths_valid = false;
+				parameterized_valid = false;
 				break;
 			}
 
@@ -1771,16 +1759,16 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
 			if (subpath == NULL)
 			{
 				/* failed to make a suitable path for this child */
-				subpaths_valid = false;
+				parameterized_valid = false;
 				break;
 			}
-			accumulate_append_subpath(subpath, &subpaths, NULL,
-									  &subpath_cars);
+			accumulate_append_subpath(subpath, &parameterized.subpaths, NULL,
+									  &parameterized.child_append_relid_sets);
 		}
 
-		if (subpaths_valid)
+		if (parameterized_valid)
 			add_path(rel, (Path *)
-					 create_append_path(root, rel, subpaths, NIL, subpath_cars,
+					 create_append_path(root, rel, parameterized,
 										NIL, required_outer, 0, false,
 										-1));
 	}
@@ -1801,14 +1789,16 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
 		{
 			Path	   *path = (Path *) lfirst(l);
 			AppendPath *appendpath;
+			AppendPathInput append = {0};
+
+			append.partial_subpaths = list_make1(path);
+			append.child_append_relid_sets = list_make1(rel->relids);
 
 			/* skip paths with no pathkeys. */
 			if (path->pathkeys == NIL)
 				continue;
 
-			appendpath = create_append_path(root, rel, NIL, list_make1(path),
-											list_make1(rel->relids),
-											NIL, NULL,
+			appendpath = create_append_path(root, rel, append, NIL, NULL,
 											path->parallel_workers, true,
 											partial_rows);
 			add_partial_path(rel, (Path *) appendpath);
@@ -1890,12 +1880,9 @@ generate_orderedappend_paths(PlannerInfo *root, RelOptInfo *rel,
 	foreach(lcp, all_child_pathkeys)
 	{
 		List	   *pathkeys = (List *) lfirst(lcp);
-		List	   *startup_subpaths = NIL;
-		List	   *startup_subpath_cars = NIL;
-		List	   *total_subpaths = NIL;
-		List	   *total_subpath_cars = NIL;
-		List	   *fractional_subpaths = NIL;
-		List	   *fractional_subpath_cars = NIL;
+		AppendPathInput startup = {0};
+		AppendPathInput total = {0};
+		AppendPathInput fractional = {0};
 		bool		startup_neq_total = false;
 		bool		fraction_neq_total = false;
 		bool		match_partition_order;
@@ -2060,21 +2047,21 @@ generate_orderedappend_paths(PlannerInfo *root, RelOptInfo *rel,
 				 */
 				cheapest_startup =
 					get_singleton_append_subpath(cheapest_startup,
-												 &startup_subpath_cars);
+												 &startup.child_append_relid_sets);
 				cheapest_total =
 					get_singleton_append_subpath(cheapest_total,
-												 &total_subpath_cars);
+												 &total.child_append_relid_sets);
 
-				startup_subpaths = lappend(startup_subpaths, cheapest_startup);
-				total_subpaths = lappend(total_subpaths, cheapest_total);
+				startup.subpaths = lappend(startup.subpaths, cheapest_startup);
+				total.subpaths = lappend(total.subpaths, cheapest_total);
 
 				if (cheapest_fractional)
 				{
 					cheapest_fractional =
 						get_singleton_append_subpath(cheapest_fractional,
-													 &fractional_subpath_cars);
-					fractional_subpaths =
-						lappend(fractional_subpaths, cheapest_fractional);
+													 &fractional.child_append_relid_sets);
+					fractional.subpaths =
+						lappend(fractional.subpaths, cheapest_fractional);
 				}
 			}
 			else
@@ -2084,16 +2071,16 @@ generate_orderedappend_paths(PlannerInfo *root, RelOptInfo *rel,
 				 * child paths for the MergeAppend.
 				 */
 				accumulate_append_subpath(cheapest_startup,
-										  &startup_subpaths, NULL,
-										  &startup_subpath_cars);
+										  &startup.subpaths, NULL,
+										  &startup.child_append_relid_sets);
 				accumulate_append_subpath(cheapest_total,
-										  &total_subpaths, NULL,
-										  &total_subpath_cars);
+										  &total.subpaths, NULL,
+										  &total.child_append_relid_sets);
 
 				if (cheapest_fractional)
 					accumulate_append_subpath(cheapest_fractional,
-											  &fractional_subpaths, NULL,
-											  &fractional_subpath_cars);
+											  &fractional.subpaths, NULL,
+											  &fractional.child_append_relid_sets);
 			}
 		}
 
@@ -2103,9 +2090,7 @@ generate_orderedappend_paths(PlannerInfo *root, RelOptInfo *rel,
 			/* We only need Append */
 			add_path(rel, (Path *) create_append_path(root,
 													  rel,
-													  startup_subpaths,
-													  NIL,
-													  startup_subpath_cars,
+													  startup,
 													  pathkeys,
 													  NULL,
 													  0,
@@ -2114,49 +2099,45 @@ generate_orderedappend_paths(PlannerInfo *root, RelOptInfo *rel,
 			if (startup_neq_total)
 				add_path(rel, (Path *) create_append_path(root,
 														  rel,
-														  total_subpaths,
-														  NIL,
-														  total_subpath_cars,
+														  total,
 														  pathkeys,
 														  NULL,
 														  0,
 														  false,
 														  -1));
 
-			if (fractional_subpaths && fraction_neq_total)
-				add_path(rel, (Path *) create_append_path(root,
-														  rel,
-														  fractional_subpaths,
-														  NIL,
-														  fractional_subpath_cars,
-														  pathkeys,
-														  NULL,
-														  0,
-														  false,
-														  -1));
+			if (fractional.subpaths && fraction_neq_total)
+				add_path(rel, (Path *) (root,
+										rel,
+										fractional,
+										pathkeys,
+										NULL,
+										0,
+										false,
+										-1));
 		}
 		else
 		{
 			/* We need MergeAppend */
 			add_path(rel, (Path *) create_merge_append_path(root,
 															rel,
-															startup_subpaths,
-															startup_subpath_cars,
+															startup.subpaths,
+															startup.child_append_relid_sets,
 															pathkeys,
 															NULL));
 			if (startup_neq_total)
 				add_path(rel, (Path *) create_merge_append_path(root,
 																rel,
-																total_subpaths,
-																total_subpath_cars,
+																total.subpaths,
+																total.child_append_relid_sets,
 																pathkeys,
 																NULL));
 
-			if (fractional_subpaths && fraction_neq_total)
+			if (fractional.subpaths && fraction_neq_total)
 				add_path(rel, (Path *) create_merge_append_path(root,
 																rel,
-																fractional_subpaths,
-																fractional_subpath_cars,
+																fractional.subpaths,
+																fractional.child_append_relid_sets,
 																pathkeys,
 																NULL));
 		}
@@ -2360,6 +2341,8 @@ get_singleton_append_subpath(Path *path, List **child_append_relid_sets)
 static void
 set_dummy_rel_pathlist(RelOptInfo *rel)
 {
+	AppendPathInput in = {0};
+
 	/* Set dummy size estimates --- we leave attr_widths[] as zeroes */
 	rel->rows = 0;
 	rel->reltarget->width = 0;
@@ -2369,7 +2352,7 @@ set_dummy_rel_pathlist(RelOptInfo *rel)
 	rel->partial_pathlist = NIL;
 
 	/* Set up the dummy path */
-	add_path(rel, (Path *) create_append_path(NULL, rel, NIL, NIL, NIL,
+	add_path(rel, (Path *) create_append_path(NULL, rel, in,
 											  NIL, rel->lateral_relids,
 											  0, false, -1));
 
diff --git a/src/backend/optimizer/path/joinrels.c b/src/backend/optimizer/path/joinrels.c
index e94021b6880..443e2dca7c0 100644
--- a/src/backend/optimizer/path/joinrels.c
+++ b/src/backend/optimizer/path/joinrels.c
@@ -1513,6 +1513,7 @@ void
 mark_dummy_rel(RelOptInfo *rel)
 {
 	MemoryContext oldcontext;
+	AppendPathInput in = {0};
 
 	/* Already marked? */
 	if (is_dummy_rel(rel))
@@ -1529,8 +1530,8 @@ mark_dummy_rel(RelOptInfo *rel)
 	rel->partial_pathlist = NIL;
 
 	/* Set up the dummy path */
-	add_path(rel, (Path *) create_append_path(NULL, rel, NIL, NIL,
-											  NIL, NIL, rel->lateral_relids,
+	add_path(rel, (Path *) create_append_path(NULL, rel, in,
+											  NIL, rel->lateral_relids,
 											  0, false, -1));
 
 	/* Set or update cheapest_total_path and related fields */
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index d905b64b9ca..d4bf8a955d1 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -4062,7 +4062,7 @@ create_degenerate_grouping_paths(PlannerInfo *root, RelOptInfo *input_rel,
 		 * might get between 0 and N output rows. Offhand I think that's
 		 * desired.)
 		 */
-		List	   *paths = NIL;
+		AppendPathInput append = {0};
 
 		while (--nrows >= 0)
 		{
@@ -4070,14 +4070,12 @@ create_degenerate_grouping_paths(PlannerInfo *root, RelOptInfo *input_rel,
 				create_group_result_path(root, grouped_rel,
 										 grouped_rel->reltarget,
 										 (List *) parse->havingQual);
-			paths = lappend(paths, path);
+			append.subpaths = lappend(append.subpaths, path);
 		}
 		path = (Path *)
 			create_append_path(root,
 							   grouped_rel,
-							   paths,
-							   NIL,
-							   NIL,
+							   append,
 							   NIL,
 							   NULL,
 							   0,
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index 6e76783126b..f50c296e3d9 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -696,9 +696,9 @@ generate_union_paths(SetOperationStmt *op, PlannerInfo *root,
 	ListCell   *lc;
 	ListCell   *lc2;
 	ListCell   *lc3;
-	List	   *cheapest_pathlist = NIL;
-	List	   *ordered_pathlist = NIL;
-	List	   *partial_pathlist = NIL;
+	AppendPathInput cheapest = {0};
+	AppendPathInput ordered = {0};
+	AppendPathInput partial = {0};
 	bool		partial_paths_valid = true;
 	bool		consider_parallel = true;
 	List	   *rellist;
@@ -783,7 +783,7 @@ generate_union_paths(SetOperationStmt *op, PlannerInfo *root,
 		if (is_dummy_rel(rel))
 			continue;
 
-		cheapest_pathlist = lappend(cheapest_pathlist,
+		cheapest.subpaths = lappend(cheapest.subpaths,
 									rel->cheapest_total_path);
 
 		if (try_sorted)
@@ -795,7 +795,7 @@ generate_union_paths(SetOperationStmt *op, PlannerInfo *root,
 														  false);
 
 			if (ordered_path != NULL)
-				ordered_pathlist = lappend(ordered_pathlist, ordered_path);
+				ordered.subpaths = lappend(ordered.subpaths, ordered_path);
 			else
 			{
 				/*
@@ -818,20 +818,20 @@ generate_union_paths(SetOperationStmt *op, PlannerInfo *root,
 			else if (rel->partial_pathlist == NIL)
 				partial_paths_valid = false;
 			else
-				partial_pathlist = lappend(partial_pathlist,
-										   linitial(rel->partial_pathlist));
+				partial.partial_subpaths = lappend(partial.partial_subpaths,
+												   linitial(rel->partial_pathlist));
 		}
 	}
 
 	/* Build result relation. */
 	result_rel = fetch_upper_rel(root, UPPERREL_SETOP, relids);
 	result_rel->reltarget = create_setop_pathtarget(root, tlist,
-													cheapest_pathlist);
+													cheapest.subpaths);
 	result_rel->consider_parallel = consider_parallel;
 	result_rel->consider_startup = (root->tuple_fraction > 0);
 
 	/* If all UNION children were dummy rels, make the resulting rel dummy */
-	if (cheapest_pathlist == NIL)
+	if (cheapest.subpaths == NIL)
 	{
 		mark_dummy_rel(result_rel);
 
@@ -842,8 +842,8 @@ generate_union_paths(SetOperationStmt *op, PlannerInfo *root,
 	 * Append the child results together using the cheapest paths from each
 	 * union child.
 	 */
-	apath = (Path *) create_append_path(root, result_rel, cheapest_pathlist,
-										NIL, NIL, NIL, NULL, 0, false, -1);
+	apath = (Path *) create_append_path(root, result_rel, cheapest,
+										NIL, NULL, 0, false, -1);
 
 	/*
 	 * Estimate number of groups.  For now we just assume the output is unique
@@ -862,7 +862,7 @@ generate_union_paths(SetOperationStmt *op, PlannerInfo *root,
 		int			parallel_workers = 0;
 
 		/* Find the highest number of workers requested for any subpath. */
-		foreach(lc, partial_pathlist)
+		foreach(lc, partial.partial_subpaths)
 		{
 			Path	   *subpath = lfirst(lc);
 
@@ -881,15 +881,15 @@ generate_union_paths(SetOperationStmt *op, PlannerInfo *root,
 		if (enable_parallel_append)
 		{
 			parallel_workers = Max(parallel_workers,
-								   pg_leftmost_one_pos32(list_length(partial_pathlist)) + 1);
+								   pg_leftmost_one_pos32(list_length(partial.partial_subpaths)) + 1);
 			parallel_workers = Min(parallel_workers,
 								   max_parallel_workers_per_gather);
 		}
 		Assert(parallel_workers > 0);
 
 		papath = (Path *)
-			create_append_path(root, result_rel, NIL, partial_pathlist,
-							   NIL, NIL, NULL, parallel_workers,
+			create_append_path(root, result_rel, partial,
+							   NIL, NULL, parallel_workers,
 							   enable_parallel_append, -1);
 		gpath = (Path *)
 			create_gather_path(root, result_rel, papath,
@@ -901,7 +901,7 @@ generate_union_paths(SetOperationStmt *op, PlannerInfo *root,
 		double		dNumGroups;
 		bool		can_sort = grouping_is_sortable(groupList);
 		bool		can_hash = grouping_is_hashable(groupList);
-		Path	   *first_path = linitial(cheapest_pathlist);
+		Path	   *first_path = linitial(cheapest.subpaths);
 
 		/*
 		 * Estimate the number of UNION output rows.  In the case when only a
@@ -911,7 +911,7 @@ generate_union_paths(SetOperationStmt *op, PlannerInfo *root,
 		 * contain Vars with varno==0, which estimate_num_groups() wouldn't
 		 * like.
 		 */
-		if (list_length(cheapest_pathlist) == 1 &&
+		if (list_length(cheapest.subpaths) == 1 &&
 			first_path->parent->reloptkind != RELOPT_UPPER_REL)
 		{
 			dNumGroups = estimate_num_groups(root,
@@ -1017,7 +1017,7 @@ generate_union_paths(SetOperationStmt *op, PlannerInfo *root,
 
 			path = (Path *) create_merge_append_path(root,
 													 result_rel,
-													 ordered_pathlist,
+													 ordered.subpaths,
 													 NIL,
 													 union_pathkeys,
 													 NULL);
@@ -1217,6 +1217,9 @@ generate_nonunion_paths(SetOperationStmt *op, PlannerInfo *root,
 			if (op->all)
 			{
 				Path	   *apath;
+				AppendPathInput append = {0};
+
+				append.subpaths = list_make1(lpath);
 
 				/*
 				 * EXCEPT ALL: If the right-hand input is dummy then we can
@@ -1226,8 +1229,7 @@ generate_nonunion_paths(SetOperationStmt *op, PlannerInfo *root,
 				 * left input.  The Append will be removed in setrefs.c.
 				 */
 				apath = (Path *) create_append_path(root, result_rel,
-													list_make1(lpath),
-													NIL, NIL, NIL, NULL, 0,
+													append, NIL, NULL, 0,
 													false, -1);
 
 				add_path(result_rel, apath);
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index 310175b6b21..dca5459aeab 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -1300,8 +1300,7 @@ create_tidrangescan_path(PlannerInfo *root, RelOptInfo *rel,
 AppendPath *
 create_append_path(PlannerInfo *root,
 				   RelOptInfo *rel,
-				   List *subpaths, List *partial_subpaths,
-				   List *child_append_relid_sets,
+				   AppendPathInput input,
 				   List *pathkeys, Relids required_outer,
 				   int parallel_workers, bool parallel_aware,
 				   double rows)
@@ -1311,7 +1310,7 @@ create_append_path(PlannerInfo *root,
 
 	Assert(!parallel_aware || parallel_workers > 0);
 
-	pathnode->child_append_relid_sets = child_append_relid_sets;
+	pathnode->child_append_relid_sets = input.child_append_relid_sets;
 	pathnode->path.pathtype = T_Append;
 	pathnode->path.parent = rel;
 	pathnode->path.pathtarget = rel->reltarget;
@@ -1327,7 +1326,7 @@ create_append_path(PlannerInfo *root,
 	 * on the simpler get_appendrel_parampathinfo.  There's no point in doing
 	 * the more expensive thing for a dummy path, either.
 	 */
-	if (rel->reloptkind == RELOPT_BASEREL && root && subpaths != NIL)
+	if (rel->reloptkind == RELOPT_BASEREL && root && input.subpaths != NIL)
 		pathnode->path.param_info = get_baserel_parampathinfo(root,
 															  rel,
 															  required_outer);
@@ -1358,11 +1357,11 @@ create_append_path(PlannerInfo *root,
 		 */
 		Assert(pathkeys == NIL);
 
-		list_sort(subpaths, append_total_cost_compare);
-		list_sort(partial_subpaths, append_startup_cost_compare);
+		list_sort(input.subpaths, append_total_cost_compare);
+		list_sort(input.partial_subpaths, append_startup_cost_compare);
 	}
-	pathnode->first_partial_path = list_length(subpaths);
-	pathnode->subpaths = list_concat(subpaths, partial_subpaths);
+	pathnode->first_partial_path = list_length(input.subpaths);
+	pathnode->subpaths = list_concat(input.subpaths, input.partial_subpaths);
 
 	/*
 	 * Apply query-wide LIMIT if known and path is for sole base relation.
@@ -3938,11 +3937,12 @@ reparameterize_path(PlannerInfo *root, Path *path,
 		case T_Append:
 			{
 				AppendPath *apath = (AppendPath *) path;
-				List	   *childpaths = NIL;
-				List	   *partialpaths = NIL;
+				AppendPathInput new_append = {0};
 				int			i;
 				ListCell   *lc;
 
+				new_append.child_append_relid_sets = apath->child_append_relid_sets;
+
 				/* Reparameterize the children */
 				i = 0;
 				foreach(lc, apath->subpaths)
@@ -3956,14 +3956,13 @@ reparameterize_path(PlannerInfo *root, Path *path,
 						return NULL;
 					/* We have to re-split the regular and partial paths */
 					if (i < apath->first_partial_path)
-						childpaths = lappend(childpaths, spath);
+						new_append.subpaths = lappend(new_append.subpaths, spath);
 					else
-						partialpaths = lappend(partialpaths, spath);
+						new_append.partial_subpaths = lappend(new_append.partial_subpaths, spath);
 					i++;
 				}
 				return (Path *)
-					create_append_path(root, rel, childpaths, partialpaths,
-									   apath->child_append_relid_sets,
+					create_append_path(root, rel, new_append,
 									   apath->path.pathkeys, required_outer,
 									   apath->path.parallel_workers,
 									   apath->path.parallel_aware,
diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h
index dc8cab2b7e6..8dca0cc67e8 100644
--- a/src/include/optimizer/pathnode.h
+++ b/src/include/optimizer/pathnode.h
@@ -77,9 +77,15 @@ extern TidRangePath *create_tidrangescan_path(PlannerInfo *root,
 											  List *tidrangequals,
 											  Relids required_outer,
 											  int parallel_workers);
+
+typedef struct AppendPathInput
+{
+	List	   *subpaths;
+	List	   *partial_subpaths;
+	List	   *child_append_relid_sets;
+} AppendPathInput;
 extern AppendPath *create_append_path(PlannerInfo *root, RelOptInfo *rel,
-									  List *subpaths, List *partial_subpaths,
-									  List *child_append_relid_sets,
+									  AppendPathInput input,
 									  List *pathkeys, Relids required_outer,
 									  int parallel_workers, bool parallel_aware,
 									  double rows);
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 2c4f350bebe..38382b4c91d 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -125,6 +125,7 @@ AnlIndexData
 AnyArrayType
 Append
 AppendPath
+AppendPathInput
 AppendRelInfo
 AppendState
 ApplyErrorCallbackArg
-- 
2.47.1