/* * tuplestore_gettupleslot - exported function to fetch a MinimalTuple * * If successful, put tuple in slot and return TRUE; else, clear the slot * and return FALSE. */ bool tuplestore_gettupleslot_pos(Tuplestorestate *state, TuplestorePos *pos, bool forward, TupleTableSlot *slot) { MemTuple tuple; bool should_free = false; tuple = (MemTuple) tuplestore_gettuple(state, pos, forward, &should_free); if (tuple) { ExecStoreMemTuple(tuple, slot, should_free); return true; } else { ExecClearTuple(slot); return false; } }
/* -------------------------------- * ExecStoreTuple * * This function is used to store a 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. * It must always be 'false' for tuples that are stored in disk pages, * since we don't want to try to pfree those. * * 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! * * Return value is just the passed-in slot pointer. * * 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. * -------------------------------- */ TupleTableSlot * ExecStoreHeapTuple(HeapTuple tuple, TupleTableSlot *slot, Buffer buffer, bool shouldFree) { /* * sanity checks */ 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); /* * Actually we are storing a memtuple! */ if(is_heaptuple_memtuple(tuple)) { Assert(buffer == InvalidBuffer); return ExecStoreMemTuple((MemTuple) tuple, slot, shouldFree); } /* * Free any old physical tuple belonging to the slot. */ free_heaptuple_memtuple(slot); /* * Store the new tuple into the specified slot. */ /* Clear tts_flags, here isempty set to false */ slot->PRIVATE_tts_flags = shouldFree ? TTS_SHOULDFREE : 0; /* store the tuple */ slot->PRIVATE_tts_heaptuple = (void *) tuple; /* Mark extracted state invalid */ slot->PRIVATE_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. * * 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. */ if (slot->tts_buffer != buffer) { if (BufferIsValid(slot->tts_buffer)) ReleaseBuffer(slot->tts_buffer); slot->tts_buffer = buffer; if (BufferIsValid(buffer)) IncrBufferRefCount(buffer); } return slot; }