commit 501cc0544c0317fa2718793f3e2d0aa35e7f936f Author: Amit Khandekar Date: Thu Aug 16 15:08:52 2018 +0530 Slotification of partition tuples. ConvertPartitionTupleSlot() and (in some cases) do_convert_tuple() both deal with tuples of partitions. At all such places, avoid fetching of tuples, and instead do the conversion rather using slot directly. There are other places where do_convert_tuple() deals with non-partition tuples. This will be worked on separately. 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 276a262..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,11 +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 cd43af1..1742cd4 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; @@ -1937,10 +1936,8 @@ ExecPartitionCheckEmitError(ResultRelInfo *resultRelInfo, map = convert_tuples_by_name(old_tupdesc, tupdesc, gettext_noop("could not convert row type")); /* Input slot might be of a partition, which has a fixed tupdesc. */ - slot = MakeTupleTableSlot(tupdesc); if (map != NULL) - tuple = do_convert_tuple(tuple, map); - ExecStoreTuple(tuple, slot, InvalidBuffer, false); + slot = ConvertTupleSlot(map, slot, MakeTupleTableSlot(tupdesc)); } insertedCols = GetInsertedColumns(resultRelInfo, estate); @@ -2006,7 +2003,6 @@ ExecConstraints(ResultRelInfo *resultRelInfo, */ if (resultRelInfo->ri_PartitionRoot) { - HeapTuple tuple = ExecFetchSlotTuple(slot); TupleConversionMap *map; rel = resultRelInfo->ri_PartitionRoot; @@ -2018,10 +2014,9 @@ ExecConstraints(ResultRelInfo *resultRelInfo, * Input slot might be partition-specific, which has a * fixed tupdesc. */ - slot = MakeTupleTableSlot(tupdesc); if (map != NULL) - tuple = do_convert_tuple(tuple, map); - ExecStoreTuple(tuple, slot, InvalidBuffer, false); + slot = ConvertTupleSlot(map, slot, + MakeTupleTableSlot(tupdesc)); } insertedCols = GetInsertedColumns(resultRelInfo, estate); @@ -2055,7 +2050,6 @@ ExecConstraints(ResultRelInfo *resultRelInfo, /* See the comment above. */ if (resultRelInfo->ri_PartitionRoot) { - HeapTuple tuple = ExecFetchSlotTuple(slot); TupleDesc old_tupdesc = RelationGetDescr(rel); TupleConversionMap *map; @@ -2068,10 +2062,9 @@ ExecConstraints(ResultRelInfo *resultRelInfo, * Input slot might be partition-specific, which has a * fixed tupdesc. */ - slot = MakeTupleTableSlot(tupdesc); if (map != NULL) - tuple = do_convert_tuple(tuple, map); - ExecStoreTuple(tuple, slot, InvalidBuffer, false); + slot = ConvertTupleSlot(map, slot, + MakeTupleTableSlot(tupdesc)); } insertedCols = GetInsertedColumns(resultRelInfo, estate); @@ -2163,7 +2156,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; @@ -2176,10 +2168,9 @@ ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo, * Input slot might be partition-specific, which has a * fixed tupdesc. */ - slot = MakeTupleTableSlot(tupdesc); if (map != NULL) - 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 03779db..a57277f 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); - } } } @@ -805,36 +789,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 9b4cd36..65cd53a 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -1162,13 +1162,9 @@ 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 * into the root. @@ -1801,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 72623d4..8469e2a 100644 --- a/src/include/executor/execPartition.h +++ b/src/include/executor/execPartition.h @@ -222,11 +222,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,