From 345b2dcf070bd8fbccde643b1b2856027623e9e5 Mon Sep 17 00:00:00 2001
From: Robert Haas <rhaas@postgresql.org>
Date: Wed, 4 Jan 2017 13:05:29 -0500
Subject: [PATCH] Move partition_tuple_slot out of EState.

Commit 2ac3ef7a01df859c62d0a02333b646d65eaec5ff added a TupleTapleSlot
for partition tuple slot to EState (es_partition_tuple_slot) but it's
more logical to have it as part of ModifyTableState
(mt_partition_tuple_slot) and CopyState (partition_tuple_slot).

Discussion: http://postgr.es/m/1bd459d9-4c0c-197a-346e-e5e59e217d97@lab.ntt.co.jp

Amit Langote, per a gripe from me
---
 src/backend/commands/copy.c            | 26 +++++++++++++-------------
 src/backend/executor/execMain.c        | 12 ++++++++++++
 src/backend/executor/nodeModifyTable.c | 17 ++++++++---------
 src/include/executor/executor.h        |  1 +
 src/include/nodes/execnodes.h          |  4 +---
 5 files changed, 35 insertions(+), 25 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 77a8631de12..071b97dee13 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -161,11 +161,14 @@ typedef struct CopyStateData
 	ExprState **defexprs;		/* array of default att expressions */
 	bool		volatile_defexprs;		/* is any of defexprs volatile? */
 	List	   *range_table;
+
 	PartitionDispatch *partition_dispatch_info;
-	int			num_dispatch;
-	int			num_partitions;
-	ResultRelInfo *partitions;
+	int			num_dispatch;		/* Number of entries in the above array */
+	int			num_partitions;		/* Number of members in the following
+									 * arrays */
+	ResultRelInfo  *partitions;		/* Per partition result relation */
 	TupleConversionMap **partition_tupconv_maps;
+	TupleTableSlot *partition_tuple_slot;
 
 	/*
 	 * These variables are used to reduce overhead in textual COPY FROM.
@@ -1409,6 +1412,7 @@ BeginCopy(ParseState *pstate,
 			PartitionDispatch  *partition_dispatch_info;
 			ResultRelInfo	   *partitions;
 			TupleConversionMap **partition_tupconv_maps;
+			TupleTableSlot	   *partition_tuple_slot;
 			int					num_parted,
 								num_partitions;
 
@@ -1416,12 +1420,14 @@ BeginCopy(ParseState *pstate,
 										   &partition_dispatch_info,
 										   &partitions,
 										   &partition_tupconv_maps,
+										   &partition_tuple_slot,
 										   &num_parted, &num_partitions);
 			cstate->partition_dispatch_info = partition_dispatch_info;
 			cstate->num_dispatch = num_parted;
 			cstate->partitions = partitions;
 			cstate->num_partitions = num_partitions;
 			cstate->partition_tupconv_maps = partition_tupconv_maps;
+			cstate->partition_tuple_slot = partition_tuple_slot;
 		}
 	}
 	else
@@ -2435,15 +2441,6 @@ CopyFrom(CopyState cstate)
 	/* Triggers might need a slot as well */
 	estate->es_trig_tuple_slot = ExecInitExtraTupleSlot(estate);
 
-	/*
-	 * Initialize a dedicated slot to manipulate tuples of any given
-	 * partition's rowtype.
-	 */
-	if (cstate->partition_dispatch_info)
-		estate->es_partition_tuple_slot = ExecInitExtraTupleSlot(estate);
-	else
-		estate->es_partition_tuple_slot = NULL;
-
 	/*
 	 * It's more efficient to prepare a bunch of tuples for insertion, and
 	 * insert them in one heap_multi_insert() call, than call heap_insert()
@@ -2591,7 +2588,7 @@ CopyFrom(CopyState cstate)
 				 * we're finished dealing with the partition.
 				 */
 				oldslot = slot;
-				slot = estate->es_partition_tuple_slot;
+				slot = cstate->partition_tuple_slot;
 				Assert(slot != NULL);
 				ExecSetSlotDescriptor(slot, RelationGetDescr(partrel));
 				ExecStoreTuple(tuple, slot, InvalidBuffer, true);
@@ -2756,6 +2753,9 @@ CopyFrom(CopyState cstate)
 			ExecCloseIndices(resultRelInfo);
 			heap_close(resultRelInfo->ri_RelationDesc, NoLock);
 		}
