diff options
Diffstat (limited to 'src/backend/executor')
-rw-r--r-- | src/backend/executor/execIndexing.c | 2 | ||||
-rw-r--r-- | src/backend/executor/execMain.c | 8 | ||||
-rw-r--r-- | src/backend/executor/execPartition.c | 4 | ||||
-rw-r--r-- | src/backend/executor/execReplication.c | 4 | ||||
-rw-r--r-- | src/backend/executor/execScan.c | 4 | ||||
-rw-r--r-- | src/backend/executor/execTuples.c | 124 | ||||
-rw-r--r-- | src/backend/executor/nodeAgg.c | 7 | ||||
-rw-r--r-- | src/backend/executor/nodeBitmapHeapscan.c | 7 | ||||
-rw-r--r-- | src/backend/executor/nodeGather.c | 8 | ||||
-rw-r--r-- | src/backend/executor/nodeGatherMerge.c | 9 | ||||
-rw-r--r-- | src/backend/executor/nodeIndexonlyscan.c | 2 | ||||
-rw-r--r-- | src/backend/executor/nodeIndexscan.c | 20 | ||||
-rw-r--r-- | src/backend/executor/nodeModifyTable.c | 4 | ||||
-rw-r--r-- | src/backend/executor/nodeSamplescan.c | 7 | ||||
-rw-r--r-- | src/backend/executor/nodeSeqscan.c | 11 | ||||
-rw-r--r-- | src/backend/executor/nodeSetOp.c | 7 | ||||
-rw-r--r-- | src/backend/executor/nodeTidscan.c | 16 |
17 files changed, 135 insertions, 109 deletions
diff --git a/src/backend/executor/execIndexing.c b/src/backend/executor/execIndexing.c index 903076ee3c4..9927ad70e66 100644 --- a/src/backend/executor/execIndexing.c +++ b/src/backend/executor/execIndexing.c @@ -750,7 +750,7 @@ retry: * Extract the index column values and isnull flags from the existing * tuple. */ - ExecStoreTuple(tup, existing_slot, InvalidBuffer, false); + ExecStoreHeapTuple(tup, existing_slot, false); FormIndexDatum(indexInfo, existing_slot, estate, existing_values, existing_isnull); diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 04f14c91787..5443cbf67db 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -1957,7 +1957,7 @@ ExecPartitionCheckEmitError(ResultRelInfo *resultRelInfo, { tuple = do_convert_tuple(tuple, map); ExecSetSlotDescriptor(slot, tupdesc); - ExecStoreTuple(tuple, slot, InvalidBuffer, false); + ExecStoreHeapTuple(tuple, slot, false); } } @@ -2036,7 +2036,7 @@ ExecConstraints(ResultRelInfo *resultRelInfo, { tuple = do_convert_tuple(tuple, map); ExecSetSlotDescriptor(slot, tupdesc); - ExecStoreTuple(tuple, slot, InvalidBuffer, false); + ExecStoreHeapTuple(tuple, slot, false); } } @@ -2084,7 +2084,7 @@ ExecConstraints(ResultRelInfo *resultRelInfo, { tuple = do_convert_tuple(tuple, map); ExecSetSlotDescriptor(slot, tupdesc); - ExecStoreTuple(tuple, slot, InvalidBuffer, false); + ExecStoreHeapTuple(tuple, slot, false); } } @@ -2190,7 +2190,7 @@ ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo, { tuple = do_convert_tuple(tuple, map); ExecSetSlotDescriptor(slot, tupdesc); - ExecStoreTuple(tuple, slot, InvalidBuffer, false); + ExecStoreHeapTuple(tuple, slot, false); } } diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c index 38ecc4192ee..ec7a5267c34 100644 --- a/src/backend/executor/execPartition.c +++ b/src/backend/executor/execPartition.c @@ -258,7 +258,7 @@ ExecFindPartition(ResultRelInfo *resultRelInfo, PartitionDispatch *pd, if (myslot != NULL && map != NULL) { tuple = do_convert_tuple(tuple, map); - ExecStoreTuple(tuple, myslot, InvalidBuffer, true); + ExecStoreHeapTuple(tuple, myslot, true); slot = myslot; } @@ -842,7 +842,7 @@ ConvertPartitionTupleSlot(TupleConversionMap *map, *p_my_slot = new_slot; Assert(new_slot != NULL); ExecSetSlotDescriptor(new_slot, map->outdesc); - ExecStoreTuple(tuple, new_slot, InvalidBuffer, shouldFree); + ExecStoreHeapTuple(tuple, new_slot, shouldFree); return tuple; } diff --git a/src/backend/executor/execReplication.c b/src/backend/executor/execReplication.c index 9a7dedf5aa2..25ba93e03c3 100644 --- a/src/backend/executor/execReplication.c +++ b/src/backend/executor/execReplication.c @@ -146,7 +146,7 @@ retry: if ((scantuple = index_getnext(scan, ForwardScanDirection)) != NULL) { found = true; - ExecStoreTuple(scantuple, outslot, InvalidBuffer, false); + ExecStoreHeapTuple(scantuple, outslot, false); ExecMaterializeSlot(outslot); xwait = TransactionIdIsValid(snap.xmin) ? @@ -310,7 +310,7 @@ retry: continue; found = true; - ExecStoreTuple(scantuple, outslot, InvalidBuffer, false); + ExecStoreHeapTuple(scantuple, outslot, false); ExecMaterializeSlot(outslot); xwait = TransactionIdIsValid(snap.xmin) ? diff --git a/src/backend/executor/execScan.c b/src/backend/executor/execScan.c index f84a3fb0dbc..233cc280608 100644 --- a/src/backend/executor/execScan.c +++ b/src/backend/executor/execScan.c @@ -78,8 +78,8 @@ ExecScanFetch(ScanState *node, return ExecClearTuple(slot); /* Store test tuple in the plan node's scan slot */ - ExecStoreTuple(estate->es_epqTuple[scanrelid - 1], - slot, InvalidBuffer, false); + ExecStoreHeapTuple(estate->es_epqTuple[scanrelid - 1], + slot, false); /* Check if it meets the access-method conditions */ if (!(*recheckMtd) (node, slot)) diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c index c45dc246f68..573677af725 100644 --- a/src/backend/executor/execTuples.c +++ b/src/backend/executor/execTuples.c @@ -26,10 +26,10 @@ * * During ExecutorRun() * ---------------- - * - SeqNext() calls ExecStoreTuple() to place the tuple returned - * by the access methods into the scan tuple slot. + * - SeqNext() calls ExecStoreBufferHeapTuple() to place the tuple + * returned by the access methods into the scan tuple slot. * - * - ExecSeqScan() calls ExecStoreTuple() to take the result + * - ExecSeqScan() calls ExecStoreHeapTuple() to take the result * tuple from ExecProject() and place it into the result tuple slot. * * - ExecutePlan() calls the output function. @@ -287,48 +287,88 @@ ExecSetSlotDescriptor(TupleTableSlot *slot, /* slot to change */ } /* -------------------------------- - * ExecStoreTuple + * ExecStoreHeapTuple * - * This function is used to store a physical tuple into a specified + * This function is used to store an on-the-fly physical tuple into a specified * slot in the tuple table. * * tuple: tuple to store * slot: slot to store it in - * buffer: disk buffer if tuple is in a disk page, else InvalidBuffer * shouldFree: true if ExecClearTuple should pfree() the tuple * when done with it * - * If 'buffer' is not InvalidBuffer, the tuple table code acquires a pin - * on the buffer which is held until the slot is cleared, so that the tuple - * won't go away on us. + * shouldFree is normally set 'true' for tuples constructed on-the-fly. But it + * can be 'false' when the referenced tuple is held in a tuple table slot + * belonging to a lower-level executor Proc node. In this case the lower-level + * slot retains ownership and responsibility for eventually releasing the + * tuple. When this method is used, we must be certain that the upper-level + * Proc node will lose interest in the tuple sooner than the lower-level one + * does! If you're not certain, copy the lower-level tuple with heap_copytuple + * and let the upper-level table slot assume ownership of the copy! * - * shouldFree is normally set 'true' for tuples constructed on-the-fly. - * It must always be 'false' for tuples that are stored in disk pages, - * since we don't want to try to pfree those. + * Return value is just the passed-in slot pointer. + * -------------------------------- + */ +TupleTableSlot * +ExecStoreHeapTuple(HeapTuple tuple, + TupleTableSlot *slot, + bool shouldFree) +{ + /* + * sanity checks + */ + Assert(tuple != NULL); + Assert(slot != NULL); + Assert(slot->tts_tupleDescriptor != NULL); + + /* + * Free any old physical tuple belonging to the slot. + */ + if (slot->tts_shouldFree) + heap_freetuple(slot->tts_tuple); + if (slot->tts_shouldFreeMin) + heap_free_minimal_tuple(slot->tts_mintuple); + + /* + * Store the new tuple into the specified slot. + */ + slot->tts_isempty = false; + slot->tts_shouldFree = shouldFree; + slot->tts_shouldFreeMin = false; + slot->tts_tuple = tuple; + slot->tts_mintuple = NULL; + + /* Mark extracted state invalid */ + slot->tts_nvalid = 0; + + /* Unpin any buffer pinned by the slot. */ + if (BufferIsValid(slot->tts_buffer)) + ReleaseBuffer(slot->tts_buffer); + slot->tts_buffer = InvalidBuffer; + + return slot; +} + +/* -------------------------------- + * ExecStoreBufferHeapTuple * - * Another case where it is 'false' is when the referenced tuple is held - * in a tuple table slot belonging to a lower-level executor Proc node. - * In this case the lower-level slot retains ownership and responsibility - * for eventually releasing the tuple. When this method is used, we must - * be certain that the upper-level Proc node will lose interest in the tuple - * sooner than the lower-level one does! If you're not certain, copy the - * lower-level tuple with heap_copytuple and let the upper-level table - * slot assume ownership of the copy! + * This function is used to store an on-disk physical tuple from a buffer + * into a specified slot in the tuple table. * - * Return value is just the passed-in slot pointer. + * tuple: tuple to store + * slot: slot to store it in + * buffer: disk buffer if tuple is in a disk page, else InvalidBuffer + * + * The tuple table code acquires a pin on the buffer which is held until the + * slot is cleared, so that the tuple won't go away on us. * - * NOTE: before PostgreSQL 8.1, this function would accept a NULL tuple - * pointer and effectively behave like ExecClearTuple (though you could - * still specify a buffer to pin, which would be an odd combination). - * This saved a couple lines of code in a few places, but seemed more likely - * to mask logic errors than to be really useful, so it's now disallowed. + * Return value is just the passed-in slot pointer. * -------------------------------- */ TupleTableSlot * -ExecStoreTuple(HeapTuple tuple, - TupleTableSlot *slot, - Buffer buffer, - bool shouldFree) +ExecStoreBufferHeapTuple(HeapTuple tuple, + TupleTableSlot *slot, + Buffer buffer) { /* * sanity checks @@ -336,8 +376,7 @@ ExecStoreTuple(HeapTuple tuple, Assert(tuple != NULL); Assert(slot != NULL); Assert(slot->tts_tupleDescriptor != NULL); - /* passing shouldFree=true for a tuple on a disk page is not sane */ - Assert(BufferIsValid(buffer) ? (!shouldFree) : true); + Assert(BufferIsValid(buffer)); /* * Free any old physical tuple belonging to the slot. @@ -351,7 +390,7 @@ ExecStoreTuple(HeapTuple tuple, * Store the new tuple into the specified slot. */ slot->tts_isempty = false; - slot->tts_shouldFree = shouldFree; + slot->tts_shouldFree = false; slot->tts_shouldFreeMin = false; slot->tts_tuple = tuple; slot->tts_mintuple = NULL; @@ -360,21 +399,20 @@ ExecStoreTuple(HeapTuple tuple, slot->tts_nvalid = 0; /* - * If tuple is on a disk page, keep the page pinned as long as we hold a - * pointer into it. We assume the caller already has such a pin. + * Keep the disk page containing the given tuple pinned as long as we hold + * a pointer into it. We assume the caller already has such a pin. * * This is coded to optimize the case where the slot previously held a - * tuple on the same disk page: in that case releasing and re-acquiring - * the pin is a waste of cycles. This is a common situation during - * seqscans, so it's worth troubling over. + * tuple on the same disk page: in that case releasing and re-acquiring the + * pin is a waste of cycles. This is a common situation during seqscans, + * so it's worth troubling over. */ if (slot->tts_buffer != buffer) { if (BufferIsValid(slot->tts_buffer)) ReleaseBuffer(slot->tts_buffer); slot->tts_buffer = buffer; - if (BufferIsValid(buffer)) - IncrBufferRefCount(buffer); + IncrBufferRefCount(buffer); } return slot; @@ -383,7 +421,7 @@ ExecStoreTuple(HeapTuple tuple, /* -------------------------------- * ExecStoreMinimalTuple * - * Like ExecStoreTuple, but insert a "minimal" tuple into the slot. + * Like ExecStoreHeapTuple, but insert a "minimal" tuple into the slot. * * No 'buffer' parameter since minimal tuples are never stored in relations. * -------------------------------- @@ -652,7 +690,7 @@ ExecFetchSlotTuple(TupleTableSlot *slot) tuple = heap_expand_tuple(slot->tts_tuple, slot->tts_tupleDescriptor); MemoryContextSwitchTo(oldContext); - slot = ExecStoreTuple(tuple, slot, InvalidBuffer, true); + slot = ExecStoreHeapTuple(tuple, slot, true); } return slot->tts_tuple; } @@ -834,7 +872,7 @@ ExecCopySlot(TupleTableSlot *dstslot, TupleTableSlot *srcslot) newTuple = ExecCopySlotTuple(srcslot); MemoryContextSwitchTo(oldContext); - return ExecStoreTuple(newTuple, dstslot, InvalidBuffer, true); + return ExecStoreHeapTuple(newTuple, dstslot, true); } diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c index 0fe0c22c1ea..98d8483b720 100644 --- a/src/backend/executor/nodeAgg.c +++ b/src/backend/executor/nodeAgg.c @@ -1799,10 +1799,9 @@ agg_retrieve_direct(AggState *aggstate) * reserved for it. The tuple will be deleted when it is * cleared from the slot. */ - ExecStoreTuple(aggstate->grp_firstTuple, - firstSlot, - InvalidBuffer, - true); + ExecStoreHeapTuple(aggstate->grp_firstTuple, + firstSlot, + true); aggstate->grp_firstTuple = NULL; /* don't keep two pointers */ /* set up for first advance_aggregates call */ diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c index 3e1c9e07145..baffae27e3e 100644 --- a/src/backend/executor/nodeBitmapHeapscan.c +++ b/src/backend/executor/nodeBitmapHeapscan.c @@ -340,10 +340,9 @@ BitmapHeapNext(BitmapHeapScanState *node) * Set up the result slot to point to this tuple. Note that the * slot acquires a pin on the buffer. */ - ExecStoreTuple(&scan->rs_ctup, - slot, - scan->rs_cbuf, - false); + ExecStoreBufferHeapTuple(&scan->rs_ctup, + slot, + scan->rs_cbuf); /* * If we are using lossy info, we have to recheck the qual diff --git a/src/backend/executor/nodeGather.c b/src/backend/executor/nodeGather.c index 4a700b7b30e..ad16c783bd8 100644 --- a/src/backend/executor/nodeGather.c +++ b/src/backend/executor/nodeGather.c @@ -257,11 +257,9 @@ gather_getnext(GatherState *gatherstate) if (HeapTupleIsValid(tup)) { - ExecStoreTuple(tup, /* tuple to store */ - fslot, /* slot in which to store the tuple */ - InvalidBuffer, /* buffer associated with this - * tuple */ - true); /* pfree tuple when done with it */ + ExecStoreHeapTuple(tup, /* tuple to store */ + fslot, /* slot to store the tuple */ + true); /* pfree tuple when done with it */ return fslot; } } diff --git a/src/backend/executor/nodeGatherMerge.c b/src/backend/executor/nodeGatherMerge.c index a0b3334bedf..a1a11dfda1d 100644 --- a/src/backend/executor/nodeGatherMerge.c +++ b/src/backend/executor/nodeGatherMerge.c @@ -679,11 +679,10 @@ gather_merge_readnext(GatherMergeState *gm_state, int reader, bool nowait) Assert(HeapTupleIsValid(tup)); /* Build the TupleTableSlot for the given tuple */ - ExecStoreTuple(tup, /* tuple to store */ - gm_state->gm_slots[reader], /* slot in which to store the - * tuple */ - InvalidBuffer, /* no buffer associated with tuple */ - true); /* pfree tuple when done with it */ + ExecStoreHeapTuple(tup, /* tuple to store */ + gm_state->gm_slots[reader], /* slot in which to store + * the tuple */ + true); /* pfree tuple when done with it */ return true; } diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c index 8c32a74d39e..4b6d531810c 100644 --- a/src/backend/executor/nodeIndexonlyscan.c +++ b/src/backend/executor/nodeIndexonlyscan.c @@ -199,7 +199,7 @@ IndexOnlyNext(IndexOnlyScanState *node) */ Assert(slot->tts_tupleDescriptor->natts == scandesc->xs_hitupdesc->natts); - ExecStoreTuple(scandesc->xs_hitup, slot, InvalidBuffer, false); + ExecStoreHeapTuple(scandesc->xs_hitup, slot, false); } else if (scandesc->xs_itup) StoreIndexTuple(slot, scandesc->xs_itup, scandesc->xs_itupdesc); diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c index 10891bc3f46..6285a2114e8 100644 --- a/src/backend/executor/nodeIndexscan.c +++ b/src/backend/executor/nodeIndexscan.c @@ -140,10 +140,10 @@ IndexNext(IndexScanState *node) * Note: we pass 'false' because tuples returned by amgetnext are * pointers onto disk pages and must not be pfree()'d. */ - ExecStoreTuple(tuple, /* tuple to store */ - slot, /* slot to store in */ - scandesc->xs_cbuf, /* buffer containing tuple */ - false); /* don't pfree */ + ExecStoreBufferHeapTuple(tuple, /* tuple to store */ + slot, /* slot to store in */ + scandesc->xs_cbuf); /* buffer containing + * tuple */ /* * If the index was lossy, we have to recheck the index quals using @@ -257,7 +257,7 @@ IndexNextWithReorder(IndexScanState *node) tuple = reorderqueue_pop(node); /* Pass 'true', as the tuple in the queue is a palloc'd copy */ - ExecStoreTuple(tuple, slot, InvalidBuffer, true); + ExecStoreHeapTuple(tuple, slot, true); return slot; } } @@ -284,13 +284,11 @@ next_indextuple: /* * Store the scanned tuple in the scan tuple slot of the scan state. - * Note: we pass 'false' because tuples returned by amgetnext are - * pointers onto disk pages and must not be pfree()'d. */ - ExecStoreTuple(tuple, /* tuple to store */ - slot, /* slot to store in */ - scandesc->xs_cbuf, /* buffer containing tuple */ - false); /* don't pfree */ + ExecStoreBufferHeapTuple(tuple, /* tuple to store */ + slot, /* slot to store in */ + scandesc->xs_cbuf); /* buffer containing + * tuple */ /* * If the index was lossy, we have to recheck the index quals and diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index d8d89c7983c..bf0d5e8edb5 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -888,7 +888,7 @@ ldelete:; if (slot->tts_tupleDescriptor != RelationGetDescr(resultRelationDesc)) ExecSetSlotDescriptor(slot, RelationGetDescr(resultRelationDesc)); - ExecStoreTuple(&deltuple, slot, InvalidBuffer, false); + ExecStoreHeapTuple(&deltuple, slot, false); } rslot = ExecProcessReturning(resultRelInfo, slot, planSlot); @@ -1479,7 +1479,7 @@ ExecOnConflictUpdate(ModifyTableState *mtstate, ExecCheckHeapTupleVisible(estate, &tuple, buffer); /* Store target's existing tuple in the state's dedicated slot */ - ExecStoreTuple(&tuple, mtstate->mt_existing, buffer, false); + ExecStoreBufferHeapTuple(&tuple, mtstate->mt_existing, buffer); /* * Make tuple and any needed join variables available to ExecQual and diff --git a/src/backend/executor/nodeSamplescan.c b/src/backend/executor/nodeSamplescan.c index 15177dbed7a..99528be84a6 100644 --- a/src/backend/executor/nodeSamplescan.c +++ b/src/backend/executor/nodeSamplescan.c @@ -63,10 +63,9 @@ SampleNext(SampleScanState *node) slot = node->ss.ss_ScanTupleSlot; if (tuple) - ExecStoreTuple(tuple, /* tuple to store */ - slot, /* slot to store in */ - node->ss.ss_currentScanDesc->rs_cbuf, /* tuple's buffer */ - false); /* don't pfree this pointer */ + ExecStoreBufferHeapTuple(tuple, /* tuple to store */ + slot, /* slot to store in */ + node->ss.ss_currentScanDesc->rs_cbuf); /* tuple's buffer */ else ExecClearTuple(slot); diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c index c7849de6bca..cd53491be0a 100644 --- a/src/backend/executor/nodeSeqscan.c +++ b/src/backend/executor/nodeSeqscan.c @@ -84,15 +84,14 @@ SeqNext(SeqScanState *node) * our scan tuple slot and return the slot. Note: we pass 'false' because * tuples returned by heap_getnext() are pointers onto disk pages and were * not created with palloc() and so should not be pfree()'d. Note also - * that ExecStoreTuple will increment the refcount of the buffer; the + * that ExecStoreHeapTuple will increment the refcount of the buffer; the * refcount will not be dropped until the tuple table slot is cleared. */ if (tuple) - ExecStoreTuple(tuple, /* tuple to store */ - slot, /* slot to store in */ - scandesc->rs_cbuf, /* buffer associated with this - * tuple */ - false); /* don't pfree this pointer */ + ExecStoreBufferHeapTuple(tuple, /* tuple to store */ + slot, /* slot to store in */ + scandesc->rs_cbuf); /* buffer associated + * with this tuple */ else ExecClearTuple(slot); diff --git a/src/backend/executor/nodeSetOp.c b/src/backend/executor/nodeSetOp.c index 3fa4a5fcc65..3535b19c41d 100644 --- a/src/backend/executor/nodeSetOp.c +++ b/src/backend/executor/nodeSetOp.c @@ -267,10 +267,9 @@ setop_retrieve_direct(SetOpState *setopstate) * for it. The tuple will be deleted when it is cleared from the * slot. */ - ExecStoreTuple(setopstate->grp_firstTuple, - resultTupleSlot, - InvalidBuffer, - true); + ExecStoreHeapTuple(setopstate->grp_firstTuple, + resultTupleSlot, + true); setopstate->grp_firstTuple = NULL; /* don't keep two pointers */ /* Initialize working state for a new input tuple group */ diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c index e207b1ffb51..0cb1946a3e3 100644 --- a/src/backend/executor/nodeTidscan.c +++ b/src/backend/executor/nodeTidscan.c @@ -377,20 +377,18 @@ TidNext(TidScanState *node) if (heap_fetch(heapRelation, snapshot, tuple, &buffer, false, NULL)) { /* - * store the scanned tuple in the scan tuple slot of the scan + * Store the scanned tuple in the scan tuple slot of the scan * state. Eventually we will only do this and not return a tuple. - * Note: we pass 'false' because tuples returned by amgetnext are - * pointers onto disk pages and were not created with palloc() and - * so should not be pfree()'d. */ - ExecStoreTuple(tuple, /* tuple to store */ - slot, /* slot to store in */ - buffer, /* buffer associated with tuple */ - false); /* don't pfree */ + ExecStoreBufferHeapTuple(tuple, /* tuple to store */ + slot, /* slot to store in */ + buffer); /* buffer associated with + * tuple */ /* * At this point we have an extra pin on the buffer, because - * ExecStoreTuple incremented the pin count. Drop our local pin. + * ExecStoreHeapTuple incremented the pin count. Drop our local + * pin. */ ReleaseBuffer(buffer); |