1515 *
1616 *
1717 * IDENTIFICATION
18- * $PostgreSQL: pgsql/src/backend/executor/execTuples.c,v 1.105 2009/01/01 17:23:41 momjian Exp $
18+ * $PostgreSQL: pgsql/src/backend/executor/execTuples.c,v 1.106 2009/03/30 04:08:43 tgl Exp $
1919 *
2020 *-------------------------------------------------------------------------
2121 */
@@ -146,6 +146,7 @@ ExecCreateTupleTable(int tableSize)
146146 slot -> type = T_TupleTableSlot ;
147147 slot -> tts_isempty = true;
148148 slot -> tts_shouldFree = false;
149+ slot -> tts_shouldFreeMin = false;
149150 slot -> tts_tuple = NULL ;
150151 slot -> tts_tupleDescriptor = NULL ;
151152 slot -> tts_mcxt = CurrentMemoryContext ;
@@ -224,6 +225,7 @@ MakeSingleTupleTableSlot(TupleDesc tupdesc)
224225 /* This should match ExecCreateTupleTable() */
225226 slot -> tts_isempty = true;
226227 slot -> tts_shouldFree = false;
228+ slot -> tts_shouldFreeMin = false;
227229 slot -> tts_tuple = NULL ;
228230 slot -> tts_tupleDescriptor = NULL ;
229231 slot -> tts_mcxt = CurrentMemoryContext ;
@@ -410,18 +412,16 @@ ExecStoreTuple(HeapTuple tuple,
410412 * Free any old physical tuple belonging to the slot.
411413 */
412414 if (slot -> tts_shouldFree )
413- {
414- if (slot -> tts_mintuple )
415- heap_free_minimal_tuple (slot -> tts_mintuple );
416- else
417- heap_freetuple (slot -> tts_tuple );
418- }
415+ heap_freetuple (slot -> tts_tuple );
416+ if (slot -> tts_shouldFreeMin )
417+ heap_free_minimal_tuple (slot -> tts_mintuple );
419418
420419 /*
421420 * Store the new tuple into the specified slot.
422421 */
423422 slot -> tts_isempty = false;
424423 slot -> tts_shouldFree = shouldFree ;
424+ slot -> tts_shouldFreeMin = false;
425425 slot -> tts_tuple = tuple ;
426426 slot -> tts_mintuple = NULL ;
427427
@@ -473,12 +473,9 @@ ExecStoreMinimalTuple(MinimalTuple mtup,
473473 * Free any old physical tuple belonging to the slot.
474474 */
475475 if (slot -> tts_shouldFree )
476- {
477- if (slot -> tts_mintuple )
478- heap_free_minimal_tuple (slot -> tts_mintuple );
479- else
480- heap_freetuple (slot -> tts_tuple );
481- }
476+ heap_freetuple (slot -> tts_tuple );
477+ if (slot -> tts_shouldFreeMin )
478+ heap_free_minimal_tuple (slot -> tts_mintuple );
482479
483480 /*
484481 * Drop the pin on the referenced buffer, if there is one.
@@ -492,7 +489,8 @@ ExecStoreMinimalTuple(MinimalTuple mtup,
492489 * Store the new tuple into the specified slot.
493490 */
494491 slot -> tts_isempty = false;
495- slot -> tts_shouldFree = shouldFree ;
492+ slot -> tts_shouldFree = false;
493+ slot -> tts_shouldFreeMin = shouldFree ;
496494 slot -> tts_tuple = & slot -> tts_minhdr ;
497495 slot -> tts_mintuple = mtup ;
498496
@@ -526,16 +524,14 @@ ExecClearTuple(TupleTableSlot *slot) /* slot in which to store tuple */
526524 * Free the old physical tuple if necessary.
527525 */
528526 if (slot -> tts_shouldFree )
529- {
530- if (slot -> tts_mintuple )
531- heap_free_minimal_tuple (slot -> tts_mintuple );
532- else
533- heap_freetuple (slot -> tts_tuple );
534- }
527+ heap_freetuple (slot -> tts_tuple );
528+ if (slot -> tts_shouldFreeMin )
529+ heap_free_minimal_tuple (slot -> tts_mintuple );
535530
536531 slot -> tts_tuple = NULL ;
537532 slot -> tts_mintuple = NULL ;
538533 slot -> tts_shouldFree = false;
534+ slot -> tts_shouldFreeMin = false;
539535
540536 /*
541537 * Drop the pin on the referenced buffer, if there is one.
@@ -616,6 +612,7 @@ ExecStoreAllNullTuple(TupleTableSlot *slot)
616612 * ExecCopySlotTuple
617613 * Obtain a copy of a slot's regular physical tuple. The copy is
618614 * palloc'd in the current memory context.
615+ * The slot itself is undisturbed.
619616 *
620617 * This works even if the slot contains a virtual or minimal tuple;
621618 * however the "system columns" of the result will not be meaningful.
@@ -631,15 +628,12 @@ ExecCopySlotTuple(TupleTableSlot *slot)
631628 Assert (!slot -> tts_isempty );
632629
633630 /*
634- * If we have a physical tuple then just copy it.
631+ * If we have a physical tuple (either format) then just copy it.
635632 */
636- if (slot -> tts_tuple )
637- {
638- if (slot -> tts_mintuple )
639- return heap_tuple_from_minimal_tuple (slot -> tts_mintuple );
640- else
641- return heap_copytuple (slot -> tts_tuple );
642- }
633+ if (TTS_HAS_PHYSICAL_TUPLE (slot ))
634+ return heap_copytuple (slot -> tts_tuple );
635+ if (slot -> tts_mintuple )
636+ return heap_tuple_from_minimal_tuple (slot -> tts_mintuple );
643637
644638 /*
645639 * Otherwise we need to build a tuple from the Datum array.
@@ -653,6 +647,7 @@ ExecCopySlotTuple(TupleTableSlot *slot)
653647 * ExecCopySlotMinimalTuple
654648 * Obtain a copy of a slot's minimal physical tuple. The copy is
655649 * palloc'd in the current memory context.
650+ * The slot itself is undisturbed.
656651 * --------------------------------
657652 */
658653MinimalTuple
@@ -665,15 +660,13 @@ ExecCopySlotMinimalTuple(TupleTableSlot *slot)
665660 Assert (!slot -> tts_isempty );
666661
667662 /*
668- * If we have a physical tuple then just copy it.
663+ * If we have a physical tuple then just copy it. Prefer to copy
664+ * tts_mintuple since that's a tad cheaper.
669665 */
666+ if (slot -> tts_mintuple )
667+ return heap_copy_minimal_tuple (slot -> tts_mintuple );
670668 if (slot -> tts_tuple )
671- {
672- if (slot -> tts_mintuple )
673- return heap_copy_minimal_tuple (slot -> tts_mintuple );
674- else
675- return minimal_tuple_from_heap_tuple (slot -> tts_tuple );
676- }
669+ return minimal_tuple_from_heap_tuple (slot -> tts_tuple );
677670
678671 /*
679672 * Otherwise we need to build a tuple from the Datum array.
@@ -689,9 +682,11 @@ ExecCopySlotMinimalTuple(TupleTableSlot *slot)
689682 *
690683 * If the slot contains a virtual tuple, we convert it to physical
691684 * form. The slot retains ownership of the physical tuple.
692- * Likewise, if it contains a minimal tuple we convert to regular form.
685+ * If it contains a minimal tuple we convert to regular form and store
686+ * that in addition to the minimal tuple (not instead of, because
687+ * callers may hold pointers to Datums within the minimal tuple).
693688 *
694- * The difference between this and ExecMaterializeSlot() is that this
689+ * The main difference between this and ExecMaterializeSlot() is that this
695690 * does not guarantee that the contained tuple is local storage.
696691 * Hence, the result must be treated as read-only.
697692 * --------------------------------
@@ -708,7 +703,7 @@ ExecFetchSlotTuple(TupleTableSlot *slot)
708703 /*
709704 * If we have a regular physical tuple then just return it.
710705 */
711- if (slot -> tts_tuple && slot -> tts_mintuple == NULL )
706+ if (TTS_HAS_PHYSICAL_TUPLE ( slot ) )
712707 return slot -> tts_tuple ;
713708
714709 /*
@@ -722,16 +717,17 @@ ExecFetchSlotTuple(TupleTableSlot *slot)
722717 * Fetch the slot's minimal physical tuple.
723718 *
724719 * If the slot contains a virtual tuple, we convert it to minimal
725- * physical form. The slot retains ownership of the physical tuple.
726- * Likewise, if it contains a regular tuple we convert to minimal form.
720+ * physical form. The slot retains ownership of the minimal tuple.
721+ * If it contains a regular tuple we convert to minimal form and store
722+ * that in addition to the regular tuple (not instead of, because
723+ * callers may hold pointers to Datums within the regular tuple).
727724 *
728725 * As above, the result must be treated as read-only.
729726 * --------------------------------
730727 */
731728MinimalTuple
732729ExecFetchSlotMinimalTuple (TupleTableSlot * slot )
733730{
734- MinimalTuple newTuple ;
735731 MemoryContext oldContext ;
736732
737733 /*
@@ -741,28 +737,30 @@ ExecFetchSlotMinimalTuple(TupleTableSlot *slot)
741737 Assert (!slot -> tts_isempty );
742738
743739 /*
744- * If we have a minimal physical tuple then just return it.
740+ * If we have a minimal physical tuple (local or not) then just return it.
745741 */
746742 if (slot -> tts_mintuple )
747743 return slot -> tts_mintuple ;
748744
749745 /*
750- * Otherwise, build a minimal tuple, and then store it as the new slot
751- * value. (Note: tts_nvalid will be reset to zero here. There are cases
752- * in which this could be optimized but it's probably not worth worrying
753- * about.)
746+ * Otherwise, copy or build a minimal tuple, and store it into the slot.
754747 *
755748 * We may be called in a context that is shorter-lived than the tuple
756749 * slot, but we have to ensure that the materialized tuple will survive
757750 * anyway.
758751 */
759752 oldContext = MemoryContextSwitchTo (slot -> tts_mcxt );
760- newTuple = ExecCopySlotMinimalTuple (slot );
753+ slot -> tts_mintuple = ExecCopySlotMinimalTuple (slot );
754+ slot -> tts_shouldFreeMin = true;
761755 MemoryContextSwitchTo (oldContext );
762756
763- ExecStoreMinimalTuple (newTuple , slot , true);
757+ /*
758+ * Note: we may now have a situation where we have a local minimal tuple
759+ * attached to a virtual or non-local physical tuple. There seems no
760+ * harm in that at the moment, but if any materializes, we should change
761+ * this function to force the slot into minimal-tuple-only state.
762+ */
764763
765- Assert (slot -> tts_mintuple );
766764 return slot -> tts_mintuple ;
767765}
768766
@@ -809,7 +807,6 @@ ExecFetchSlotTupleDatum(TupleTableSlot *slot)
809807HeapTuple
810808ExecMaterializeSlot (TupleTableSlot * slot )
811809{
812- HeapTuple newTuple ;
813810 MemoryContext oldContext ;
814811
815812 /*
@@ -822,24 +819,47 @@ ExecMaterializeSlot(TupleTableSlot *slot)
822819 * If we have a regular physical tuple, and it's locally palloc'd, we have
823820 * nothing to do.
824821 */
825- if (slot -> tts_tuple && slot -> tts_shouldFree && slot -> tts_mintuple == NULL )
822+ if (slot -> tts_tuple && slot -> tts_shouldFree )
826823 return slot -> tts_tuple ;
827824
828825 /*
829- * Otherwise, copy or build a tuple, and then store it as the new slot
830- * value. (Note: tts_nvalid will be reset to zero here. There are cases
831- * in which this could be optimized but it's probably not worth worrying
832- * about.)
826+ * Otherwise, copy or build a physical tuple, and store it into the slot.
833827 *
834828 * We may be called in a context that is shorter-lived than the tuple
835829 * slot, but we have to ensure that the materialized tuple will survive
836830 * anyway.
837831 */
838832 oldContext = MemoryContextSwitchTo (slot -> tts_mcxt );
839- newTuple = ExecCopySlotTuple (slot );
833+ slot -> tts_tuple = ExecCopySlotTuple (slot );
834+ slot -> tts_shouldFree = true;
840835 MemoryContextSwitchTo (oldContext );
841836
842- ExecStoreTuple (newTuple , slot , InvalidBuffer , true);
837+ /*
838+ * Drop the pin on the referenced buffer, if there is one.
839+ */
840+ if (BufferIsValid (slot -> tts_buffer ))
841+ ReleaseBuffer (slot -> tts_buffer );
842+
843+ slot -> tts_buffer = InvalidBuffer ;
844+
845+ /*
846+ * Mark extracted state invalid. This is important because the slot
847+ * is not supposed to depend any more on the previous external data;
848+ * we mustn't leave any dangling pass-by-reference datums in tts_values.
849+ * However, we have not actually invalidated any such datums, if there
850+ * happen to be any previously fetched from the slot. (Note in particular
851+ * that we have not pfree'd tts_mintuple, if there is one.)
852+ */
853+ slot -> tts_nvalid = 0 ;
854+
855+ /*
856+ * On the same principle of not depending on previous remote storage,
857+ * forget the mintuple if it's not local storage. (If it is local storage,
858+ * we must not pfree it now, since callers might have already fetched
859+ * datum pointers referencing it.)
860+ */
861+ if (!slot -> tts_shouldFreeMin )
862+ slot -> tts_mintuple = NULL ;
843863
844864 return slot -> tts_tuple ;
845865}
0 commit comments