v3-0001-delta.patch

text/plain

Filename: v3-0001-delta.patch
Type: text/plain
Part: 0
Message: Re: Internal error XX000 with enable_partition_pruning=on, pg 11 beta1 on Debian

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: unified
Series: patch v3-0001
File+
src/backend/executor/execPartition.c 151 177
src/backend/optimizer/plan/createplan.c 17 7
src/backend/partitioning/partprune.c 42 33
src/include/executor/execPartition.h 1 12
src/include/partitioning/partprune.h 1 0
diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c
index dac789d414..f81ff672ca 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -48,7 +48,7 @@ static char *ExecBuildSlotPartitionKeyDescription(Relation rel,
 									 bool *isnull,
 									 int maxfieldlen);
 static List *adjust_partition_tlist(List *tlist, TupleConversionMap *map);
-static void find_matching_subplans_recurse(PartitionPruningData *pprune,
+static void find_matching_subplans_recurse(PartitionPruneState *prunestate,
 							   PartitionedRelPruningData *prelprune,
 							   bool initial_prune,
 							   Bitmapset **validsubplans);
@@ -1396,14 +1396,10 @@ adjust_partition_tlist(List *tlist, TupleConversionMap *map)
  *
  * 'partitionpruneinfo' is a PartitionPruneInfo as generated by
  * make_partition_pruneinfo.  Here we build a PartitionPruneState containing a
- * PartitionPruningData for each partitionpruneinfo->prune_infos, in
- * turn, a PartitionedRelPruningData is created for each
- * PartitionedRelPruneInfo stored in each 'prune_infos'.  This two-level system
- * is required in order to support run-time pruning with UNION ALL parents
- * containing one or more partitioned tables as children.  The data stored in
- * each PartitionedRelPruningData can be re-used each time we re-evaluate
- * which partitions match the pruning steps provided in each
- * PartitionedRelPruneInfo.
+ * PartitionedRelPruningData for each PartitionedRelPruneInfo
+ * in partitionpruneinfo->prune_infos.  The data stored in each
+ * PartitionedRelPruningData can be re-used each time we re-evaluate which
+ * partitions match the pruning steps provided in each PartitionedRelPruneInfo.
  */
 PartitionPruneState *
 ExecCreatePartitionPruneState(PlanState *planstate,
@@ -1422,8 +1418,8 @@ ExecCreatePartitionPruneState(PlanState *planstate,
 	 * Allocate the data structure
 	 */
 	prunestate = (PartitionPruneState *)
-		palloc(offsetof(PartitionPruneState, partprunedata) +
-			   sizeof(PartitionPruningData *) * n_part_hierarchies);
+		palloc(offsetof(PartitionPruneState, partrelprunedata) +
+			   sizeof(PartitionedRelPruningData) * n_part_hierarchies);
 
 	prunestate->num_partprunedata = n_part_hierarchies;
 	prunestate->do_initial_prune = false;	/* may be set below */
@@ -1445,125 +1441,109 @@ ExecCreatePartitionPruneState(PlanState *planstate,
 	i = 0;
 	foreach(lc, partitionpruneinfo->prune_infos)
 	{
-		ListCell   *lc2;
-		List	   *partrelpruneinfos = lfirst_node(List, lc);
-		PartitionPruningData *prunedata;
-		int			npartrelpruneinfos = list_length(partrelpruneinfos);
-		int			j;
+		PartitionedRelPruneInfo *pinfo = castNode(PartitionedRelPruneInfo, lfirst(lc));
+		PartitionedRelPruningData *prelprune = &prunestate->partrelprunedata[i];
+		PartitionPruneContext *context = &prelprune->context;
+		PartitionDesc partdesc;
+		PartitionKey partkey;
+		int			partnatts;
+		int			n_steps;
+		ListCell   *lc3;
 
-		prunedata = palloc(offsetof(PartitionPruningData, partrelprunedata) +
-						   npartrelpruneinfos * sizeof(PartitionedRelPruningData));
-		prunestate->partprunedata[i] = prunedata;
-		prunedata->num_partrelprunedata = npartrelpruneinfos;
+		/*
+		 * We must copy the subplan_map rather than pointing directly to
+		 * the plan's version, as we may end up making modifications to it
+		 * later.
+		 */
+		prelprune->subplan_map = palloc(sizeof(int) * pinfo->nparts);
+		memcpy(prelprune->subplan_map, pinfo->subplan_map,
+			   sizeof(int) * pinfo->nparts);
 
-		j = 0;
-		foreach(lc2, partrelpruneinfos)
+		/* We can use the subpart_map verbatim, since we never modify it */
+		prelprune->subpart_map = pinfo->subpart_map;
+
+		/* present_parts is also subject to later modification */
+		prelprune->present_parts = bms_copy(pinfo->present_parts);
+
+		/*
+		 * We need to hold a pin on the partitioned table's relcache entry
+		 * so that we can rely on its copies of the table's partition key
+		 * and partition descriptor.  We need not get a lock though; one
+		 * should have been acquired already by InitPlan or
+		 * ExecLockNonLeafAppendTables.
+		 */
+		context->partrel = relation_open(pinfo->reloid, NoLock);
+
+		partkey = RelationGetPartitionKey(context->partrel);
+		partdesc = RelationGetPartitionDesc(context->partrel);
+		n_steps = list_length(pinfo->pruning_steps);
+
+		context->strategy = partkey->strategy;
+		context->partnatts = partnatts = partkey->partnatts;
+		context->nparts = pinfo->nparts;
+		context->boundinfo = partdesc->boundinfo;
+		context->partcollation = partkey->partcollation;
+		context->partsupfunc = partkey->partsupfunc;
+
+		/* We'll look up type-specific support functions as needed */
+		context->stepcmpfuncs = (FmgrInfo *)
+			palloc0(sizeof(FmgrInfo) * n_steps * partnatts);
+
+		context->ppccontext = CurrentMemoryContext;
+		context->planstate = planstate;
+
+		/* Initialize expression state for each expression we need */
+		context->exprstates = (ExprState **)
+			palloc0(sizeof(ExprState *) * n_steps * partnatts);
+		foreach(lc3, pinfo->pruning_steps)
 		{
-			PartitionedRelPruneInfo *pinfo = castNode(PartitionedRelPruneInfo, lfirst(lc2));
-			PartitionedRelPruningData *prelprune = &prunedata->partrelprunedata[j];
-			PartitionPruneContext *context = &prelprune->context;
-			PartitionDesc partdesc;
-			PartitionKey partkey;
-			int			partnatts;
-			int			n_steps;
-			ListCell   *lc3;
+			PartitionPruneStepOp *step = (PartitionPruneStepOp *) lfirst(lc3);
+			ListCell   *lc4;
+			int			keyno;
 
-			/*
-			 * We must copy the subplan_map rather than pointing directly to
-			 * the plan's version, as we may end up making modifications to it
-			 * later.
-			 */
-			prelprune->subplan_map = palloc(sizeof(int) * pinfo->nparts);
-			memcpy(prelprune->subplan_map, pinfo->subplan_map,
-				   sizeof(int) * pinfo->nparts);
+			/* not needed for other step kinds */
+			if (!IsA(step, PartitionPruneStepOp))
+				continue;
 
-			/* We can use the subpart_map verbatim, since we never modify it */
-			prelprune->subpart_map = pinfo->subpart_map;
+			Assert(list_length(step->exprs) <= partnatts);
 
-			/* present_parts is also subject to later modification */
-			prelprune->present_parts = bms_copy(pinfo->present_parts);
-
-			/*
-			 * We need to hold a pin on the partitioned table's relcache entry
-			 * so that we can rely on its copies of the table's partition key
-			 * and partition descriptor.  We need not get a lock though; one
-			 * should have been acquired already by InitPlan or
-			 * ExecLockNonLeafAppendTables.
-			 */
-			context->partrel = relation_open(pinfo->reloid, NoLock);
-
-			partkey = RelationGetPartitionKey(context->partrel);
-			partdesc = RelationGetPartitionDesc(context->partrel);
-			n_steps = list_length(pinfo->pruning_steps);
-
-			context->strategy = partkey->strategy;
-			context->partnatts = partnatts = partkey->partnatts;
-			context->nparts = pinfo->nparts;
-			context->boundinfo = partdesc->boundinfo;
-			context->partcollation = partkey->partcollation;
-			context->partsupfunc = partkey->partsupfunc;
-
-			/* We'll look up type-specific support functions as needed */
-			context->stepcmpfuncs = (FmgrInfo *)
-				palloc0(sizeof(FmgrInfo) * n_steps * partnatts);
-
-			context->ppccontext = CurrentMemoryContext;
-			context->planstate = planstate;
-
-			/* Initialize expression state for each expression we need */
-			context->exprstates = (ExprState **)
-				palloc0(sizeof(ExprState *) * n_steps * partnatts);
-			foreach(lc3, pinfo->pruning_steps)
+			keyno = 0;
+			foreach(lc4, step->exprs)
 			{
-				PartitionPruneStepOp *step = (PartitionPruneStepOp *) lfirst(lc3);
-				ListCell   *lc4;
-				int			keyno;
+				Expr	   *expr = (Expr *) lfirst(lc4);
 
-				/* not needed for other step kinds */
-				if (!IsA(step, PartitionPruneStepOp))
-					continue;
-
-				Assert(list_length(step->exprs) <= partnatts);
-
-				keyno = 0;
-				foreach(lc4, step->exprs)
+				/* not needed for Consts */
+				if (!IsA(expr, Const))
 				{
-					Expr	   *expr = (Expr *) lfirst(lc4);
+					int			stateidx = PruneCxtStateIdx(partnatts,
+															step->step.step_id,
+															keyno);
 
-					/* not needed for Consts */
-					if (!IsA(expr, Const))
-					{
-						int			stateidx = PruneCxtStateIdx(partnatts,
-																step->step.step_id,
-																keyno);
-
-						context->exprstates[stateidx] =
-							ExecInitExpr(expr, context->planstate);
-					}
-					keyno++;
+					context->exprstates[stateidx] =
+						ExecInitExpr(expr, context->planstate);
 				}
+				keyno++;
 			}
-
-			/* Array is not modified at runtime, so just point to plan's copy */
-			context->exprhasexecparam = pinfo->hasexecparam;
-
-			prelprune->pruning_steps = pinfo->pruning_steps;
-			prelprune->do_initial_prune = pinfo->do_initial_prune;
-			prelprune->do_exec_prune = pinfo->do_exec_prune;
-
-			/* Record if pruning would be useful at any level */
-			prunestate->do_initial_prune |= pinfo->do_initial_prune;
-			prunestate->do_exec_prune |= pinfo->do_exec_prune;
-
-			/*
-			 * Accumulate the IDs of all PARAM_EXEC Params affecting the
-			 * partitioning decisions at this plan node.
-			 */
-			prunestate->execparamids = bms_add_members(prunestate->execparamids,
-													   pinfo->execparamids);
-
-			j++;
 		}
+
+		/* Array is not modified at runtime, so just point to plan's copy */
+		context->exprhasexecparam = pinfo->hasexecparam;
+
+		prelprune->pruning_steps = pinfo->pruning_steps;
+		prelprune->do_initial_prune = pinfo->do_initial_prune;
+		prelprune->do_exec_prune = pinfo->do_exec_prune;
+
+		/* Record if pruning would be useful at any level */
+		prunestate->do_initial_prune |= pinfo->do_initial_prune;
+		prunestate->do_exec_prune |= pinfo->do_exec_prune;
+
+		/*
+		 * Accumulate the IDs of all PARAM_EXEC Params affecting the
+		 * partitioning decisions at this plan node.
+		 */
+		prunestate->execparamids = bms_add_members(prunestate->execparamids,
+												   pinfo->execparamids);
+
 		i++;
 	}
 	return prunestate;
@@ -1579,17 +1559,14 @@ ExecCreatePartitionPruneState(PlanState *planstate,
 void
 ExecDestroyPartitionPruneState(PartitionPruneState *prunestate)
 {
-	PartitionPruningData **partprunedata = prunestate->partprunedata;
+	PartitionedRelPruningData *partrelprunedata = prunestate->partrelprunedata;
 	int			i;
 
 	for (i = 0; i < prunestate->num_partprunedata; i++)
 	{
-		PartitionPruningData *pprune = partprunedata[i];
-		PartitionedRelPruningData *prunedata = pprune->partrelprunedata;
-		int			j;
+		PartitionedRelPruningData prunedata = partrelprunedata[i];
 
-		for (j = 0; j < pprune->num_partrelprunedata; j++)
-			relation_close(prunedata[j].context.partrel, NoLock);
+		relation_close(prunedata.context.partrel, NoLock);
 	}
 }
 
@@ -1623,14 +1600,16 @@ ExecFindInitialMatchingSubPlans(PartitionPruneState *prunestate, int nsubplans)
 
 	for (i = 0; i < prunestate->num_partprunedata; i++)
 	{
-		PartitionPruningData *pprune;
 		PartitionedRelPruningData *prelprune;
 
-		pprune = prunestate->partprunedata[i];
-		prelprune = &pprune->partrelprunedata[0];
+		prelprune = &prunestate->partrelprunedata[i];
+
+		/* Only call find_matching_subplans_recurse on root table. */
+		if (prelprune->context.partrel->rd_rel->relispartition)
+			continue;
 
 		/* Perform pruning without using PARAM_EXEC Params */
-		find_matching_subplans_recurse(pprune, prelprune, true, &result);
+		find_matching_subplans_recurse(prunestate, prelprune, true, &result);
 
 		/* Expression eval may have used space in node's ps_ExprContext too */
 		ResetExprContext(prelprune->context.planstate->ps_ExprContext);
@@ -1681,58 +1660,50 @@ ExecFindInitialMatchingSubPlans(PartitionPruneState *prunestate, int nsubplans)
 		 * 'present_parts'.
 		 */
 
-		for (i = 0; i < prunestate->num_partprunedata; i++)
+		for (i = prunestate->num_partprunedata - 1; i >= 0; i--)
 		{
-			int			j;
-			PartitionPruningData *prunedata;
+			PartitionedRelPruningData *pprune;
+			int			nparts;
+			int			k;
 
-			prunedata = prunestate->partprunedata[i];
+			pprune = &prunestate->partrelprunedata[i];
+			nparts = pprune->context.nparts;
+			/* We just rebuild present_parts from scratch */
+			bms_free(pprune->present_parts);
+			pprune->present_parts = NULL;
 
-			for (j = prunedata->num_partrelprunedata - 1; j >= 0; j--)
+			for (k = 0; k < nparts; k++)
 			{
-				PartitionedRelPruningData *pprune;
-				int			nparts;
-				int			k;
+				int			oldidx = pprune->subplan_map[k];
+				int			subidx;
 
-				pprune = &prunedata->partrelprunedata[j];
-				nparts = pprune->context.nparts;
-				/* We just rebuild present_parts from scratch */
-				bms_free(pprune->present_parts);
-				pprune->present_parts = NULL;
-
-				for (k = 0; k < nparts; k++)
+				/*
+				 * If this partition existed as a subplan then change the
+				 * old subplan index to the new subplan index.  The new
+				 * index may become -1 if the partition was pruned above,
+				 * or it may just come earlier in the subplan list due to
+				 * some subplans being removed earlier in the list.  If
+				 * it's a subpartition, add it to present_parts unless
+				 * it's entirely pruned.
+				 */
+				if (oldidx >= 0)
 				{
-					int			oldidx = pprune->subplan_map[k];
-					int			subidx;
+					Assert(oldidx < nsubplans);
+					pprune->subplan_map[k] = new_subplan_indexes[oldidx];
 
-					/*
-					 * If this partition existed as a subplan then change the
-					 * old subplan index to the new subplan index.  The new
-					 * index may become -1 if the partition was pruned above,
-					 * or it may just come earlier in the subplan list due to
-					 * some subplans being removed earlier in the list.  If
-					 * it's a subpartition, add it to present_parts unless
-					 * it's entirely pruned.
-					 */
-					if (oldidx >= 0)
-					{
-						Assert(oldidx < nsubplans);
-						pprune->subplan_map[k] = new_subplan_indexes[oldidx];
+					if (new_subplan_indexes[oldidx] >= 0)
+						pprune->present_parts =
+							bms_add_member(pprune->present_parts, k);
+				}
+				else if ((subidx = pprune->subpart_map[k]) >= 0)
+				{
+					PartitionedRelPruningData *subprune;
 
-						if (new_subplan_indexes[oldidx] >= 0)
-							pprune->present_parts =
-								bms_add_member(pprune->present_parts, k);
-					}
-					else if ((subidx = pprune->subpart_map[k]) >= 0)
-					{
-						PartitionedRelPruningData *subprune;
+					subprune = &prunestate->partrelprunedata[subidx];
 
-						subprune = &prunedata->partrelprunedata[subidx];
-
-						if (!bms_is_empty(subprune->present_parts))
-							pprune->present_parts =
-								bms_add_member(pprune->present_parts, k);
-					}
+					if (!bms_is_empty(subprune->present_parts))
+						pprune->present_parts =
+							bms_add_member(pprune->present_parts, k);
 				}
 			}
 		}
@@ -1764,18 +1735,21 @@ ExecFindMatchingSubPlans(PartitionPruneState *prunestate)
 
 	for (i = 0; i < prunestate->num_partprunedata; i++)
 	{
-		PartitionPruningData *pprune;
 		PartitionedRelPruningData *prelprune;
 
-		pprune = prunestate->partprunedata[i];
-		prelprune = &pprune->partrelprunedata[0];
+		prelprune = &prunestate->partrelprunedata[i];
 
-		find_matching_subplans_recurse(pprune, prelprune, false, &result);
+		/* Only call find_matching_subplans_recurse on root table. */
+		if (prelprune->context.partrel->rd_rel->relispartition)
+			continue;
+
+		find_matching_subplans_recurse(prunestate, prelprune, false, &result);
 
 		/* Expression eval may have used space in node's ps_ExprContext too */
 		ResetExprContext(prelprune->context.planstate->ps_ExprContext);
 	}
 
+
 	MemoryContextSwitchTo(oldcontext);
 
 	/* Copy result out of the temp context before we reset it */
@@ -1797,7 +1771,7 @@ ExecFindMatchingSubPlans(PartitionPruneState *prunestate)
  * Adds valid (non-prunable) subplan IDs to *validsubplans
  */
 static void
-find_matching_subplans_recurse(PartitionPruningData *pprune,
+find_matching_subplans_recurse(PartitionPruneState *prunestate,
 							   PartitionedRelPruningData *prelprune,
 							   bool initial_prune,
 							   Bitmapset **validsubplans)
@@ -1841,8 +1815,8 @@ find_matching_subplans_recurse(PartitionPruningData *pprune,
 			int			partidx = prelprune->subpart_map[i];
 
 			if (partidx >= 0)
-				find_matching_subplans_recurse(pprune,
-											   &pprune->partrelprunedata[partidx],
+				find_matching_subplans_recurse(prunestate,
+											   &prunestate->partrelprunedata[partidx],
 											   initial_prune, validsubplans);
 			else
 			{
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index f9e6ad3ab7..c7872661c4 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -1033,6 +1033,7 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path)
 	ListCell   *subpaths;
 	RelOptInfo *rel = best_path->path.parent;
 	PartitionPruneInfo *partpruneinfo = NULL;
+	List	   *flattened_partitioned_rels = NIL;
 
 	/*
 	 * The subpaths list could be empty, if every child was proven empty by
@@ -1083,6 +1084,9 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path)
 
 		prunequal = extract_actual_clauses(rel->baserestrictinfo, false);
 
+		flattened_partitioned_rels =
+					flatten_partitioned_rels(best_path->partitioned_rels);
+
 		if (best_path->path.param_info)
 		{
 			List	   *prmquals = best_path->path.param_info->ppi_clauses;
@@ -1098,6 +1102,7 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path)
 			partpruneinfo =
 				make_partition_pruneinfo(root, rel,
 										 best_path->partitioned_rels,
+										 flattened_partitioned_rels,
 										 best_path->subpaths, prunequal);
 	}
 
@@ -1109,7 +1114,7 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path)
 	 */
 
 	plan = make_append(subplans, best_path->first_partial_path,
-					   tlist, best_path->partitioned_rels,
+					   tlist, flattened_partitioned_rels,
 					   partpruneinfo);
 
 	copy_generic_path_info(&plan->plan, (Path *) best_path);
@@ -1135,6 +1140,7 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path)
 	ListCell   *subpaths;
 	RelOptInfo *rel = best_path->path.parent;
 	PartitionPruneInfo *partpruneinfo = NULL;
+	List	   *flattened_partitioned_rels = NIL;
 
 	/*
 	 * We don't have the actual creation of the MergeAppend node split out
@@ -1233,6 +1239,9 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path)
 
 		prunequal = extract_actual_clauses(rel->baserestrictinfo, false);
 
+		flattened_partitioned_rels =
+					flatten_partitioned_rels(best_path->partitioned_rels);
+
 		if (best_path->path.param_info)
 		{
 
@@ -1247,12 +1256,12 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path)
 
 		if (prunequal != NIL)
 			partpruneinfo = make_partition_pruneinfo(root, rel,
-													  best_path->partitioned_rels,
-													  best_path->subpaths, prunequal);
+													 best_path->partitioned_rels,
+													 flattened_partitioned_rels,
+													 best_path->subpaths, prunequal);
 	}
 
-	node->partitioned_rels =
-		flatten_partitioned_rels(best_path->partitioned_rels);
+	node->partitioned_rels = flattened_partitioned_rels;
 	node->mergeplans = subplans;
 	node->part_prune_info = partpruneinfo;
 
@@ -5006,7 +5015,7 @@ bitmap_subplan_mark_shared(Plan *plan)
 /*
  * flatten_partitioned_rels
  *		Convert List of Lists into a single List with all elements from the
-*		sub-lists.
+ *		sub-lists.
  */
 static List *
 flatten_partitioned_rels(List *partitioned_rels)
@@ -5380,8 +5389,9 @@ make_append(List *appendplans, int first_partial_plan,
 	plan->righttree = NULL;
 	node->appendplans = appendplans;
 	node->first_partial_plan = first_partial_plan;
-	node->partitioned_rels = flatten_partitioned_rels(partitioned_rels);
+	node->partitioned_rels = partitioned_rels;
 	node->part_prune_info = partpruneinfo;
+
 	return node;
 }
 
diff --git a/src/backend/partitioning/partprune.c b/src/backend/partitioning/partprune.c
index 9ce216c28b..490eb4090d 100644
--- a/src/backend/partitioning/partprune.c
+++ b/src/backend/partitioning/partprune.c
@@ -114,6 +114,7 @@ typedef struct PruneStepResult
 static List *make_partitionedrel_pruneinfo(PlannerInfo *root,
 							  RelOptInfo *parentrel,
 							  int *relid_subplan_map,
+							  int *relid_subpart_map,
 							  List *partitioned_rels, List *prunequal,
 							  Bitmapset **matchedsubplans);
 static List *gen_partprune_steps(RelOptInfo *rel, List *clauses,
@@ -195,12 +196,15 @@ static bool partkey_datum_from_expr(PartitionPruneContext *context,
  */
 PartitionPruneInfo *
 make_partition_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel,
-						 List *partitioned_rels, List *subpaths,
+						 List *partitioned_rels,
+						 List *flattened_partitioned_rels,
+						 List *subpaths,
 						 List *prunequal)
 {
 	PartitionPruneInfo *pruneinfo;
 	Bitmapset  *allmatchedsubplans = NULL;
 	int		   *relid_subplan_map;
+	int		   *relid_subpart_map;
 	ListCell   *lc;
 	List	   *prunerelinfos;
 	int			i;
@@ -230,6 +234,38 @@ make_partition_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel,
 		relid_subplan_map[pathrel->relid] = i++;
 	}
 
+	/*
+	 * Construct a temporary array to map from planner relids to index of the
+	 * partitioned_rel.  For convenience, we use 1-based indexes here, so that
+	 * zero can represent an un-filled array entry.
+	 *
+	 * Also, since we're going to flatten the list before putting it into the
+	 * plan, use indexes into the flattened list in the mapping arrays of
+	 * resulting PartitionedRelPruneInfo nodes, instead of indexes into
+	 * individual sub-lists.
+	 */
+	relid_subpart_map = palloc0(sizeof(int) * root->simple_rel_array_size);
+
+	/*
+	 * relid_subpart_map maps relid of a non-leaf partition to the index in
+	 * 'partitioned_rels' of that rel (which will also be the index in the
+	 * returned PartitionedRelPruneInfo list of the info for that partition).
+	 */
+	i = 1;
+	foreach(lc, flattened_partitioned_rels)
+	{
+		Index		rti = lfirst_int(lc);
+
+		Assert(rti < root->simple_rel_array_size);
+		/* No duplicates please */
+		Assert(relid_subpart_map[rti] == 0);
+		/* Same rel cannot be both leaf and non-leaf */
+		Assert(relid_subplan_map[rti] == 0);
+
+		relid_subpart_map[rti] = i++;
+	}
+
+
 	Assert(partitioned_rels->type == T_List);
 
 	prunerelinfos = NIL;
@@ -243,19 +279,22 @@ make_partition_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel,
 
 		prelinfolist = make_partitionedrel_pruneinfo(root, parentrel,
 													 relid_subplan_map,
+													 relid_subpart_map,
 													 rels, prunequal,
 													 &matchedsubplans);
 
 		/* When pruning is possible, record the matched subplans */
 		if (prelinfolist != NIL)
 		{
-			prunerelinfos = lappend(prunerelinfos, prelinfolist);
+			prunerelinfos = list_concat(prunerelinfos,
+										list_copy(prelinfolist));
 			allmatchedsubplans = bms_join(matchedsubplans,
 										  allmatchedsubplans);
 		}
 	}
 
 	pfree(relid_subplan_map);
+	pfree(relid_subpart_map);
 
 	/*
 	 * if none of the partition hierarchies had any useful run-time pruning
@@ -310,45 +349,17 @@ make_partition_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel,
  */
 static List *
 make_partitionedrel_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel,
-							  int *relid_subplan_map,
+							  int *relid_subplan_map, int *relid_subpart_map,
 							  List *partitioned_rels, List *prunequal,
 							  Bitmapset **matchedsubplans)
 {
 	RelOptInfo *targetpart = NULL;
 	List	   *prelinfolist = NIL;
 	bool		doruntimeprune = false;
-	bool		hascontradictingquals = false;
 	ListCell   *lc;
-	int		   *relid_subpart_map;
 	Bitmapset  *subplansfound = NULL;
 	int			i;
 
-	/*
-	 * Construct a temporary array to map from planner relids to index of the
-	 * partitioned_rel.  For convenience, we use 1-based indexes here, so that
-	 * zero can represent an un-filled array entry.
-	 */
-	relid_subpart_map = palloc0(sizeof(int) * root->simple_rel_array_size);
-
-	/*
-	 * relid_subpart_map maps relid of a non-leaf partition to the index in
-	 * 'partitioned_rels' of that rel (which will also be the index in the
-	 * returned PartitionedRelPruneInfo list of the info for that partition).
-	 */
-	i = 1;
-	foreach(lc, partitioned_rels)
-	{
-		Index		rti = lfirst_int(lc);
-
-		Assert(rti < root->simple_rel_array_size);
-		/* No duplicates please */
-		Assert(relid_subpart_map[rti] == 0);
-		/* Same rel cannot be both leaf and non-leaf */
-		Assert(relid_subplan_map[rti] == 0);
-
-		relid_subpart_map[rti] = i++;
-	}
-
 	/* We now build a PartitionedRelPruneInfo for each partitioned rel */
 	foreach(lc, partitioned_rels)
 	{
@@ -477,8 +488,6 @@ make_partitionedrel_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel,
 		prelinfolist = lappend(prelinfolist, prelinfo);
 	}
 
-	pfree(relid_subpart_map);
-
 	if (!doruntimeprune)
 		return NIL;
 
diff --git a/src/include/executor/execPartition.h b/src/include/executor/execPartition.h
index 4327fd4cb1..5b6acac4f0 100644
--- a/src/include/executor/execPartition.h
+++ b/src/include/executor/execPartition.h
@@ -147,17 +147,6 @@ typedef struct PartitionedRelPruningData
 	bool		do_exec_prune;
 } PartitionedRelPruningData;
 
-/*
- * PartitionPruningData - Encapsulates an array of PartitionedRelPruningData
- * which belong to a single partition hierarchy containing 1 or more
- * partitions.
- */
-typedef struct PartitionPruningData
-{
-	int			num_partrelprunedata;
-	PartitionedRelPruningData partrelprunedata[FLEXIBLE_ARRAY_MEMBER];
-} PartitionPruningData;
-
 /*-----------------------
  * PartitionPruneState - State object required for plan nodes to perform
  * run-time partition pruning.
@@ -198,7 +187,7 @@ typedef struct PartitionPruneState
 	Bitmapset  *execparamids;
 	Bitmapset  *other_subplans;
 	MemoryContext prune_context;
-	PartitionPruningData *partprunedata[FLEXIBLE_ARRAY_MEMBER];
+	PartitionedRelPruningData partrelprunedata[FLEXIBLE_ARRAY_MEMBER];
 } PartitionPruneState;
 
 extern PartitionTupleRouting *ExecSetupPartitionTupleRouting(ModifyTableState *mtstate,
diff --git a/src/include/partitioning/partprune.h b/src/include/partitioning/partprune.h
index df3bcb737d..79398d1cc1 100644
--- a/src/include/partitioning/partprune.h
+++ b/src/include/partitioning/partprune.h
@@ -77,6 +77,7 @@ typedef struct PartitionPruneContext
 extern PartitionPruneInfo *make_partition_pruneinfo(PlannerInfo *root,
 						 RelOptInfo *parentrel,
 						 List *partitioned_rels,
+						 List *flattened_partitioned_rels,
 						 List *subpaths, List *prunequal);
 extern Relids prune_append_rel_partitions(RelOptInfo *rel);
 extern Bitmapset *get_matching_partitions(PartitionPruneContext *context,