diff --git a/src/backend/access/common/tupconvert.c b/src/backend/access/common/tupconvert.c index 3bc67b8..fbcfa85 100644 --- a/src/backend/access/common/tupconvert.c +++ b/src/backend/access/common/tupconvert.c @@ -22,6 +22,7 @@ #include "access/htup_details.h" #include "access/tupconvert.h" +#include "executor/tuptable.h" #include "utils/builtins.h" @@ -406,6 +407,60 @@ do_convert_tuple(HeapTuple tuple, TupleConversionMap *map) } /* + * Perform conversion of a tuple slot according to the map. + */ +TupleTableSlot * +ConvertTupleSlot(TupleConversionMap *map, + TupleTableSlot *in_slot, TupleTableSlot *out_slot) +{ + AttrNumber *attrMap = map->attrMap; + Datum *invalues; + bool *inisnull; + Datum *outvalues; + bool *outisnull; + int outnatts = map->outdesc->natts; + int i; + + /* Sanity checks */ + Assert(in_slot->tts_tupleDescriptor != NULL && + out_slot->tts_tupleDescriptor != NULL); + Assert(in_slot->tts_values != NULL && out_slot->tts_values != NULL); + + /* Extract all the values of the in slot. */ + slot_getallattrs(in_slot); + + /* Before doing the mapping, clear any old contents from the out slot */ + ExecClearTuple(out_slot); + + invalues = in_slot->tts_values; + inisnull = in_slot->tts_isnull; + outvalues = out_slot->tts_values; + outisnull = out_slot->tts_isnull; + + /* Transpose into proper fields of the out slot. */ + for (i = 0; i < outnatts; i++) + { + int j = attrMap[i] - 1; + + /* attrMap[i] == 0 means it's a NULL datum. */ + if (j == -1) + { + outvalues[i] = (Datum) 0; + outisnull[i] = true; + } + else + { + outvalues[i] = invalues[j]; + outisnull[i] = inisnull[j]; + } + } + + ExecStoreVirtualTuple(out_slot); + + return out_slot; +} + +/* * Free a TupleConversionMap structure. */ void diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index f61db3e..9084e9c 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -31,6 +31,7 @@ #include "commands/trigger.h" #include "executor/execPartition.h" #include "executor/executor.h" +#include "executor/tuptable.h" #include "foreign/fdwapi.h" #include "libpq/libpq.h" #include "libpq/pqformat.h" @@ -2869,12 +2870,21 @@ CopyFrom(CopyState cstate) if (map != NULL) { TupleTableSlot *new_slot; + MemoryContext oldcontext; Assert(proute->partition_tuple_slots != NULL && proute->partition_tuple_slots[leaf_part_index] != NULL); new_slot = proute->partition_tuple_slots[leaf_part_index]; - tuple = ConvertPartitionTupleSlot(map, tuple, new_slot, &slot, - false); + slot = ConvertTupleSlot(map, slot, new_slot); + + /* + * Get the tuple in the per-tuple context. Also, we cannot call + * ExecMaterializeSlot(), otherwise the tuple will get freed + * while storing the next tuple. + */ + oldcontext = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate)); + tuple = ExecCopySlotTuple(slot); + MemoryContextSwitchTo(oldcontext); } tuple->t_tableOid = RelationGetRelid(resultRelInfo->ri_RelationDesc); diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 415670e..ecdf7f2 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -1927,7 +1927,6 @@ ExecPartitionCheckEmitError(ResultRelInfo *resultRelInfo, */ if (resultRelInfo->ri_PartitionRoot) { - HeapTuple tuple = ExecFetchSlotTuple(slot); TupleDesc old_tupdesc = RelationGetDescr(rel); TupleConversionMap *map; @@ -1936,16 +1935,12 @@ ExecPartitionCheckEmitError(ResultRelInfo *resultRelInfo, /* a reverse map */ map = convert_tuples_by_name(old_tupdesc, tupdesc, gettext_noop("could not convert row type")); + /* + * Partition-specific slot's tupdesc can't be changed, so allocate a + * new one. + */ if (map != NULL) - { - /* - * Partition-specific slot's tupdesc can't be changed, so allocate - * a new one. - */ - slot = MakeTupleTableSlot(tupdesc); - tuple = do_convert_tuple(tuple, map); - ExecStoreTuple(tuple, slot, InvalidBuffer, false); - } + slot = ConvertTupleSlot(map, slot, MakeTupleTableSlot(tupdesc)); } insertedCols = GetInsertedColumns(resultRelInfo, estate); @@ -2011,7 +2006,6 @@ ExecConstraints(ResultRelInfo *resultRelInfo, */ if (resultRelInfo->ri_PartitionRoot) { - HeapTuple tuple = ExecFetchSlotTuple(slot); TupleConversionMap *map; rel = resultRelInfo->ri_PartitionRoot; @@ -2019,16 +2013,13 @@ ExecConstraints(ResultRelInfo *resultRelInfo, /* a reverse map */ map = convert_tuples_by_name(orig_tupdesc, tupdesc, gettext_noop("could not convert row type")); + /* + * Partition-specific slot's tupdesc can't be changed, so + * allocate a new one. + */ if (map != NULL) - { - /* - * Partition-specific slot's tupdesc can't be changed, - * so allocate a new one. - */ - slot = MakeTupleTableSlot(tupdesc); - tuple = do_convert_tuple(tuple, map); - ExecStoreTuple(tuple, slot, InvalidBuffer, false); - } + slot = ConvertTupleSlot(map, slot, + MakeTupleTableSlot(tupdesc)); } insertedCols = GetInsertedColumns(resultRelInfo, estate); @@ -2062,7 +2053,6 @@ ExecConstraints(ResultRelInfo *resultRelInfo, /* See the comment above. */ if (resultRelInfo->ri_PartitionRoot) { - HeapTuple tuple = ExecFetchSlotTuple(slot); TupleDesc old_tupdesc = RelationGetDescr(rel); TupleConversionMap *map; @@ -2071,16 +2061,13 @@ ExecConstraints(ResultRelInfo *resultRelInfo, /* a reverse map */ map = convert_tuples_by_name(old_tupdesc, tupdesc, gettext_noop("could not convert row type")); + /* + * Partition-specific slot's tupdesc can't be changed, so + * allocate a new one. + */ if (map != NULL) - { - /* - * Partition-specific slot's tupdesc can't be changed, - * so allocate a new one. - */ - slot = MakeTupleTableSlot(tupdesc); - tuple = do_convert_tuple(tuple, map); - ExecStoreTuple(tuple, slot, InvalidBuffer, false); - } + slot = ConvertTupleSlot(map, slot, + MakeTupleTableSlot(tupdesc)); } insertedCols = GetInsertedColumns(resultRelInfo, estate); @@ -2172,7 +2159,6 @@ ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo, /* See the comment in ExecConstraints(). */ if (resultRelInfo->ri_PartitionRoot) { - HeapTuple tuple = ExecFetchSlotTuple(slot); TupleDesc old_tupdesc = RelationGetDescr(rel); TupleConversionMap *map; @@ -2181,16 +2167,13 @@ ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo, /* a reverse map */ map = convert_tuples_by_name(old_tupdesc, tupdesc, gettext_noop("could not convert row type")); + /* + * Partition-specific slot's tupdesc can't be changed, + * so allocate a new one. + */ if (map != NULL) - { - /* - * Partition-specific slot's tupdesc can't be - * changed, so allocate a new one. - */ - slot = MakeTupleTableSlot(tupdesc); - tuple = do_convert_tuple(tuple, map); - ExecStoreTuple(tuple, slot, InvalidBuffer, false); - } + slot = ConvertTupleSlot(map, slot, + MakeTupleTableSlot(tupdesc)); } insertedCols = GetInsertedColumns(resultRelInfo, estate); diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c index 2af7599..6c9b8f9 100644 --- a/src/backend/executor/execPartition.c +++ b/src/backend/executor/execPartition.c @@ -190,7 +190,6 @@ ExecFindPartition(ResultRelInfo *resultRelInfo, PartitionDispatch *pd, TupleTableSlot *ecxt_scantuple_old = ecxt->ecxt_scantuple; TupleTableSlot *myslot = NULL; MemoryContext oldcxt; - HeapTuple tuple; /* use per-tuple context here to avoid leaking memory */ oldcxt = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate)); @@ -203,7 +202,6 @@ ExecFindPartition(ResultRelInfo *resultRelInfo, PartitionDispatch *pd, ExecPartitionCheck(resultRelInfo, slot, estate, true); /* start with the root partitioned table */ - tuple = ExecFetchSlotTuple(slot); dispatch = pd[0]; while (true) { @@ -218,11 +216,7 @@ ExecFindPartition(ResultRelInfo *resultRelInfo, PartitionDispatch *pd, */ myslot = dispatch->tupslot; if (myslot != NULL && map != NULL) - { - tuple = do_convert_tuple(tuple, map); - ExecStoreTuple(tuple, myslot, InvalidBuffer, true); - slot = myslot; - } + slot = ConvertTupleSlot(map, slot, myslot); /* * Extract partition key from tuple. Expression evaluation machinery @@ -267,16 +261,6 @@ ExecFindPartition(ResultRelInfo *resultRelInfo, PartitionDispatch *pd, { /* move down one level */ dispatch = pd[-dispatch->indexes[cur_index]]; - - /* - * Release the dedicated slot, if it was used. Create a copy of - * the tuple first, for the next iteration. - */ - if (slot == myslot) - { - tuple = ExecCopySlotTuple(myslot); - ExecClearTuple(myslot); - } } } @@ -807,36 +791,6 @@ TupConvMapForLeaf(PartitionTupleRouting *proute, } /* - * ConvertPartitionTupleSlot -- convenience function for tuple conversion. - * The tuple, if converted, is stored in new_slot, and *p_my_slot is - * updated to point to it. new_slot typically should be one of the - * dedicated partition tuple slots. If map is NULL, *p_my_slot is not changed. - * - * Returns the converted tuple, unless map is NULL, in which case original - * tuple is returned unmodified. - */ -HeapTuple -ConvertPartitionTupleSlot(TupleConversionMap *map, - HeapTuple tuple, - TupleTableSlot *new_slot, - TupleTableSlot **p_my_slot, - bool shouldFree) -{ - Assert(map != NULL && new_slot != NULL); - - tuple = do_convert_tuple(tuple, map); - - /* - * Change the partition tuple slot descriptor, as per converted tuple. - */ - *p_my_slot = new_slot; - Assert(new_slot != NULL); - ExecStoreTuple(tuple, new_slot, InvalidBuffer, shouldFree); - - return tuple; -} - -/* * ExecCleanupTupleRouting -- Clean up objects allocated for partition tuple * routing. * diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index e4b2d37..65cd53a 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -1162,11 +1162,8 @@ lreplace:; Assert(map_index >= 0 && map_index < mtstate->mt_nplans); tupconv_map = tupconv_map_for_subplan(mtstate, map_index); if (tupconv_map != NULL) - tuple = ConvertPartitionTupleSlot(tupconv_map, - tuple, - proute->root_tuple_slot, - &slot, - true); + slot = ConvertTupleSlot(tupconv_map, + slot, proute->root_tuple_slot); /* * Prepare for tuple routing, making it look like we're inserting @@ -1800,7 +1797,7 @@ ExecPrepareTupleRouting(ModifyTableState *mtstate, Assert(proute->partition_tuple_slots != NULL && proute->partition_tuple_slots[partidx] != NULL); new_slot = proute->partition_tuple_slots[partidx]; - ConvertPartitionTupleSlot(map, tuple, new_slot, &slot, true); + slot = ConvertTupleSlot(map, slot, new_slot); } /* Initialize information needed to handle ON CONFLICT DO UPDATE. */ diff --git a/src/include/access/tupconvert.h b/src/include/access/tupconvert.h index 66c0ed0..7a453fe 100644 --- a/src/include/access/tupconvert.h +++ b/src/include/access/tupconvert.h @@ -16,6 +16,7 @@ #include "access/htup.h" #include "access/tupdesc.h" +#include "executor/tuptable.h" typedef struct TupleConversionMap @@ -44,6 +45,9 @@ extern AttrNumber *convert_tuples_by_name_map(TupleDesc indesc, extern HeapTuple do_convert_tuple(HeapTuple tuple, TupleConversionMap *map); +extern TupleTableSlot *ConvertTupleSlot(TupleConversionMap *map, + TupleTableSlot *in_slot, TupleTableSlot *out_slot); + extern void free_conversion_map(TupleConversionMap *map); #endif /* TUPCONVERT_H */ diff --git a/src/include/executor/execPartition.h b/src/include/executor/execPartition.h index c2a2dc5..13a213e 100644 --- a/src/include/executor/execPartition.h +++ b/src/include/executor/execPartition.h @@ -219,11 +219,6 @@ extern void ExecInitRoutingInfo(ModifyTableState *mtstate, extern void ExecSetupChildParentMapForLeaf(PartitionTupleRouting *proute); extern TupleConversionMap *TupConvMapForLeaf(PartitionTupleRouting *proute, ResultRelInfo *rootRelInfo, int leaf_index); -extern HeapTuple ConvertPartitionTupleSlot(TupleConversionMap *map, - HeapTuple tuple, - TupleTableSlot *new_slot, - TupleTableSlot **p_my_slot, - bool shouldFree); extern void ExecCleanupTupleRouting(ModifyTableState *mtstate, PartitionTupleRouting *proute); extern PartitionPruneState *ExecCreatePartitionPruneState(PlanState *planstate,