diff options
Diffstat (limited to 'src/backend/executor')
-rw-r--r-- | src/backend/executor/execMain.c | 2 | ||||
-rw-r--r-- | src/backend/executor/execReplication.c | 4 | ||||
-rw-r--r-- | src/backend/executor/execSRF.c | 2 | ||||
-rw-r--r-- | src/backend/executor/execTuples.c | 85 | ||||
-rw-r--r-- | src/backend/executor/functions.c | 2 | ||||
-rw-r--r-- | src/backend/executor/nodeForeignscan.c | 2 | ||||
-rw-r--r-- | src/backend/executor/nodeHash.c | 24 | ||||
-rw-r--r-- | src/backend/executor/nodeHashjoin.c | 17 | ||||
-rw-r--r-- | src/backend/executor/nodeModifyTable.c | 26 | ||||
-rw-r--r-- | src/backend/executor/tqueue.c | 6 |
10 files changed, 108 insertions, 62 deletions
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index ba156f8c5fc..d10e533fd16 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -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 diff --git a/src/backend/executor/execReplication.c b/src/backend/executor/execReplication.c index 25ba93e03c3..071ba8762d4 100644 --- a/src/backend/executor/execReplication.c +++ b/src/backend/executor/execReplication.c @@ -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, diff --git a/src/backend/executor/execSRF.c b/src/backend/executor/execSRF.c index b97b8d797ec..3bffb0ea71f 100644 --- a/src/backend/executor/execSRF.c +++ b/src/backend/executor/execSRF.c @@ -521,7 +521,7 @@ restart: { /* We must return the whole tuple as a Datum. */ *isNull = false; - return ExecFetchSlotTupleDatum(fcache->funcResultSlot); + return ExecFetchSlotHeapTupleDatum(fcache->funcResultSlot); } else { diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c index 9f0d9daa829..391db672d1d 100644 --- a/src/backend/executor/execTuples.c +++ b/src/backend/executor/execTuples.c @@ -676,23 +676,27 @@ ExecCopySlotMinimalTuple(TupleTableSlot *slot) 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 @@ -700,6 +704,10 @@ ExecFetchSlotTuple(TupleTableSlot *slot) 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. @@ -779,40 +792,44 @@ ExecFetchSlotMinimalTuple(TupleTableSlot *slot) } /* -------------------------------- - * 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; } /* -------------------------------- diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c index 23545896d4d..f4dd5732198 100644 --- a/src/backend/executor/functions.c +++ b/src/backend/executor/functions.c @@ -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 { diff --git a/src/backend/executor/nodeForeignscan.c b/src/backend/executor/nodeForeignscan.c index 5d2cd0ed717..f7eef32f6fe 100644 --- a/src/backend/executor/nodeForeignscan.c +++ b/src/backend/executor/nodeForeignscan.c @@ -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); } diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c index a9f812d66b8..5a9f1ea3c55 100644 --- a/src/backend/executor/nodeHash.c +++ b/src/backend/executor/nodeHash.c @@ -1590,7 +1590,8 @@ ExecHashTableInsert(HashJoinTable hashtable, TupleTableSlot *slot, uint32 hashvalue) { - MinimalTuple tuple = ExecFetchSlotMinimalTuple(slot); + bool shouldFree; + MinimalTuple tuple = ExecFetchSlotMinimalTuple(slot, &shouldFree); int bucketno; int batchno; @@ -1664,6 +1665,9 @@ ExecHashTableInsert(HashJoinTable hashtable, 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; @@ -1723,6 +1728,9 @@ retry: 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); } /* diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c index 08a8bb3426c..d6a6ef770dd 100644 --- a/src/backend/executor/nodeHashjoin.c +++ b/src/backend/executor/nodeHashjoin.c @@ -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(); } diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index 6ef694d5a4a..a3ca336f2ac 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -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; @@ -274,7 +274,7 @@ ExecInsert(ModifyTableState *mtstate, * 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 @@ -315,7 +315,7 @@ ExecInsert(ModifyTableState *mtstate, return NULL; /* trigger might have changed tuple */ - tuple = ExecMaterializeSlot(slot); + tuple = ExecFetchSlotHeapTuple(slot, true, NULL); } /* INSTEAD OF ROW INSERT Triggers */ @@ -328,7 +328,7 @@ ExecInsert(ModifyTableState *mtstate, return NULL; /* trigger might have changed tuple */ - tuple = ExecMaterializeSlot(slot); + tuple = ExecFetchSlotHeapTuple(slot, true, NULL); newId = InvalidOid; } @@ -346,7 +346,7 @@ ExecInsert(ModifyTableState *mtstate, return NULL; /* FDW might have changed tuple */ - tuple = ExecMaterializeSlot(slot); + tuple = ExecFetchSlotHeapTuple(slot, true, NULL); /* * AFTER ROW Triggers or RETURNING expressions might reference the @@ -695,7 +695,7 @@ ExecDelete(ModifyTableState *mtstate, */ if (TTS_EMPTY(slot)) ExecStoreAllNullTuple(slot); - tuple = ExecMaterializeSlot(slot); + tuple = ExecFetchSlotHeapTuple(slot, true, NULL); tuple->t_tableOid = RelationGetRelid(resultRelationDesc); } else @@ -953,7 +953,7 @@ ExecUpdate(ModifyTableState *mtstate, * 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 @@ -972,7 +972,7 @@ ExecUpdate(ModifyTableState *mtstate, return NULL; /* trigger might have changed tuple */ - tuple = ExecMaterializeSlot(slot); + tuple = ExecFetchSlotHeapTuple(slot, true, NULL); } /* INSTEAD OF ROW UPDATE Triggers */ @@ -986,7 +986,7 @@ ExecUpdate(ModifyTableState *mtstate, return NULL; /* trigger might have changed tuple */ - tuple = ExecMaterializeSlot(slot); + tuple = ExecFetchSlotHeapTuple(slot, true, NULL); } else if (resultRelInfo->ri_FdwRoutine) { @@ -1002,7 +1002,7 @@ ExecUpdate(ModifyTableState *mtstate, return NULL; /* FDW might have changed tuple */ - tuple = ExecMaterializeSlot(slot); + tuple = ExecFetchSlotHeapTuple(slot, true, NULL); /* * AFTER ROW Triggers or RETURNING expressions might reference the @@ -1129,7 +1129,7 @@ lreplace:; else { slot = ExecFilterJunk(resultRelInfo->ri_junkFilter, epqslot); - tuple = ExecMaterializeSlot(slot); + tuple = ExecFetchSlotHeapTuple(slot, true, NULL); goto lreplace; } } @@ -1268,7 +1268,7 @@ 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 diff --git a/src/backend/executor/tqueue.c b/src/backend/executor/tqueue.c index ecdbe7f79f6..e47ef491928 100644 --- a/src/backend/executor/tqueue.c +++ b/src/backend/executor/tqueue.c @@ -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; |