*** pgsql/src/backend/executor/execTuples.c 2008/01/01 19:45:49 1.100 --- pgsql/src/backend/executor/execTuples.c 2009/03/30 04:09:09 1.100.2.1 *************** *** 15,21 **** * * * IDENTIFICATION ! * $PostgreSQL: pgsql/src/backend/executor/execTuples.c,v 1.99 2007/01/05 22:19:27 momjian Exp $ * *------------------------------------------------------------------------- */ --- 15,21 ---- * * * IDENTIFICATION ! * $PostgreSQL: pgsql/src/backend/executor/execTuples.c,v 1.100 2008/01/01 19:45:49 momjian Exp $ * *------------------------------------------------------------------------- */ *************** ExecCreateTupleTable(int tableSize) *** 146,151 **** --- 146,152 ---- slot->type = T_TupleTableSlot; slot->tts_isempty = true; slot->tts_shouldFree = false; + slot->tts_shouldFreeMin = false; slot->tts_tuple = NULL; slot->tts_tupleDescriptor = NULL; slot->tts_mcxt = CurrentMemoryContext; *************** MakeSingleTupleTableSlot(TupleDesc tupde *** 224,229 **** --- 225,231 ---- /* This should match ExecCreateTupleTable() */ slot->tts_isempty = true; slot->tts_shouldFree = false; + slot->tts_shouldFreeMin = false; slot->tts_tuple = NULL; slot->tts_tupleDescriptor = NULL; slot->tts_mcxt = CurrentMemoryContext; *************** ExecStoreTuple(HeapTuple tuple, *** 410,427 **** * Free any old physical tuple belonging to the slot. */ if (slot->tts_shouldFree) ! { ! if (slot->tts_mintuple) ! heap_free_minimal_tuple(slot->tts_mintuple); ! else ! heap_freetuple(slot->tts_tuple); ! } /* * Store the new tuple into the specified slot. */ slot->tts_isempty = false; slot->tts_shouldFree = shouldFree; slot->tts_tuple = tuple; slot->tts_mintuple = NULL; --- 412,427 ---- * 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; *************** ExecStoreMinimalTuple(MinimalTuple mtup, *** 473,484 **** * Free any old physical tuple belonging to the slot. */ if (slot->tts_shouldFree) ! { ! if (slot->tts_mintuple) ! heap_free_minimal_tuple(slot->tts_mintuple); ! else ! heap_freetuple(slot->tts_tuple); ! } /* * Drop the pin on the referenced buffer, if there is one. --- 473,481 ---- * 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); /* * Drop the pin on the referenced buffer, if there is one. *************** ExecStoreMinimalTuple(MinimalTuple mtup, *** 492,498 **** * Store the new tuple into the specified slot. */ slot->tts_isempty = false; ! slot->tts_shouldFree = shouldFree; slot->tts_tuple = &slot->tts_minhdr; slot->tts_mintuple = mtup; --- 489,496 ---- * Store the new tuple into the specified slot. */ slot->tts_isempty = false; ! slot->tts_shouldFree = false; ! slot->tts_shouldFreeMin = shouldFree; slot->tts_tuple = &slot->tts_minhdr; slot->tts_mintuple = mtup; *************** ExecClearTuple(TupleTableSlot *slot) /* *** 526,541 **** * Free the old physical tuple if necessary. */ if (slot->tts_shouldFree) ! { ! if (slot->tts_mintuple) ! heap_free_minimal_tuple(slot->tts_mintuple); ! else ! heap_freetuple(slot->tts_tuple); ! } slot->tts_tuple = NULL; slot->tts_mintuple = NULL; slot->tts_shouldFree = false; /* * Drop the pin on the referenced buffer, if there is one. --- 524,537 ---- * Free the old physical tuple if necessary. */ if (slot->tts_shouldFree) ! heap_freetuple(slot->tts_tuple); ! if (slot->tts_shouldFreeMin) ! heap_free_minimal_tuple(slot->tts_mintuple); slot->tts_tuple = NULL; slot->tts_mintuple = NULL; slot->tts_shouldFree = false; + slot->tts_shouldFreeMin = false; /* * Drop the pin on the referenced buffer, if there is one. *************** ExecStoreAllNullTuple(TupleTableSlot *sl *** 616,621 **** --- 612,618 ---- * ExecCopySlotTuple * Obtain a copy of a slot's regular physical tuple. The copy is * palloc'd in the current memory context. + * The slot itself is undisturbed. * * This works even if the slot contains a virtual or minimal tuple; * however the "system columns" of the result will not be meaningful. *************** ExecCopySlotTuple(TupleTableSlot *slot) *** 631,645 **** Assert(!slot->tts_isempty); /* ! * If we have a physical tuple then just copy it. */ ! if (slot->tts_tuple) ! { ! if (slot->tts_mintuple) ! return heap_tuple_from_minimal_tuple(slot->tts_mintuple); ! else ! return heap_copytuple(slot->tts_tuple); ! } /* * Otherwise we need to build a tuple from the Datum array. --- 628,639 ---- Assert(!slot->tts_isempty); /* ! * If we have a physical tuple (either format) then just copy it. */ ! if (TTS_HAS_PHYSICAL_TUPLE(slot)) ! return heap_copytuple(slot->tts_tuple); ! if (slot->tts_mintuple) ! return heap_tuple_from_minimal_tuple(slot->tts_mintuple); /* * Otherwise we need to build a tuple from the Datum array. *************** ExecCopySlotTuple(TupleTableSlot *slot) *** 653,658 **** --- 647,653 ---- * ExecCopySlotMinimalTuple * Obtain a copy of a slot's minimal physical tuple. The copy is * palloc'd in the current memory context. + * The slot itself is undisturbed. * -------------------------------- */ MinimalTuple *************** ExecCopySlotMinimalTuple(TupleTableSlot *** 665,679 **** Assert(!slot->tts_isempty); /* ! * If we have a physical tuple then just copy it. */ if (slot->tts_tuple) ! { ! if (slot->tts_mintuple) ! return heap_copy_minimal_tuple(slot->tts_mintuple); ! else ! return minimal_tuple_from_heap_tuple(slot->tts_tuple); ! } /* * Otherwise we need to build a tuple from the Datum array. --- 660,672 ---- Assert(!slot->tts_isempty); /* ! * If we have a physical tuple then just copy it. Prefer to copy ! * tts_mintuple since that's a tad cheaper. */ + if (slot->tts_mintuple) + return heap_copy_minimal_tuple(slot->tts_mintuple); if (slot->tts_tuple) ! return minimal_tuple_from_heap_tuple(slot->tts_tuple); /* * Otherwise we need to build a tuple from the Datum array. *************** ExecCopySlotMinimalTuple(TupleTableSlot *** 689,697 **** * * If the slot contains a virtual tuple, we convert it to physical * form. The slot retains ownership of the physical tuple. ! * Likewise, if it contains a minimal tuple we convert to regular form. * ! * The 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. * -------------------------------- --- 682,692 ---- * * 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. * -------------------------------- *************** ExecFetchSlotTuple(TupleTableSlot *slot) *** 708,714 **** /* * If we have a regular physical tuple then just return it. */ ! if (slot->tts_tuple && slot->tts_mintuple == NULL) return slot->tts_tuple; /* --- 703,709 ---- /* * If we have a regular physical tuple then just return it. */ ! if (TTS_HAS_PHYSICAL_TUPLE(slot)) return slot->tts_tuple; /* *************** ExecFetchSlotTuple(TupleTableSlot *slot) *** 722,729 **** * Fetch the slot's minimal physical tuple. * * If the slot contains a virtual tuple, we convert it to minimal ! * physical form. The slot retains ownership of the physical tuple. ! * Likewise, if it contains a regular tuple we convert to minimal form. * * As above, the result must be treated as read-only. * -------------------------------- --- 717,726 ---- * Fetch the slot's minimal physical tuple. * * If the slot contains a virtual tuple, we convert it to minimal ! * physical form. The slot retains ownership of the minimal tuple. ! * If it contains a regular tuple we convert to minimal form and store ! * that in addition to the regular tuple (not instead of, because ! * callers may hold pointers to Datums within the regular tuple). * * As above, the result must be treated as read-only. * -------------------------------- *************** ExecFetchSlotTuple(TupleTableSlot *slot) *** 731,737 **** MinimalTuple ExecFetchSlotMinimalTuple(TupleTableSlot *slot) { - MinimalTuple newTuple; MemoryContext oldContext; /* --- 728,733 ---- *************** ExecFetchSlotMinimalTuple(TupleTableSlot *** 741,768 **** Assert(!slot->tts_isempty); /* ! * If we have a minimal physical tuple then just return it. */ if (slot->tts_mintuple) return slot->tts_mintuple; /* ! * Otherwise, build a minimal tuple, and then store it as the new slot ! * value. (Note: tts_nvalid will be reset to zero here. There are cases ! * in which this could be optimized but it's probably not worth worrying ! * about.) * * We may be called in a context that is shorter-lived than the tuple * slot, but we have to ensure that the materialized tuple will survive * anyway. */ oldContext = MemoryContextSwitchTo(slot->tts_mcxt); ! newTuple = ExecCopySlotMinimalTuple(slot); MemoryContextSwitchTo(oldContext); ! ExecStoreMinimalTuple(newTuple, slot, true); - Assert(slot->tts_mintuple); return slot->tts_mintuple; } --- 737,766 ---- Assert(!slot->tts_isempty); /* ! * If we have a minimal physical tuple (local or not) then just return it. */ if (slot->tts_mintuple) return slot->tts_mintuple; /* ! * Otherwise, copy or build a minimal tuple, and store it into the slot. * * We may be called in a context that is shorter-lived than the tuple * slot, but we have to ensure that the materialized tuple will survive * anyway. */ oldContext = MemoryContextSwitchTo(slot->tts_mcxt); ! slot->tts_mintuple = ExecCopySlotMinimalTuple(slot); ! slot->tts_shouldFreeMin = true; MemoryContextSwitchTo(oldContext); ! /* ! * Note: we may now have a situation where we have a local minimal tuple ! * attached to a virtual or non-local physical tuple. There seems no ! * harm in that at the moment, but if any materializes, we should change ! * this function to force the slot into minimal-tuple-only state. ! */ return slot->tts_mintuple; } *************** ExecFetchSlotMinimalTuple(TupleTableSlot *** 782,788 **** HeapTuple ExecMaterializeSlot(TupleTableSlot *slot) { - HeapTuple newTuple; MemoryContext oldContext; /* --- 780,785 ---- *************** ExecMaterializeSlot(TupleTableSlot *slot *** 795,818 **** * If we have a regular physical tuple, and it's locally palloc'd, we have * nothing to do. */ ! if (slot->tts_tuple && slot->tts_shouldFree && slot->tts_mintuple == NULL) return slot->tts_tuple; /* ! * Otherwise, copy or build a tuple, and then store it as the new slot ! * value. (Note: tts_nvalid will be reset to zero here. There are cases ! * in which this could be optimized but it's probably not worth worrying ! * about.) * * We may be called in a context that is shorter-lived than the tuple * slot, but we have to ensure that the materialized tuple will survive * anyway. */ oldContext = MemoryContextSwitchTo(slot->tts_mcxt); ! newTuple = ExecCopySlotTuple(slot); MemoryContextSwitchTo(oldContext); ! ExecStoreTuple(newTuple, slot, InvalidBuffer, true); return slot->tts_tuple; } --- 792,838 ---- * If we have a regular physical tuple, and it's locally palloc'd, we have * nothing to do. */ ! if (slot->tts_tuple && slot->tts_shouldFree) return slot->tts_tuple; /* ! * Otherwise, copy or build a physical tuple, and store it into the slot. * * We may be called in a context that is shorter-lived than the tuple * slot, but we have to ensure that the materialized tuple will survive * anyway. */ oldContext = MemoryContextSwitchTo(slot->tts_mcxt); ! slot->tts_tuple = ExecCopySlotTuple(slot); ! slot->tts_shouldFree = true; MemoryContextSwitchTo(oldContext); ! /* ! * Drop the pin on the referenced buffer, if there is one. ! */ ! if (BufferIsValid(slot->tts_buffer)) ! ReleaseBuffer(slot->tts_buffer); ! ! slot->tts_buffer = InvalidBuffer; ! ! /* ! * Mark extracted state invalid. This is important because the slot ! * is not supposed to depend any more on the previous external data; ! * we mustn't leave any dangling pass-by-reference datums in tts_values. ! * However, we have not actually invalidated any such datums, if there ! * happen to be any previously fetched from the slot. (Note in particular ! * that we have not pfree'd tts_mintuple, if there is one.) ! */ ! slot->tts_nvalid = 0; ! ! /* ! * On the same principle of not depending on previous remote storage, ! * forget the mintuple if it's not local storage. (If it is local storage, ! * we must not pfree it now, since callers might have already fetched ! * datum pointers referencing it.) ! */ ! if (!slot->tts_shouldFreeMin) ! slot->tts_mintuple = NULL; return slot->tts_tuple; }