+
+		/* Release the standalone partition tuple descriptor */
+		ExecDropSingleTupleTableSlot(cstate->partition_tuple_slot);
 	}
 
 	FreeExecutorState(estate);
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 7e3c207018f..eb9b528c4e4 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -3012,6 +3012,9 @@ EvalPlanQualEnd(EPQState *epqstate)
  *		entry for every leaf partition (required to convert input tuple based
  *		on the root table's rowtype to a leaf partition's rowtype after tuple
  *		routing is done
+ * 'partition_tuple_slot' receives a standalone TupleTableSlot to be used
+ *		to manipulate any given leaf partition's rowtype after that partition
+ *		is chosen by tuple-routing.
  * 'num_parted' receives the number of partitioned tables in the partition
  *		tree (= the number of entries in the 'pd' output array)
  * 'num_partitions' receives the number of leaf partitions in the partition
@@ -3026,6 +3029,7 @@ ExecSetupPartitionTupleRouting(Relation rel,
 							   PartitionDispatch **pd,
 							   ResultRelInfo **partitions,
 							   TupleConversionMap ***tup_conv_maps,
+							   TupleTableSlot **partition_tuple_slot,
 							   int *num_parted, int *num_partitions)
 {
 	TupleDesc	tupDesc = RelationGetDescr(rel);
@@ -3043,6 +3047,14 @@ ExecSetupPartitionTupleRouting(Relation rel,
 	*tup_conv_maps = (TupleConversionMap **) palloc0(*num_partitions *
 										   sizeof(TupleConversionMap *));
 
+	/*
+	 * Initialize an empty slot that will be used to manipulate tuples of any
+	 * given partition's rowtype.  It is attached to the caller-specified node
+	 * (such as ModifyTableState) and released when the node finishes
+	 * processing.
+	 */
+	*partition_tuple_slot = MakeTupleTableSlot();
+
 	leaf_part_rri = *partitions;
 	i = 0;
 	foreach(cell, leaf_parts)
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index c7dd148944e..aa364707f8d 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -329,7 +329,7 @@ ExecInsert(ModifyTableState *mtstate,
 			 * Use the dedicated slot for that.
 			 */
 			oldslot = slot;
-			slot = estate->es_partition_tuple_slot;
+			slot = mtstate->mt_partition_tuple_slot;
 			Assert(slot != NULL);
 			ExecSetSlotDescriptor(slot, RelationGetDescr(partrel));
 			ExecStoreTuple(tuple, slot, InvalidBuffer, true);
@@ -1738,6 +1738,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
 		PartitionDispatch  *partition_dispatch_info;
 		ResultRelInfo	   *partitions;
 		TupleConversionMap **partition_tupconv_maps;
+		TupleTableSlot	   *partition_tuple_slot;
 		int					num_parted,
 							num_partitions;
 
@@ -1745,21 +1746,15 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
 									   &partition_dispatch_info,
 									   &partitions,
 									   &partition_tupconv_maps,
+									   &partition_tuple_slot,
 									   &num_parted, &num_partitions);
 		mtstate->mt_partition_dispatch_info = partition_dispatch_info;
 		mtstate->mt_num_dispatch = num_parted;
 		mtstate->mt_partitions = partitions;
 		mtstate->mt_num_partitions = num_partitions;
 		mtstate->mt_partition_tupconv_maps = partition_tupconv_maps;
-
-		/*
-		 * Initialize a dedicated slot to manipulate tuples of any given
-		 * partition's rowtype.
-		 */
-		estate->es_partition_tuple_slot = ExecInitExtraTupleSlot(estate);
+		mtstate->mt_partition_tuple_slot = partition_tuple_slot;
 	}
-	else
-		estate->es_partition_tuple_slot = NULL;
 
 	/*
 	 * Initialize any WITH CHECK OPTION constraints if needed.
@@ -2100,6 +2095,10 @@ ExecEndModifyTable(ModifyTableState *node)
 		heap_close(resultRelInfo->ri_RelationDesc, NoLock);
 	}
 
+	/* Release the standalone partition tuple descriptor, if any */
+	if (node->mt_partition_tuple_slot)
+		ExecDropSingleTupleTableSlot(node->mt_partition_tuple_slot);
+
 	/*
 	 * Free the exprcontext
 	 */
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index a3fa5f07671..4a7074edd70 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -217,6 +217,7 @@ extern void ExecSetupPartitionTupleRouting(Relation rel,
 							   PartitionDispatch **pd,
 							   ResultRelInfo **partitions,
 							   TupleConversionMap ***tup_conv_maps,
+							   TupleTableSlot **partition_tuple_slot,
 							   int *num_parted, int *num_partitions);
 extern int ExecFindPartition(ResultRelInfo *resultRelInfo,
 				  PartitionDispatch *pd,
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 486555eac4c..0e05d472c90 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -384,9 +384,6 @@ typedef struct EState
 	TupleTableSlot *es_trig_oldtup_slot;		/* for TriggerEnabled */
 	TupleTableSlot *es_trig_newtup_slot;		/* for TriggerEnabled */
 
-	/* Slot used to manipulate a tuple after it is routed to a partition */
-	TupleTableSlot *es_partition_tuple_slot;
-
 	/* Parameter info: */
 	ParamListInfo es_param_list_info;	/* values of external params */
 	ParamExecData *es_param_exec_vals;	/* values of internal params */
@@ -1165,6 +1162,7 @@ typedef struct ModifyTableState
 	ResultRelInfo  *mt_partitions;	/* Per partition result relation */
 	TupleConversionMap **mt_partition_tupconv_maps;
 									/* Per partition tuple conversion map */
+	TupleTableSlot *mt_partition_tuple_slot;
 } ModifyTableState;
 
 /* ----------------
-- 
GitLab