mirror of
				https://github.com/postgres/postgres.git
				synced 2025-10-31 00:03:57 -04:00 
			
		
		
		
	Simplify and encapsulate tuple routing support code.
Instead of having ExecSetupPartitionTupleRouting return multiple out parameters, have it return a pointer to a structure containing all of those different things. Also, provide and use a cleanup function, ExecCleanupTupleRouting, instead of cleaning up all of the resources allocated by ExecSetupPartitionTupleRouting individually. Amit Khandekar, reviewed by Amit Langote, David Rowley, and me Discussion: http://postgr.es/m/CAJ3gD9fWfxgKC+PfJZF3hkgAcNOy-LpfPxVYitDEXKHjeieWQQ@mail.gmail.com
This commit is contained in:
		
							parent
							
								
									d3fb72ea6d
								
							
						
					
					
						commit
						cc6337d2fe
					
				| @ -166,12 +166,9 @@ typedef struct CopyStateData | |||||||
| 	bool		volatile_defexprs;	/* is any of defexprs volatile? */ | 	bool		volatile_defexprs;	/* is any of defexprs volatile? */ | ||||||
| 	List	   *range_table; | 	List	   *range_table; | ||||||
| 
 | 
 | ||||||
| 	PartitionDispatch *partition_dispatch_info; | 	/* Tuple-routing support info */ | ||||||
| 	int			num_dispatch;	/* Number of entries in the above array */ | 	PartitionTupleRouting *partition_tuple_routing; | ||||||
| 	int			num_partitions; /* Number of members in the following arrays */ | 
 | ||||||
| 	ResultRelInfo **partitions; /* Per partition result relation pointers */ |  | ||||||
| 	TupleConversionMap **partition_tupconv_maps; |  | ||||||
| 	TupleTableSlot *partition_tuple_slot; |  | ||||||
| 	TransitionCaptureState *transition_capture; | 	TransitionCaptureState *transition_capture; | ||||||
| 	TupleConversionMap **transition_tupconv_maps; | 	TupleConversionMap **transition_tupconv_maps; | ||||||
| 
 | 
 | ||||||
