index fd20aa96aa9b8a18e3cef7ac9f807ae811148d85..6f9c6e193fcce9035810b500636e15a59f85d3a9 100644 (file)
ExecStoreVirtualTuple(resultSlot);
/*
- * If we have any system columns to return, install them.
+ * If we have any system columns to return, materialize a heap tuple in the
+ * slot from column values set above and install system columns in that tuple.
*/
if (dmstate->hasSystemCols)
{
- HeapTuple resultTup = ExecMaterializeSlot(resultSlot);
+ HeapTuple resultTup = ExecFetchSlotHeapTuple(resultSlot, true, NULL);
/* ctid */
if (dmstate->ctidAttno)
index b58a74f4e3db9d8e8f30d35e08ca84814742faa3..a9471c5ef6a1a380a4988e9f24354fd909e423d0 100644 (file)
if (slot == NULL) /* "do nothing" */
skip_tuple = true;
else /* trigger might have changed tuple */
- tuple = ExecMaterializeSlot(slot);
+ tuple = ExecFetchSlotHeapTuple(slot, true, NULL);
}
if (!skip_tuple)
continue; /* next tuple please */
/* FDW might have changed tuple */
- tuple = ExecMaterializeSlot(slot);
+ tuple = ExecFetchSlotHeapTuple(slot, true, NULL);
/*
* AFTER ROW Triggers might reference the tableoid
index d5cb62da15bd1945c69982203f6d5064b73de903..d8002e5b776d1ccb2358696c1d10629e0d8f827d 100644 (file)
@@ -589,7 +589,7 @@ intorel_receive(TupleTableSlot *slot, DestReceiver *self)
* get the heap tuple out of the tuple table slot, making sure we have a
* writable copy
*/
- tuple = ExecMaterializeSlot(slot);
+ tuple = ExecCopySlotTuple(slot);
/*
* force assignment of new OID (see comments in ExecInsert)
index e1eb7c374b833402c20255db384529dc0b7cee34..9957c7074de076781c723b9f77c508f5c4992dc9 100644 (file)
@@ -484,7 +484,7 @@ transientrel_receive(TupleTableSlot *slot, DestReceiver *self)
* get the heap tuple out of the tuple table slot, making sure we have a
* writable copy
*/
- tuple = ExecMaterializeSlot(slot);
+ tuple = ExecCopySlotTuple(slot);
heap_insert(myState->transientrel,
tuple,
@@ -494,6 +494,9 @@ transientrel_receive(TupleTableSlot *slot, DestReceiver *self)
/* We know this is a newly created relation, so there are no indexes */
+ /* Free the copied tuple. */
+ heap_freetuple(tuple);
+
return true;
}
index ccb5706c1628d6de1dd7b54b3531699d06d3d424..d6f33ecbd04317be76b8cf4488386001ab58e7c5 100644 (file)
@@ -2517,7 +2517,8 @@ ExecBRInsertTriggers(EState *estate, ResultRelInfo *relinfo,
TupleTableSlot *slot)
{
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
- HeapTuple slottuple = ExecMaterializeSlot(slot);
+ bool should_free;
+ HeapTuple slottuple = ExecFetchSlotHeapTuple(slot, true, &should_free);
HeapTuple newtuple = slottuple;
HeapTuple oldtuple;
TriggerData LocTriggerData;
@@ -2556,7 +2557,11 @@ ExecBRInsertTriggers(EState *estate, ResultRelInfo *relinfo,
if (oldtuple != newtuple && oldtuple != slottuple)
heap_freetuple(oldtuple);
if (newtuple == NULL)
+ {
+ if (should_free)
+ heap_freetuple(slottuple);
return NULL; /* "do nothing" */
+ }
}
if (newtuple != slottuple)
@@ -2575,6 +2580,9 @@ ExecBRInsertTriggers(EState *estate, ResultRelInfo *relinfo,
ExecStoreHeapTuple(newtuple, newslot, false);
slot = newslot;
}
+
+ if (should_free)
+ heap_freetuple(slottuple);
return slot;
}
@@ -2598,7 +2606,8 @@ ExecIRInsertTriggers(EState *estate, ResultRelInfo *relinfo,
TupleTableSlot *slot)
{
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
- HeapTuple slottuple = ExecMaterializeSlot(slot);
+ bool should_free;
+ HeapTuple slottuple = ExecFetchSlotHeapTuple(slot, true, &should_free);
HeapTuple newtuple = slottuple;
HeapTuple oldtuple;
TriggerData LocTriggerData;
@@ -2637,7 +2646,11 @@ ExecIRInsertTriggers(EState *estate, ResultRelInfo *relinfo,
if (oldtuple != newtuple && oldtuple != slottuple)
heap_freetuple(oldtuple);
if (newtuple == NULL)
+ {
+ if (should_free)
+ heap_freetuple(slottuple);
return NULL; /* "do nothing" */
+ }
}
if (newtuple != slottuple)
@@ -2656,6 +2669,9 @@ ExecIRInsertTriggers(EState *estate, ResultRelInfo *relinfo,
ExecStoreHeapTuple(newtuple, newslot, false);
slot = newslot;
}
+
+ if (should_free)
+ heap_freetuple(slottuple);
return slot;
}
@@ -2976,7 +2992,7 @@ ExecBRUpdateTriggers(EState *estate, EPQState *epqstate,
TupleTableSlot *slot)
{
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
- HeapTuple slottuple = ExecMaterializeSlot(slot);
+ HeapTuple slottuple = ExecFetchSlotHeapTuple(slot, true, NULL);
HeapTuple newtuple = slottuple;
TriggerData LocTriggerData;
HeapTuple trigtuple;
@@ -3018,7 +3034,7 @@ ExecBRUpdateTriggers(EState *estate, EPQState *epqstate,
if (newSlot != NULL)
{
slot = ExecFilterJunk(relinfo->ri_junkFilter, newSlot);
- slottuple = ExecMaterializeSlot(slot);
+ slottuple = ExecFetchSlotHeapTuple(slot, true, NULL);
newtuple = slottuple;
}
@@ -3132,7 +3148,7 @@ ExecIRUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
HeapTuple trigtuple, TupleTableSlot *slot)
{
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
- HeapTuple slottuple = ExecMaterializeSlot(slot);
+ HeapTuple slottuple = ExecFetchSlotHeapTuple(slot, true, NULL);
HeapTuple newtuple = slottuple;
TriggerData LocTriggerData;
HeapTuple oldtuple;
case AFTER_TRIGGER_FDW_REUSE:
/*
- * Using ExecMaterializeSlot() rather than ExecFetchSlotTuple()
- * ensures that tg_trigtuple does not reference tuplestore memory.
- * (It is formally possible for the trigger function to queue
- * trigger events that add to the same tuplestore, which can push
- * other tuples out of memory.) The distinction is academic,
- * because we start with a minimal tuple that ExecFetchSlotTuple()
- * must materialize anyway.
+ * Materialize tuple in the slot so that tg_trigtuple does not
+ * reference tuplestore memory. (It is formally possible for the
+ * trigger function to queue trigger events that add to the same
+ * tuplestore, which can push other tuples out of memory.) The
+ * distinction is academic, because we start with a minimal tuple
+ * that is stored as a heap tuple, constructed in different memory
+ * context, in the slot anyway.
*/
- LocTriggerData.tg_trigtuple =
- ExecMaterializeSlot(trig_tuple_slot1);
+ LocTriggerData.tg_trigtuple = ExecFetchSlotHeapTuple(trig_tuple_slot1,
+ true, NULL);
LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
LocTriggerData.tg_newtuple =
((evtshared->ats_event & TRIGGER_EVENT_OPMASK) ==
TRIGGER_EVENT_UPDATE) ?
- ExecMaterializeSlot(trig_tuple_slot2) : NULL;
+ ExecFetchSlotHeapTuple(trig_tuple_slot2, true, NULL) : NULL;
LocTriggerData.tg_newtuplebuf = InvalidBuffer;
break;
index ba156f8c5fcf74e782af15ca3606ee3c12ff35ae..d10e533fd1663b100fe3dc558b96baad49d419cd 100644 (file)
@@ -2549,7 +2549,7 @@ EvalPlanQual(EState *estate, EPQState *epqstate,
* is to guard against early re-use of the EPQ query.
*/
if (!TupIsNull(slot))
- (void) ExecMaterializeSlot(slot);
+ ExecMaterializeSlot(slot);
/*
* Clear out the test tuple. This is needed in case the EPQ query is
index 25ba93e03c38f39a9a0523ac23f0d023faa58921..071ba8762d4f7feffb2774c2c37eb24bcdc70090 100644 (file)
@@ -418,7 +418,7 @@ ExecSimpleRelationInsert(EState *estate, TupleTableSlot *slot)
ExecPartitionCheck(resultRelInfo, slot, estate, true);
/* Materialize slot into a tuple that we can scribble upon. */
- tuple = ExecMaterializeSlot(slot);
+ tuple = ExecFetchSlotHeapTuple(slot, true, NULL);
/* OK, store the tuple and create index entries for it */
simple_heap_insert(rel, tuple);
@@ -485,7 +485,7 @@ ExecSimpleRelationUpdate(EState *estate, EPQState *epqstate,
ExecPartitionCheck(resultRelInfo, slot, estate, true);
/* Materialize slot into a tuple that we can scribble upon. */
- tuple = ExecMaterializeSlot(slot);
+ tuple = ExecFetchSlotHeapTuple(slot, true, NULL);
/* OK, update the tuple and index entries for it */
simple_heap_update(rel, &searchslot->tts_tuple->t_self,
index b97b8d797ec27dd0df65d6c6f212c72d3cfa0dc6..3bffb0ea71f38375cc1ee5e0b77f5caafd24d0b8 100644 (file)
{
/* We must return the whole tuple as a Datum. */
*isNull = false;
- return ExecFetchSlotTupleDatum(fcache->funcResultSlot);
+ return ExecFetchSlotHeapTupleDatum(fcache->funcResultSlot);
}
else
{
index 9f0d9daa8293d98daf2277a3d4022f81941e1ce6..391db672d1d6b5d2bb82d9a59cbcf3f51e19594a 100644 (file)
slot->tts_isnull);
}
-/* --------------------------------
- * ExecFetchSlotTuple
- * Fetch the slot's regular physical tuple.
- *
- * If the slot contains a virtual tuple, we convert it to physical
- * form. The slot retains ownership of the physical tuple.
- * If it contains a minimal tuple we convert to regular form and store
- * that in addition to the minimal tuple (not instead of, because
- * callers may hold pointers to Datums within the minimal tuple).
- *
- * The main difference between this and ExecMaterializeSlot() is that this
- * does not guarantee that the contained tuple is local storage.
- * Hence, the result must be treated as read-only.
- * --------------------------------
+/*
+ * ExecFetchSlotHeapTuple - fetch HeapTuple representing the slot's content
+ *
+ * The returned HeapTuple represents the slot's content as closely as
+ * possible.
+ *
+ * If materialize is true, the contents of the slots will be made independent
+ * from the underlying storage (i.e. all buffer pins are release, memory is
+ * allocated in the slot's context).
+ *
+ * If shouldFree is not-NULL it'll be set to true if the returned tuple has
+ * been allocated in the calling memory context, and must be freed by the
+ * caller (via explicit pfree() or a memory context reset).
+ *
+ * NB: If materialize is true, modifications of the returned tuple are
+ * allowed. But it depends on the type of the slot whether such modifications
+ * will also affect the slot's contents. While that is not the nicest
+ * behaviour, all such modifcations are in the process of being removed.
*/
HeapTuple
-ExecFetchSlotTuple(TupleTableSlot *slot)
+ExecFetchSlotHeapTuple(TupleTableSlot *slot, bool materialize, bool *shouldFree)
{
/*
* sanity checks
Assert(slot != NULL);
Assert(!TTS_EMPTY(slot));
+ /* will be used in the near future */
+ if (shouldFree)
+ *shouldFree = false;
+
/*
* If we have a regular physical tuple then just return it.
*/
@@ -722,7 +730,9 @@ ExecFetchSlotTuple(TupleTableSlot *slot)
/*
* Otherwise materialize the slot...
*/
- return ExecMaterializeSlot(slot);
+ ExecMaterializeSlot(slot);
+
+ return slot->tts_tuple;
}
/* --------------------------------
@@ -739,7 +749,7 @@ ExecFetchSlotTuple(TupleTableSlot *slot)
* --------------------------------
*/
MinimalTuple
-ExecFetchSlotMinimalTuple(TupleTableSlot *slot)
+ExecFetchSlotMinimalTuple(TupleTableSlot *slot, bool *shouldFree)
{
MemoryContext oldContext;
@@ -749,6 +759,9 @@ ExecFetchSlotMinimalTuple(TupleTableSlot *slot)
Assert(slot != NULL);
Assert(!TTS_EMPTY(slot));
+ /* will be used in the near future */
+ if (shouldFree)
+ *shouldFree = false;
/*
* If we have a minimal physical tuple (local or not) then just return it.
}
/* --------------------------------
- * ExecFetchSlotTupleDatum
+ * ExecFetchSlotHeapTupleDatum
* Fetch the slot's tuple as a composite-type Datum.
*
* The result is always freshly palloc'd in the caller's memory context.
* --------------------------------
*/
Datum
-ExecFetchSlotTupleDatum(TupleTableSlot *slot)
+ExecFetchSlotHeapTupleDatum(TupleTableSlot *slot)
{
HeapTuple tup;
TupleDesc tupdesc;
+ bool shouldFree;
+ Datum ret;
/* Fetch slot's contents in regular-physical-tuple form */
- tup = ExecFetchSlotTuple(slot);
+ tup = ExecFetchSlotHeapTuple(slot, false, &shouldFree);
tupdesc = slot->tts_tupleDescriptor;
/* Convert to Datum form */
- return heap_copy_tuple_as_datum(tup, tupdesc);
+ ret = heap_copy_tuple_as_datum(tup, tupdesc);
+
+ if (shouldFree)
+ pfree(tup);
+
+ return ret;
}
-/* --------------------------------
- * ExecMaterializeSlot
- * Force a slot into the "materialized" state.
+/* ExecMaterializeSlot - force a slot into the "materialized" state.
*
- * This causes the slot's tuple to be a local copy not dependent on
- * any external storage. A pointer to the contained tuple is returned.
+ * This causes the slot's tuple to be a local copy not dependent on any
+ * external storage (i.e. pointing into a Buffer, or having allocations in
+ * another memory context).
*
- * A typical use for this operation is to prepare a computed tuple
- * for being stored on disk. The original data may or may not be
- * virtual, but in any case we need a private copy for heap_insert
- * to scribble on.
- * --------------------------------
+ * A typical use for this operation is to prepare a computed tuple for being
+ * stored on disk. The original data may or may not be virtual, but in any
+ * case we need a private copy for heap_insert to scribble on.
*/
-HeapTuple
+void
ExecMaterializeSlot(TupleTableSlot *slot)
{
MemoryContext oldContext;
@@ -828,7 +845,7 @@ ExecMaterializeSlot(TupleTableSlot *slot)
* nothing to do.
*/
if (slot->tts_tuple && TTS_SHOULDFREE(slot))
- return slot->tts_tuple;
+ return;
/*
* Otherwise, copy or build a physical tuple, and store it into the slot.
@@ -868,8 +885,6 @@ ExecMaterializeSlot(TupleTableSlot *slot)
*/
if (!TTS_SHOULDFREEMIN(slot))
slot->tts_mintuple = NULL;
-
- return slot->tts_tuple;
}
/* --------------------------------
index 23545896d4dd89e039fd4e4b4a3f874bb662daf7..f4dd5732198bb55581c9af056155eee25a14ad79 100644 (file)
@@ -969,7 +969,7 @@ postquel_get_single_result(TupleTableSlot *slot,
{
/* We must return the whole tuple as a Datum. */
fcinfo->isnull = false;
- value = ExecFetchSlotTupleDatum(slot);
+ value = ExecFetchSlotHeapTupleDatum(slot);
}
else
{
index 5d2cd0ed717580a1317f088f4d4efcea5eca5361..f7eef32f6fef7b53e768f4553228cddebd3e38ef 100644 (file)
@@ -62,7 +62,7 @@ ForeignNext(ForeignScanState *node)
*/
if (plan->fsSystemCol && !TupIsNull(slot))
{
- HeapTuple tup = ExecMaterializeSlot(slot);
+ HeapTuple tup = ExecFetchSlotHeapTuple(slot, true, NULL);
tup->t_tableOid = RelationGetRelid(node->ss.ss_currentRelation);
}
index a9f812d66b8ead3bb14b587513fd398dc501b8d5..5a9f1ea3c550faaabb2e85df6599c2f5d50fee72 100644 (file)
TupleTableSlot *slot,
uint32 hashvalue)
{
- MinimalTuple tuple = ExecFetchSlotMinimalTuple(slot);
+ bool shouldFree;
+ MinimalTuple tuple = ExecFetchSlotMinimalTuple(slot, &shouldFree);
int bucketno;
int batchno;
hashvalue,
&hashtable->innerBatchFile[batchno]);
}
+
+ if (shouldFree)
+ heap_free_minimal_tuple(tuple);
}
/*
@@ -1675,7 +1679,8 @@ ExecParallelHashTableInsert(HashJoinTable hashtable,
TupleTableSlot *slot,
uint32 hashvalue)
{
- MinimalTuple tuple = ExecFetchSlotMinimalTuple(slot);
+ bool shouldFree;
+ MinimalTuple tuple = ExecFetchSlotMinimalTuple(slot, &shouldFree);
dsa_pointer shared;
int bucketno;
int batchno;
tuple);
}
++hashtable->batches[batchno].ntuples;
+
+ if (shouldFree)
+ heap_free_minimal_tuple(tuple);
}
/*
@@ -1736,7 +1744,8 @@ ExecParallelHashTableInsertCurrentBatch(HashJoinTable hashtable,
TupleTableSlot *slot,
uint32 hashvalue)
{
- MinimalTuple tuple = ExecFetchSlotMinimalTuple(slot);
+ bool shouldFree;
+ MinimalTuple tuple = ExecFetchSlotMinimalTuple(slot, &shouldFree);
HashJoinTuple hashTuple;
dsa_pointer shared;
int batchno;
@@ -1752,6 +1761,9 @@ ExecParallelHashTableInsertCurrentBatch(HashJoinTable hashtable,
HeapTupleHeaderClearMatch(HJTUPLE_MINTUPLE(hashTuple));
ExecParallelHashPushTuple(&hashtable->buckets.shared[bucketno],
hashTuple, shared);
+
+ if (shouldFree)
+ heap_free_minimal_tuple(tuple);
}
/*
@@ -2391,7 +2403,8 @@ ExecHashSkewTableInsert(HashJoinTable hashtable,
uint32 hashvalue,
int bucketNumber)
{
- MinimalTuple tuple = ExecFetchSlotMinimalTuple(slot);
+ bool shouldFree;
+ MinimalTuple tuple = ExecFetchSlotMinimalTuple(slot, &shouldFree);
HashJoinTuple hashTuple;
int hashTupleSize;
@@ -2419,6 +2432,9 @@ ExecHashSkewTableInsert(HashJoinTable hashtable,
/* Check we are not over the total spaceAllowed, either */
if (hashtable->spaceUsed > hashtable->spaceAllowed)
ExecHashIncreaseNumBatches(hashtable);
+
+ if (shouldFree)
+ heap_free_minimal_tuple(tuple);
}
/*
index 08a8bb3426c633a92a82527d1045a6ad212cca24..d6a6ef770dd201b2471f23f4e75d1c4eca244b3d 100644 (file)
@@ -389,16 +389,22 @@ ExecHashJoinImpl(PlanState *pstate, bool parallel)
if (batchno != hashtable->curbatch &&
node->hj_CurSkewBucketNo == INVALID_SKEW_BUCKET_NO)
{
+ bool shouldFree;
+ MinimalTuple mintuple = ExecFetchSlotMinimalTuple(outerTupleSlot,
+ &shouldFree);
+
/*
* Need to postpone this outer tuple to a later batch.
* Save it in the corresponding outer-batch file.
*/
Assert(parallel_state == NULL);
Assert(batchno > hashtable->curbatch);
- ExecHashJoinSaveTuple(ExecFetchSlotMinimalTuple(outerTupleSlot),
- hashvalue,
+ ExecHashJoinSaveTuple(mintuple, hashvalue,
&hashtable->outerBatchFile[batchno]);
+ if (shouldFree)
+ heap_free_minimal_tuple(mintuple);
+
/* Loop around, staying in HJ_NEED_NEW_OUTER state */
continue;
}
@@ -1404,11 +1410,16 @@ ExecParallelHashJoinPartitionOuter(HashJoinState *hjstate)
{
int batchno;
int bucketno;
+ bool shouldFree;
+ MinimalTuple mintup = ExecFetchSlotMinimalTuple(slot, &shouldFree);
ExecHashGetBucketAndBatch(hashtable, hashvalue, &bucketno,
&batchno);
sts_puttuple(hashtable->batches[batchno].outer_tuples,
- &hashvalue, ExecFetchSlotMinimalTuple(slot));
+ &hashvalue, mintup);
+
+ if (shouldFree)
+ heap_free_minimal_tuple(mintup);
}
CHECK_FOR_INTERRUPTS();
}
index 6ef694d5a4a636d9fc17b249f6b985916a427e83..a3ca336f2acdb090c7d5c65b3cc47cfaf9db1437 100644 (file)
@@ -175,7 +175,7 @@ ExecProcessReturning(ResultRelInfo *resultRelInfo,
* initialize t_tableOid before evaluating them.
*/
Assert(!TupIsNull(econtext->ecxt_scantuple));
- tuple = ExecMaterializeSlot(econtext->ecxt_scantuple);
+ tuple = ExecFetchSlotHeapTuple(econtext->ecxt_scantuple, true, NULL);
tuple->t_tableOid = RelationGetRelid(resultRelInfo->ri_RelationDesc);
}
econtext->ecxt_outertuple = planSlot;
* get the heap tuple out of the tuple table slot, making sure we have a
* writable copy
*/
- tuple = ExecMaterializeSlot(slot);
+ tuple = ExecFetchSlotHeapTuple(slot, true, NULL);
/*
* get information on the (current) result relation
return NULL;
/* trigger might have changed tuple */
- tuple = ExecMaterializeSlot(slot);
+ tuple = ExecFetchSlotHeapTuple(slot, true, NULL);
}
/* INSTEAD OF ROW INSERT Triggers */
return NULL;
/* trigger might have changed tuple */
- tuple = ExecMaterializeSlot(slot);
+ tuple = ExecFetchSlotHeapTuple(slot, true, NULL);
newId = InvalidOid;
}
return NULL;
/* FDW might have changed tuple */
- tuple = ExecMaterializeSlot(slot);
+ tuple = ExecFetchSlotHeapTuple(slot, true, NULL);
/*
* AFTER ROW Triggers or RETURNING expressions might reference the
*/
if (TTS_EMPTY(slot))
ExecStoreAllNullTuple(slot);
- tuple = ExecMaterializeSlot(slot);
+ tuple = ExecFetchSlotHeapTuple(slot, true, NULL);
tuple->t_tableOid = RelationGetRelid(resultRelationDesc);
}
else
* get the heap tuple out of the tuple table slot, making sure we have a
* writable copy
*/
- tuple = ExecMaterializeSlot(slot);
+ tuple = ExecFetchSlotHeapTuple(slot, true, NULL);
/*
* get information on the (current) result relation
return NULL;
/* trigger might have changed tuple */
- tuple = ExecMaterializeSlot(slot);
+ tuple = ExecFetchSlotHeapTuple(slot, true, NULL);
}
/* INSTEAD OF ROW UPDATE Triggers */
return NULL;
/* trigger might have changed tuple */
- tuple = ExecMaterializeSlot(slot);
+ tuple = ExecFetchSlotHeapTuple(slot, true, NULL);
}
else if (resultRelInfo->ri_FdwRoutine)
{
return NULL;
/* FDW might have changed tuple */
- tuple = ExecMaterializeSlot(slot);
+ tuple = ExecFetchSlotHeapTuple(slot, true, NULL);
/*
* AFTER ROW Triggers or RETURNING expressions might reference the
else
{
slot = ExecFilterJunk(resultRelInfo->ri_junkFilter, epqslot);
- tuple = ExecMaterializeSlot(slot);
+ tuple = ExecFetchSlotHeapTuple(slot, true, NULL);
goto lreplace;
}
}
{
*tupleid = hufd.ctid;
slot = ExecFilterJunk(resultRelInfo->ri_junkFilter, epqslot);
- tuple = ExecMaterializeSlot(slot);
+ tuple = ExecFetchSlotHeapTuple(slot, true, NULL);
goto lreplace;
}
}
@@ -1739,7 +1739,7 @@ ExecPrepareTupleRouting(ModifyTableState *mtstate,
estate->es_result_relation_info = partrel;
/* Get the heap tuple out of the given slot. */
- tuple = ExecMaterializeSlot(slot);
+ tuple = ExecFetchSlotHeapTuple(slot, true, NULL);
/*
* If we're capturing transition tuples, we might need to convert from the
index ecdbe7f79f61dc33b930fd77c134d45ccfaede69..e47ef491928ea8c529418dde343c240fed8075a6 100644 (file)
@@ -56,11 +56,15 @@ tqueueReceiveSlot(TupleTableSlot *slot, DestReceiver *self)
TQueueDestReceiver *tqueue = (TQueueDestReceiver *) self;
HeapTuple tuple;
shm_mq_result result;
+ bool should_free;
/* Send the tuple itself. */
- tuple = ExecMaterializeSlot(slot);
+ tuple = ExecFetchSlotHeapTuple(slot, true, &should_free);
result = shm_mq_send(tqueue->queue, tuple->t_len, tuple->t_data, false);
+ if (should_free)
+ heap_freetuple(tuple);
+
/* Check for failure. */
if (result == SHM_MQ_DETACHED)
return false;
index b41b400ef186f7d9d4195a0d31848695d7d7e78e..8bfa73c30ea2d3df1ac8e4e8c42bcbf7ff5e46e6 100644 (file)
@@ -185,10 +185,11 @@ extern TupleTableSlot *ExecStoreVirtualTuple(TupleTableSlot *slot);
extern TupleTableSlot *ExecStoreAllNullTuple(TupleTableSlot *slot);
extern HeapTuple ExecCopySlotTuple(TupleTableSlot *slot);
extern MinimalTuple ExecCopySlotMinimalTuple(TupleTableSlot *slot);
-extern HeapTuple ExecFetchSlotTuple(TupleTableSlot *slot);
-extern MinimalTuple ExecFetchSlotMinimalTuple(TupleTableSlot *slot);
-extern Datum ExecFetchSlotTupleDatum(TupleTableSlot *slot);
-extern HeapTuple ExecMaterializeSlot(TupleTableSlot *slot);
+extern HeapTuple ExecFetchSlotHeapTuple(TupleTableSlot *slot, bool materialize, bool *shoulFree);
+extern MinimalTuple ExecFetchSlotMinimalTuple(TupleTableSlot *slot,
+ bool *shouldFree);
+extern Datum ExecFetchSlotHeapTupleDatum(TupleTableSlot *slot);
+extern void ExecMaterializeSlot(TupleTableSlot *slot);
extern TupleTableSlot *ExecCopySlot(TupleTableSlot *dstslot,
TupleTableSlot *srcslot);
extern void slot_getmissingattrs(TupleTableSlot *slot, int startAttNum,