| @ -2472,28 +2469,10 @@ CopyFrom(CopyState cstate) | |||||||
| 	 */ | 	 */ | ||||||
| 	if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) | 	if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) | ||||||
| 	{ | 	{ | ||||||
| 		PartitionDispatch *partition_dispatch_info; | 		PartitionTupleRouting *proute; | ||||||
| 		ResultRelInfo **partitions; |  | ||||||
| 		TupleConversionMap **partition_tupconv_maps; |  | ||||||
| 		TupleTableSlot *partition_tuple_slot; |  | ||||||
| 		int			num_parted, |  | ||||||
| 					num_partitions; |  | ||||||
| 
 | 
 | ||||||
| 		ExecSetupPartitionTupleRouting(NULL, | 		proute = cstate->partition_tuple_routing = | ||||||
| 									   cstate->rel, | 			ExecSetupPartitionTupleRouting(NULL, cstate->rel, 1, estate); | ||||||
| 									   1, |  | ||||||
| 									   estate, |  | ||||||
| 									   &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; |  | ||||||
| 
 | 
 | ||||||
| 		/*
 | 		/*
 | ||||||
| 		 * If we are capturing transition tuples, they may need to be | 		 * If we are capturing transition tuples, they may need to be | ||||||
| @ -2506,11 +2485,11 @@ CopyFrom(CopyState cstate) | |||||||
| 			int			i; | 			int			i; | ||||||
| 
 | 
 | ||||||
| 			cstate->transition_tupconv_maps = (TupleConversionMap **) | 			cstate->transition_tupconv_maps = (TupleConversionMap **) | ||||||
| 				palloc0(sizeof(TupleConversionMap *) * cstate->num_partitions); | 				palloc0(sizeof(TupleConversionMap *) * proute->num_partitions); | ||||||
| 			for (i = 0; i < cstate->num_partitions; ++i) | 			for (i = 0; i < proute->num_partitions; ++i) | ||||||
| 			{ | 			{ | ||||||
| 				cstate->transition_tupconv_maps[i] = | 				cstate->transition_tupconv_maps[i] = | ||||||
| 					convert_tuples_by_name(RelationGetDescr(cstate->partitions[i]->ri_RelationDesc), | 					convert_tuples_by_name(RelationGetDescr(proute->partitions[i]->ri_RelationDesc), | ||||||
| 										   RelationGetDescr(cstate->rel), | 										   RelationGetDescr(cstate->rel), | ||||||
| 										   gettext_noop("could not convert row type")); | 										   gettext_noop("could not convert row type")); | ||||||
| 			} | 			} | ||||||
| @ -2530,7 +2509,7 @@ CopyFrom(CopyState cstate) | |||||||
| 	if ((resultRelInfo->ri_TrigDesc != NULL && | 	if ((resultRelInfo->ri_TrigDesc != NULL && | ||||||
| 		 (resultRelInfo->ri_TrigDesc->trig_insert_before_row || | 		 (resultRelInfo->ri_TrigDesc->trig_insert_before_row || | ||||||
| 		  resultRelInfo->ri_TrigDesc->trig_insert_instead_row)) || | 		  resultRelInfo->ri_TrigDesc->trig_insert_instead_row)) || | ||||||
| 		cstate->partition_dispatch_info != NULL || | 		cstate->partition_tuple_routing != NULL || | ||||||
| 		cstate->volatile_defexprs) | 		cstate->volatile_defexprs) | ||||||
| 	{ | 	{ | ||||||
| 		useHeapMultiInsert = false; | 		useHeapMultiInsert = false; | ||||||
| @ -2605,10 +2584,11 @@ CopyFrom(CopyState cstate) | |||||||
| 		ExecStoreTuple(tuple, slot, InvalidBuffer, false); | 		ExecStoreTuple(tuple, slot, InvalidBuffer, false); | ||||||
| 
 | 
 | ||||||
| 		/* Determine the partition to heap_insert the tuple into */ | 		/* Determine the partition to heap_insert the tuple into */ | ||||||
| 		if (cstate->partition_dispatch_info) | 		if (cstate->partition_tuple_routing) | ||||||
| 		{ | 		{ | ||||||
| 			int			leaf_part_index; | 			int			leaf_part_index; | ||||||
| 			TupleConversionMap *map; | 			TupleConversionMap *map; | ||||||
|  | 			PartitionTupleRouting *proute = cstate->partition_tuple_routing; | ||||||
| 
 | 
 | ||||||
| 			/*
 | 			/*
 | ||||||
| 			 * Away we go ... If we end up not finding a partition after all, | 			 * Away we go ... If we end up not finding a partition after all, | ||||||
| @ -2619,11 +2599,11 @@ CopyFrom(CopyState cstate) | |||||||
| 			 * partition, respectively. | 			 * partition, respectively. | ||||||
| 			 */ | 			 */ | ||||||
| 			leaf_part_index = ExecFindPartition(resultRelInfo, | 			leaf_part_index = ExecFindPartition(resultRelInfo, | ||||||
| 												cstate->partition_dispatch_info, | 												proute->partition_dispatch_info, | ||||||
| 												slot, | 												slot, | ||||||
| 												estate); | 												estate); | ||||||
| 			Assert(leaf_part_index >= 0 && | 			Assert(leaf_part_index >= 0 && | ||||||
| 				   leaf_part_index < cstate->num_partitions); | 				   leaf_part_index < proute->num_partitions); | ||||||
| 
 | 
 | ||||||
| 			/*
 | 			/*
 | ||||||
| 			 * If this tuple is mapped to a partition that is not same as the | 			 * If this tuple is mapped to a partition that is not same as the | ||||||
| @ -2641,7 +2621,7 @@ CopyFrom(CopyState cstate) | |||||||
| 			 * to the selected partition. | 			 * to the selected partition. | ||||||
| 			 */ | 			 */ | ||||||
| 			saved_resultRelInfo = resultRelInfo; | 			saved_resultRelInfo = resultRelInfo; | ||||||
| 			resultRelInfo = cstate->partitions[leaf_part_index]; | 			resultRelInfo = proute->partitions[leaf_part_index]; | ||||||
| 
 | 
 | ||||||
| 			/* We do not yet have a way to insert into a foreign partition */ | 			/* We do not yet have a way to insert into a foreign partition */ | ||||||
| 			if (resultRelInfo->ri_FdwRoutine) | 			if (resultRelInfo->ri_FdwRoutine) | ||||||
| @ -2688,7 +2668,7 @@ CopyFrom(CopyState cstate) | |||||||
| 			 * We might need to convert from the parent rowtype to the | 			 * We might need to convert from the parent rowtype to the | ||||||
| 			 * partition rowtype. | 			 * partition rowtype. | ||||||
| 			 */ | 			 */ | ||||||
| 			map = cstate->partition_tupconv_maps[leaf_part_index]; | 			map = proute->partition_tupconv_maps[leaf_part_index]; | ||||||
| 			if (map) | 			if (map) | ||||||
| 			{ | 			{ | ||||||
| 				Relation	partrel = resultRelInfo->ri_RelationDesc; | 				Relation	partrel = resultRelInfo->ri_RelationDesc; | ||||||
| @ -2700,7 +2680,7 @@ CopyFrom(CopyState cstate) | |||||||
| 				 * point on.  Use a dedicated slot from this point on until | 				 * point on.  Use a dedicated slot from this point on until | ||||||
| 				 * we're finished dealing with the partition. | 				 * we're finished dealing with the partition. | ||||||
| 				 */ | 				 */ | ||||||
| 				slot = cstate->partition_tuple_slot; | 				slot = proute->partition_tuple_slot; | ||||||
| 				Assert(slot != NULL); | 				Assert(slot != NULL); | ||||||
| 				ExecSetSlotDescriptor(slot, RelationGetDescr(partrel)); | 				ExecSetSlotDescriptor(slot, RelationGetDescr(partrel)); | ||||||
| 				ExecStoreTuple(tuple, slot, InvalidBuffer, true); | 				ExecStoreTuple(tuple, slot, InvalidBuffer, true); | ||||||
| @ -2852,34 +2832,8 @@ CopyFrom(CopyState cstate) | |||||||
| 	ExecCloseIndices(resultRelInfo); | 	ExecCloseIndices(resultRelInfo); | ||||||
| 
 | 
 | ||||||
| 	/* Close all the partitioned tables, leaf partitions, and their indices */ | 	/* Close all the partitioned tables, leaf partitions, and their indices */ | ||||||
| 	if (cstate->partition_dispatch_info) | 	if (cstate->partition_tuple_routing) | ||||||
| 	{ | 		ExecCleanupTupleRouting(cstate->partition_tuple_routing); | ||||||
| 		int			i; |  | ||||||
| 
 |  | ||||||
| 		/*
 |  | ||||||
| 		 * Remember cstate->partition_dispatch_info[0] corresponds to the root |  | ||||||
| 		 * partitioned table, which we must not try to close, because it is |  | ||||||
| 		 * the main target table of COPY that will be closed eventually by |  | ||||||
| 		 * DoCopy().  Also, tupslot is NULL for the root partitioned table. |  | ||||||
| 		 */ |  | ||||||
| 		for (i = 1; i < cstate->num_dispatch; i++) |  | ||||||
| 		{ |  | ||||||
| 			PartitionDispatch pd = cstate->partition_dispatch_info[i]; |  | ||||||
| 
 |  | ||||||
| 			heap_close(pd->reldesc, NoLock); |  | ||||||
| 			ExecDropSingleTupleTableSlot(pd->tupslot); |  | ||||||
| 		} |  | ||||||
| 		for (i = 0; i < cstate->num_partitions; i++) |  | ||||||
| 		{ |  | ||||||
| 			ResultRelInfo *resultRelInfo = cstate->partitions[i]; |  | ||||||
| 
 |  | ||||||
| 			ExecCloseIndices(resultRelInfo); |  | ||||||
| 			heap_close(resultRelInfo->ri_RelationDesc, NoLock); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		/* Release the standalone partition tuple descriptor */ |  | ||||||
| 		ExecDropSingleTupleTableSlot(cstate->partition_tuple_slot); |  | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	/* Close any trigger target relations */ | 	/* Close any trigger target relations */ | ||||||
| 	ExecCleanUpTriggerState(estate); | 	ExecCleanUpTriggerState(estate); | ||||||
|  | |||||||
| @ -38,58 +38,40 @@ static char *ExecBuildSlotPartitionKeyDescription(Relation rel, | |||||||
| 									 int maxfieldlen); | 									 int maxfieldlen); | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  * ExecSetupPartitionTupleRouting - set up information needed during |  * ExecSetupPartitionTupleRouting - sets up information needed during | ||||||
|  * tuple routing for partitioned tables |  * tuple routing for partitioned tables, encapsulates it in | ||||||
|  * |  * PartitionTupleRouting, and returns it. | ||||||
|  * Output arguments: |  | ||||||
|  * 'pd' receives an array of PartitionDispatch objects with one entry for |  | ||||||
|  *		every partitioned table in the partition tree |  | ||||||
|  * 'partitions' receives an array of ResultRelInfo* objects with one entry for |  | ||||||
|  *		every leaf partition in the partition tree |  | ||||||
|  * 'tup_conv_maps' receives an array of TupleConversionMap objects with one |  | ||||||
|  *		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 |  | ||||||
|  *		tree (= the number of entries in the 'partitions' and 'tup_conv_maps' |  | ||||||
|  *		output arrays |  | ||||||
|  * |  * | ||||||
|  * Note that all the relations in the partition tree are locked using the |  * Note that all the relations in the partition tree are locked using the | ||||||
|  * RowExclusiveLock mode upon return from this function. |  * RowExclusiveLock mode upon return from this function. | ||||||
|  */ |  */ | ||||||
| void | PartitionTupleRouting * | ||||||
| ExecSetupPartitionTupleRouting(ModifyTableState *mtstate, | ExecSetupPartitionTupleRouting(ModifyTableState *mtstate, | ||||||
| 							   Relation rel, | 							   Relation rel, Index resultRTindex, | ||||||
| 							   Index resultRTindex, | 							   EState *estate) | ||||||
| 							   EState *estate, |  | ||||||
| 							   PartitionDispatch **pd, |  | ||||||
| 							   ResultRelInfo ***partitions, |  | ||||||
| 							   TupleConversionMap ***tup_conv_maps, |  | ||||||
| 							   TupleTableSlot **partition_tuple_slot, |  | ||||||
| 							   int *num_parted, int *num_partitions) |  | ||||||
| { | { | ||||||
| 	TupleDesc	tupDesc = RelationGetDescr(rel); | 	TupleDesc	tupDesc = RelationGetDescr(rel); | ||||||
| 	List	   *leaf_parts; | 	List	   *leaf_parts; | ||||||
| 	ListCell   *cell; | 	ListCell   *cell; | ||||||
| 	int			i; | 	int			i; | ||||||
| 	ResultRelInfo *leaf_part_rri; | 	ResultRelInfo *leaf_part_rri; | ||||||
|  | 	PartitionTupleRouting *proute; | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Get the information about the partition tree after locking all the | 	 * Get the information about the partition tree after locking all the | ||||||
| 	 * partitions. | 	 * partitions. | ||||||
| 	 */ | 	 */ | ||||||
| 	(void) find_all_inheritors(RelationGetRelid(rel), RowExclusiveLock, NULL); | 	(void) find_all_inheritors(RelationGetRelid(rel), RowExclusiveLock, NULL); | ||||||
| 	*pd = RelationGetPartitionDispatchInfo(rel, num_parted, &leaf_parts); | 	proute = (PartitionTupleRouting *) palloc0(sizeof(PartitionTupleRouting)); | ||||||
| 	*num_partitions = list_length(leaf_parts); | 	proute->partition_dispatch_info = | ||||||
| 	*partitions = (ResultRelInfo **) palloc(*num_partitions * | 		RelationGetPartitionDispatchInfo(rel, &proute->num_dispatch, | ||||||
| 											sizeof(ResultRelInfo *)); | 										 &leaf_parts); | ||||||
| 	*tup_conv_maps = (TupleConversionMap **) palloc0(*num_partitions * | 	proute->num_partitions = list_length(leaf_parts); | ||||||
| 													 sizeof(TupleConversionMap *)); | 	proute->partitions = (ResultRelInfo **) palloc(proute->num_partitions * | ||||||
|  | 												   sizeof(ResultRelInfo *)); | ||||||
|  | 	proute->partition_tupconv_maps = | ||||||
|  | 		(TupleConversionMap **) palloc0(proute->num_partitions * | ||||||
|  | 										sizeof(TupleConversionMap *)); | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Initialize an empty slot that will be used to manipulate tuples of any | 	 * Initialize an empty slot that will be used to manipulate tuples of any | ||||||
| @ -97,9 +79,9 @@ ExecSetupPartitionTupleRouting(ModifyTableState *mtstate, | |||||||
| 	 * (such as ModifyTableState) and released when the node finishes | 	 * (such as ModifyTableState) and released when the node finishes | ||||||
| 	 * processing. | 	 * processing. | ||||||
| 	 */ | 	 */ | ||||||
| 	*partition_tuple_slot = MakeTupleTableSlot(); | 	proute->partition_tuple_slot = MakeTupleTableSlot(); | ||||||
| 
 | 
 | ||||||
| 	leaf_part_rri = (ResultRelInfo *) palloc0(*num_partitions * | 	leaf_part_rri = (ResultRelInfo *) palloc0(proute->num_partitions * | ||||||
| 											  sizeof(ResultRelInfo)); | 											  sizeof(ResultRelInfo)); | ||||||
| 	i = 0; | 	i = 0; | ||||||
| 	foreach(cell, leaf_parts) | 	foreach(cell, leaf_parts) | ||||||
| @ -109,8 +91,8 @@ ExecSetupPartitionTupleRouting(ModifyTableState *mtstate, | |||||||
| 
 | 
 | ||||||
| 		/*
 | 		/*
 | ||||||
| 		 * We locked all the partitions above including the leaf partitions. | 		 * We locked all the partitions above including the leaf partitions. | ||||||
| 		 * Note that each of the relations in *partitions are eventually | 		 * Note that each of the relations in proute->partitions are | ||||||
| 		 * closed by the caller. | 		 * eventually closed by the caller. | ||||||
| 		 */ | 		 */ | ||||||
| 		partrel = heap_open(lfirst_oid(cell), NoLock); | 		partrel = heap_open(lfirst_oid(cell), NoLock); | ||||||
| 		part_tupdesc = RelationGetDescr(partrel); | 		part_tupdesc = RelationGetDescr(partrel); | ||||||
| @ -119,8 +101,9 @@ ExecSetupPartitionTupleRouting(ModifyTableState *mtstate, | |||||||
| 		 * Save a tuple conversion map to convert a tuple routed to this | 		 * Save a tuple conversion map to convert a tuple routed to this | ||||||
| 		 * partition from the parent's type to the partition's. | 		 * partition from the parent's type to the partition's. | ||||||
| 		 */ | 		 */ | ||||||
| 		(*tup_conv_maps)[i] = convert_tuples_by_name(tupDesc, part_tupdesc, | 		proute->partition_tupconv_maps[i] = | ||||||
| 													 gettext_noop("could not convert row type")); | 			convert_tuples_by_name(tupDesc, part_tupdesc, | ||||||
|  | 								   gettext_noop("could not convert row type")); | ||||||
| 
 | 
 | ||||||
| 		InitResultRelInfo(leaf_part_rri, | 		InitResultRelInfo(leaf_part_rri, | ||||||
| 						  partrel, | 						  partrel, | ||||||
| @ -149,9 +132,11 @@ ExecSetupPartitionTupleRouting(ModifyTableState *mtstate, | |||||||
| 		estate->es_leaf_result_relations = | 		estate->es_leaf_result_relations = | ||||||
| 			lappend(estate->es_leaf_result_relations, leaf_part_rri); | 			lappend(estate->es_leaf_result_relations, leaf_part_rri); | ||||||
| 
 | 
 | ||||||
| 		(*partitions)[i] = leaf_part_rri++; | 		proute->partitions[i] = leaf_part_rri++; | ||||||
| 		i++; | 		i++; | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	return proute; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
| @ -272,6 +257,45 @@ ExecFindPartition(ResultRelInfo *resultRelInfo, PartitionDispatch *pd, | |||||||
| 	return result; | 	return result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /*
 | ||||||
|  |  * ExecCleanupTupleRouting -- Clean up objects allocated for partition tuple | ||||||
|  |  * routing. | ||||||
|  |  * | ||||||
|  |  * Close all the partitioned tables, leaf partitions, and their indices. | ||||||
|  |  */ | ||||||
|  | void | ||||||
|  | ExecCleanupTupleRouting(PartitionTupleRouting * proute) | ||||||
|  | { | ||||||
|  | 	int			i; | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * Remember, proute->partition_dispatch_info[0] corresponds to the root | ||||||
|  | 	 * partitioned table, which we must not try to close, because it is the | ||||||
|  | 	 * main target table of the query that will be closed by callers such as | ||||||
|  | 	 * ExecEndPlan() or DoCopy(). Also, tupslot is NULL for the root | ||||||
|  | 	 * partitioned table. | ||||||
|  | 	 */ | ||||||
|  | 	for (i = 1; i < proute->num_dispatch; i++) | ||||||
|  | 	{ | ||||||
|  | 		PartitionDispatch pd = proute->partition_dispatch_info[i]; | ||||||
|  | 
 | ||||||
|  | 		heap_close(pd->reldesc, NoLock); | ||||||
|  | 		ExecDropSingleTupleTableSlot(pd->tupslot); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for (i = 0; i < proute->num_partitions; i++) | ||||||
|  | 	{ | ||||||
|  | 		ResultRelInfo *resultRelInfo = proute->partitions[i]; | ||||||
|  | 
 | ||||||
|  | 		ExecCloseIndices(resultRelInfo); | ||||||
|  | 		heap_close(resultRelInfo->ri_RelationDesc, NoLock); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* Release the standalone partition tuple descriptor, if any */ | ||||||
|  | 	if (proute->partition_tuple_slot) | ||||||
|  | 		ExecDropSingleTupleTableSlot(proute->partition_tuple_slot); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /*
 | /*
 | ||||||
|  * RelationGetPartitionDispatchInfo |  * RelationGetPartitionDispatchInfo | ||||||
|  *		Returns information necessary to route tuples down a partition tree |  *		Returns information necessary to route tuples down a partition tree | ||||||
|  | |||||||
| @ -279,32 +279,33 @@ ExecInsert(ModifyTableState *mtstate, | |||||||
| 	resultRelInfo = estate->es_result_relation_info; | 	resultRelInfo = estate->es_result_relation_info; | ||||||
| 
 | 
 | ||||||
| 	/* Determine the partition to heap_insert the tuple into */ | 	/* Determine the partition to heap_insert the tuple into */ | ||||||
| 	if (mtstate->mt_partition_dispatch_info) | 	if (mtstate->mt_partition_tuple_routing) | ||||||
| 	{ | 	{ | ||||||
| 		int			leaf_part_index; | 		int			leaf_part_index; | ||||||
|  | 		PartitionTupleRouting *proute = mtstate->mt_partition_tuple_routing; | ||||||
| 		TupleConversionMap *map; | 		TupleConversionMap *map; | ||||||
| 
 | 
 | ||||||
| 		/*
 | 		/*
 | ||||||
| 		 * Away we go ... If we end up not finding a partition after all, | 		 * Away we go ... If we end up not finding a partition after all, | ||||||
| 		 * ExecFindPartition() does not return and errors out instead. | 		 * ExecFindPartition() does not return and errors out instead. | ||||||
| 		 * Otherwise, the returned value is to be used as an index into arrays | 		 * Otherwise, the returned value is to be used as an index into arrays | ||||||
| 		 * mt_partitions[] and mt_partition_tupconv_maps[] that will get us | 		 * proute->partitions[] and proute->partition_tupconv_maps[] that will | ||||||
| 		 * the ResultRelInfo and TupleConversionMap for the partition, | 		 * get us the ResultRelInfo and TupleConversionMap for the partition, | ||||||
| 		 * respectively. | 		 * respectively. | ||||||
| 		 */ | 		 */ | ||||||
| 		leaf_part_index = ExecFindPartition(resultRelInfo, | 		leaf_part_index = ExecFindPartition(resultRelInfo, | ||||||
| 											mtstate->mt_partition_dispatch_info, | 											proute->partition_dispatch_info, | ||||||
| 											slot, | 											slot, | ||||||
| 											estate); | 											estate); | ||||||
| 		Assert(leaf_part_index >= 0 && | 		Assert(leaf_part_index >= 0 && | ||||||
| 			   leaf_part_index < mtstate->mt_num_partitions); | 			   leaf_part_index < proute->num_partitions); | ||||||
| 
 | 
 | ||||||
| 		/*
 | 		/*
 | ||||||
| 		 * Save the old ResultRelInfo and switch to the one corresponding to | 		 * Save the old ResultRelInfo and switch to the one corresponding to | ||||||
| 		 * the selected partition. | 		 * the selected partition. | ||||||
| 		 */ | 		 */ | ||||||
| 		saved_resultRelInfo = resultRelInfo; | 		saved_resultRelInfo = resultRelInfo; | ||||||
| 		resultRelInfo = mtstate->mt_partitions[leaf_part_index]; | 		resultRelInfo = proute->partitions[leaf_part_index]; | ||||||
| 
 | 
 | ||||||
| 		/* We do not yet have a way to insert into a foreign partition */ | 		/* We do not yet have a way to insert into a foreign partition */ | ||||||
| 		if (resultRelInfo->ri_FdwRoutine) | 		if (resultRelInfo->ri_FdwRoutine) | ||||||
| @ -352,7 +353,7 @@ ExecInsert(ModifyTableState *mtstate, | |||||||
| 		 * We might need to convert from the parent rowtype to the partition | 		 * We might need to convert from the parent rowtype to the partition | ||||||
| 		 * rowtype. | 		 * rowtype. | ||||||
| 		 */ | 		 */ | ||||||
| 		map = mtstate->mt_partition_tupconv_maps[leaf_part_index]; | 		map = proute->partition_tupconv_maps[leaf_part_index]; | ||||||
| 		if (map) | 		if (map) | ||||||
| 		{ | 		{ | ||||||
| 			Relation	partrel = resultRelInfo->ri_RelationDesc; | 			Relation	partrel = resultRelInfo->ri_RelationDesc; | ||||||
| @ -364,7 +365,7 @@ ExecInsert(ModifyTableState *mtstate, | |||||||
| 			 * on, until we're finished dealing with the partition. Use the | 			 * on, until we're finished dealing with the partition. Use the | ||||||
| 			 * dedicated slot for that. | 			 * dedicated slot for that. | ||||||
| 			 */ | 			 */ | ||||||
| 			slot = mtstate->mt_partition_tuple_slot; | 			slot = proute->partition_tuple_slot; | ||||||
| 			Assert(slot != NULL); | 			Assert(slot != NULL); | ||||||
| 			ExecSetSlotDescriptor(slot, RelationGetDescr(partrel)); | 			ExecSetSlotDescriptor(slot, RelationGetDescr(partrel)); | ||||||
| 			ExecStoreTuple(tuple, slot, InvalidBuffer, true); | 			ExecStoreTuple(tuple, slot, InvalidBuffer, true); | ||||||
| @ -1500,9 +1501,10 @@ ExecSetupTransitionCaptureState(ModifyTableState *mtstate, EState *estate) | |||||||
| 		mtstate->mt_oc_transition_capture != NULL) | 		mtstate->mt_oc_transition_capture != NULL) | ||||||
| 	{ | 	{ | ||||||
| 		int			numResultRelInfos; | 		int			numResultRelInfos; | ||||||
|  | 		PartitionTupleRouting *proute = mtstate->mt_partition_tuple_routing; | ||||||
| 
 | 
 | ||||||
| 		numResultRelInfos = (mtstate->mt_partition_tuple_slot != NULL ? | 		numResultRelInfos = (proute != NULL ? | ||||||
| 							 mtstate->mt_num_partitions : | 							 proute->num_partitions : | ||||||
| 							 mtstate->mt_nplans); | 							 mtstate->mt_nplans); | ||||||
| 
 | 
 | ||||||
| 		/*
 | 		/*
 | ||||||
| @ -1515,13 +1517,13 @@ ExecSetupTransitionCaptureState(ModifyTableState *mtstate, EState *estate) | |||||||
| 			palloc0(sizeof(TupleConversionMap *) * numResultRelInfos); | 			palloc0(sizeof(TupleConversionMap *) * numResultRelInfos); | ||||||
| 
 | 
 | ||||||
| 		/* Choose the right set of partitions */ | 		/* Choose the right set of partitions */ | ||||||
| 		if (mtstate->mt_partition_dispatch_info != NULL) | 		if (proute != NULL) | ||||||
| 		{ | 		{ | ||||||
| 			/*
 | 			/*
 | ||||||
| 			 * For tuple routing among partitions, we need TupleDescs based on | 			 * For tuple routing among partitions, we need TupleDescs based on | ||||||
| 			 * the partition routing table. | 			 * the partition routing table. | ||||||
| 			 */ | 			 */ | ||||||
| 			ResultRelInfo **resultRelInfos = mtstate->mt_partitions; | 			ResultRelInfo **resultRelInfos = proute->partitions; | ||||||
| 
 | 
 | ||||||
| 			for (i = 0; i < numResultRelInfos; ++i) | 			for (i = 0; i < numResultRelInfos; ++i) | ||||||
| 			{ | 			{ | ||||||
| @ -1832,6 +1834,8 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) | |||||||
| 	ListCell   *l; | 	ListCell   *l; | ||||||
| 	int			i; | 	int			i; | ||||||
| 	Relation	rel; | 	Relation	rel; | ||||||
|  | 	PartitionTupleRouting *proute = NULL; | ||||||
|  | 	int			num_partitions = 0; | ||||||
| 
 | 
 | ||||||
| 	/* check for unsupported flags */ | 	/* check for unsupported flags */ | ||||||
| 	Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK))); | 	Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK))); | ||||||
| @ -1945,28 +1949,11 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) | |||||||
| 	if (operation == CMD_INSERT && | 	if (operation == CMD_INSERT && | ||||||
| 		rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) | 		rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) | ||||||
| 	{ | 	{ | ||||||
| 		PartitionDispatch *partition_dispatch_info; | 		proute = mtstate->mt_partition_tuple_routing = | ||||||
| 		ResultRelInfo **partitions; | 			ExecSetupPartitionTupleRouting(mtstate, | ||||||
| 		TupleConversionMap **partition_tupconv_maps; | 										   rel, node->nominalRelation, | ||||||
| 		TupleTableSlot *partition_tuple_slot; | 										   estate); | ||||||
| 		int			num_parted, | 		num_partitions = proute->num_partitions; | ||||||
| 					num_partitions; |  | ||||||
| 
 |  | ||||||
| 		ExecSetupPartitionTupleRouting(mtstate, |  | ||||||
| 									   rel, |  | ||||||
| 									   node->nominalRelation, |  | ||||||
| 									   estate, |  | ||||||
| 									   &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; |  | ||||||
| 		mtstate->mt_partition_tuple_slot = partition_tuple_slot; |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| @ -2009,7 +1996,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) | |||||||
| 	 * will suffice.  This only occurs for the INSERT case; UPDATE/DELETE | 	 * will suffice.  This only occurs for the INSERT case; UPDATE/DELETE | ||||||
| 	 * cases are handled above. | 	 * cases are handled above. | ||||||
| 	 */ | 	 */ | ||||||
| 	if (node->withCheckOptionLists != NIL && mtstate->mt_num_partitions > 0) | 	if (node->withCheckOptionLists != NIL && num_partitions > 0) | ||||||
| 	{ | 	{ | ||||||
| 		List	   *wcoList; | 		List	   *wcoList; | ||||||
| 		PlanState  *plan; | 		PlanState  *plan; | ||||||
| @ -2026,14 +2013,14 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) | |||||||
| 			   mtstate->mt_nplans == 1); | 			   mtstate->mt_nplans == 1); | ||||||
| 		wcoList = linitial(node->withCheckOptionLists); | 		wcoList = linitial(node->withCheckOptionLists); | ||||||
| 		plan = mtstate->mt_plans[0]; | 		plan = mtstate->mt_plans[0]; | ||||||
| 		for (i = 0; i < mtstate->mt_num_partitions; i++) | 		for (i = 0; i < num_partitions; i++) | ||||||
| 		{ | 		{ | ||||||
| 			Relation	partrel; | 			Relation	partrel; | ||||||
| 			List	   *mapped_wcoList; | 			List	   *mapped_wcoList; | ||||||
| 			List	   *wcoExprs = NIL; | 			List	   *wcoExprs = NIL; | ||||||
| 			ListCell   *ll; | 			ListCell   *ll; | ||||||
| 
 | 
 | ||||||
| 			resultRelInfo = mtstate->mt_partitions[i]; | 			resultRelInfo = proute->partitions[i]; | ||||||
| 			partrel = resultRelInfo->ri_RelationDesc; | 			partrel = resultRelInfo->ri_RelationDesc; | ||||||
| 
 | 
 | ||||||
| 			/* varno = node->nominalRelation */ | 			/* varno = node->nominalRelation */ | ||||||
| @ -2101,12 +2088,12 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) | |||||||
| 		 * are handled above. | 		 * are handled above. | ||||||
| 		 */ | 		 */ | ||||||
| 		returningList = linitial(node->returningLists); | 		returningList = linitial(node->returningLists); | ||||||
| 		for (i = 0; i < mtstate->mt_num_partitions; i++) | 		for (i = 0; i < num_partitions; i++) | ||||||
| 		{ | 		{ | ||||||
| 			Relation	partrel; | 			Relation	partrel; | ||||||
| 			List	   *rlist; | 			List	   *rlist; | ||||||
| 
 | 
 | ||||||
| 			resultRelInfo = mtstate->mt_partitions[i]; | 			resultRelInfo = proute->partitions[i]; | ||||||
| 			partrel = resultRelInfo->ri_RelationDesc; | 			partrel = resultRelInfo->ri_RelationDesc; | ||||||
| 
 | 
 | ||||||
| 			/* varno = node->nominalRelation */ | 			/* varno = node->nominalRelation */ | ||||||
| @ -2372,32 +2359,9 @@ ExecEndModifyTable(ModifyTableState *node) | |||||||
| 														   resultRelInfo); | 														   resultRelInfo); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/* Close all the partitioned tables, leaf partitions, and their indices */ | ||||||
| 	 * Close all the partitioned tables, leaf partitions, and their indices | 	if (node->mt_partition_tuple_routing) | ||||||
| 	 * | 		ExecCleanupTupleRouting(node->mt_partition_tuple_routing); | ||||||
| 	 * Remember node->mt_partition_dispatch_info[0] corresponds to the root |  | ||||||
| 	 * partitioned table, which we must not try to close, because it is the |  | ||||||
| 	 * main target table of the query that will be closed by ExecEndPlan(). |  | ||||||
| 	 * Also, tupslot is NULL for the root partitioned table. |  | ||||||
| 	 */ |  | ||||||
| 	for (i = 1; i < node->mt_num_dispatch; i++) |  | ||||||
| 	{ |  | ||||||
| 		PartitionDispatch pd = node->mt_partition_dispatch_info[i]; |  | ||||||
| 
 |  | ||||||
| 		heap_close(pd->reldesc, NoLock); |  | ||||||
| 		ExecDropSingleTupleTableSlot(pd->tupslot); |  | ||||||
| 	} |  | ||||||
| 	for (i = 0; i < node->mt_num_partitions; i++) |  | ||||||
| 	{ |  | ||||||
| 		ResultRelInfo *resultRelInfo = node->mt_partitions[i]; |  | ||||||
| 
 |  | ||||||
| 		ExecCloseIndices(resultRelInfo); |  | ||||||
| 		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 | 	 * Free the exprcontext | ||||||
|  | |||||||
| @ -49,18 +49,47 @@ typedef struct PartitionDispatchData | |||||||
| 
 | 
 | ||||||
| typedef struct PartitionDispatchData *PartitionDispatch; | typedef struct PartitionDispatchData *PartitionDispatch; | ||||||
| 
 | 
 | ||||||
| extern void ExecSetupPartitionTupleRouting(ModifyTableState *mtstate, | /*-----------------------
 | ||||||
| 							   Relation rel, |  * PartitionTupleRouting - Encapsulates all information required to execute | ||||||
| 							   Index resultRTindex, |  * tuple-routing between partitions. | ||||||
| 							   EState *estate, |  * | ||||||
| 							   PartitionDispatch **pd, |  * partition_dispatch_info		Array of PartitionDispatch objects with one | ||||||
| 							   ResultRelInfo ***partitions, |  *								entry for every partitioned table in the | ||||||
| 							   TupleConversionMap ***tup_conv_maps, |  *								partition tree. | ||||||
| 							   TupleTableSlot **partition_tuple_slot, |  * num_dispatch					number of partitioned tables in the partition | ||||||
| 							   int *num_parted, int *num_partitions); |  *								tree (= length of partition_dispatch_info[]) | ||||||
|  |  * partitions					Array of ResultRelInfo* objects with one entry | ||||||
|  |  *								for every leaf partition in the partition tree. | ||||||
|  |  * num_partitions				Number of leaf partitions in the partition tree | ||||||
|  |  *								(= 'partitions' array length) | ||||||
|  |  * partition_tupconv_maps		Array of TupleConversionMap objects with one | ||||||
|  |  *								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			TupleTableSlot to be used to manipulate any | ||||||
|  |  *								given leaf partition's rowtype after that | ||||||
|  |  *								partition is chosen for insertion by | ||||||
|  |  *								tuple-routing. | ||||||
|  |  *----------------------- | ||||||
|  |  */ | ||||||
|  | typedef struct PartitionTupleRouting | ||||||
|  | { | ||||||
|  | 	PartitionDispatch *partition_dispatch_info; | ||||||
|  | 	int			num_dispatch; | ||||||
|  | 	ResultRelInfo **partitions; | ||||||
|  | 	int			num_partitions; | ||||||
|  | 	TupleConversionMap **partition_tupconv_maps; | ||||||
|  | 	TupleTableSlot *partition_tuple_slot; | ||||||
|  | } PartitionTupleRouting; | ||||||
|  | 
 | ||||||
|  | extern PartitionTupleRouting *ExecSetupPartitionTupleRouting(ModifyTableState *mtstate, | ||||||
|  | 							   Relation rel, Index resultRTindex, | ||||||
|  | 							   EState *estate); | ||||||
| extern int ExecFindPartition(ResultRelInfo *resultRelInfo, | extern int ExecFindPartition(ResultRelInfo *resultRelInfo, | ||||||
| 				  PartitionDispatch *pd, | 				  PartitionDispatch *pd, | ||||||
| 				  TupleTableSlot *slot, | 				  TupleTableSlot *slot, | ||||||
| 				  EState *estate); | 				  EState *estate); | ||||||
|  | extern void ExecCleanupTupleRouting(PartitionTupleRouting *proute); | ||||||
| 
 | 
 | ||||||
| #endif							/* EXECPARTITION_H */ | #endif							/* EXECPARTITION_H */ | ||||||
|  | |||||||
| @ -985,15 +985,8 @@ typedef struct ModifyTableState | |||||||
| 	TupleTableSlot *mt_existing;	/* slot to store existing target tuple in */ | 	TupleTableSlot *mt_existing;	/* slot to store existing target tuple in */ | ||||||
| 	List	   *mt_excludedtlist;	/* the excluded pseudo relation's tlist  */ | 	List	   *mt_excludedtlist;	/* the excluded pseudo relation's tlist  */ | ||||||
| 	TupleTableSlot *mt_conflproj;	/* CONFLICT ... SET ... projection target */ | 	TupleTableSlot *mt_conflproj;	/* CONFLICT ... SET ... projection target */ | ||||||
| 	struct PartitionDispatchData **mt_partition_dispatch_info; | 	struct PartitionTupleRouting *mt_partition_tuple_routing; | ||||||
| 	/* Tuple-routing support info */ | 	/* Tuple-routing support info */ | ||||||
| 	int			mt_num_dispatch;	/* Number of entries in the above array */ |  | ||||||
| 	int			mt_num_partitions;	/* Number of members in the following
 |  | ||||||
| 									 * arrays */ |  | ||||||
| 	ResultRelInfo **mt_partitions;	/* Per partition result relation pointers */ |  | ||||||
| 	TupleConversionMap **mt_partition_tupconv_maps; |  | ||||||
| 	/* Per partition tuple conversion map */ |  | ||||||
| 	TupleTableSlot *mt_partition_tuple_slot; |  | ||||||
| 	struct TransitionCaptureState *mt_transition_capture; | 	struct TransitionCaptureState *mt_transition_capture; | ||||||
| 	/* controls transition table population for specified operation */ | 	/* controls transition table population for specified operation */ | ||||||
| 	struct TransitionCaptureState *mt_oc_transition_capture; | 	struct TransitionCaptureState *mt_oc_transition_capture; | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user