15
15
*
16
16
*
17
17
* 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 $
19
19
*
20
20
*-------------------------------------------------------------------------
21
21
*/
@@ -146,6 +146,7 @@ ExecCreateTupleTable(int tableSize)
146
146
slot -> type = T_TupleTableSlot ;
147
147
slot -> tts_isempty = true;
148
148
slot -> tts_shouldFree = false;
149
+ slot -> tts_shouldFreeMin = false;
149
150
slot -> tts_tuple = NULL ;
150
151
slot -> tts_tupleDescriptor = NULL ;
151
152
slot -> tts_mcxt = CurrentMemoryContext ;
@@ -224,6 +225,7 @@ MakeSingleTupleTableSlot(TupleDesc tupdesc)
224
225
/* This should match ExecCreateTupleTable() */
225
226
slot -> tts_isempty = true;
226
227
slot -> tts_shouldFree = false;
228
+ slot -> tts_shouldFreeMin = false;
227
229
slot -> tts_tuple = NULL ;
228
230
slot -> tts_tupleDescriptor = NULL ;
229
231
slot -> tts_mcxt = CurrentMemoryContext ;
@@ -410,18 +412,16 @@ ExecStoreTuple(HeapTuple tuple,
410
412
* Free any old physical tuple belonging to the slot.
411
413
*/
412
414
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 );
419
418
420
419
/*
421
420
* Store the new tuple into the specified slot.
422
421
*/
423
422
slot -> tts_isempty = false;
424
423
slot -> tts_shouldFree = shouldFree ;
424
+ slot -> tts_shouldFreeMin = false;
425
425
slot -> tts_tuple = tuple ;
426
426
slot -> tts_mintuple = NULL ;
427
427
@@ -473,12 +473,9 @@ ExecStoreMinimalTuple(MinimalTuple mtup,
473
473
* Free any old physical tuple belonging to the slot.
474
474
*/
475
475
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 );
482
479
483
480
/*
484
481
* Drop the pin on the referenced buffer, if there is one.
@@ -492,7 +489,8 @@ ExecStoreMinimalTuple(MinimalTuple mtup,
492
489
* Store the new tuple into the specified slot.
493
490
*/
494
491
slot -> tts_isempty = false;
495
- slot -> tts_shouldFree = shouldFree ;
492
+ slot -> tts_shouldFree = false;
493
+ slot -> tts_shouldFreeMin = shouldFree ;
496
494
slot -> tts_tuple = & slot -> tts_minhdr ;
497
495
slot -> tts_mintuple = mtup ;
498
496
@@ -526,16 +524,14 @@ ExecClearTuple(TupleTableSlot *slot) /* slot in which to store tuple */
526
524
* Free the old physical tuple if necessary.
527
525
*/
528
526
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 );
535
530
536
531
slot -> tts_tuple = NULL ;
537
532
slot -> tts_mintuple = NULL ;
538
533
slot -> tts_shouldFree = false;
534
+ slot -> tts_shouldFreeMin = false;
539
535
540
536
/*
541
537
* Drop the pin on the referenced buffer, if there is one.
@@ -616,6 +612,7 @@ ExecStoreAllNullTuple(TupleTableSlot *slot)
616
612
* ExecCopySlotTuple
617
613
* Obtain a copy of a slot's regular physical tuple. The copy is
618
614
* palloc'd in the current memory context.
615
+ * The slot itself is undisturbed.
619
616
*
620
617
* This works even if the slot contains a virtual or minimal tuple;
621
618
* however the "system columns" of the result will not be meaningful.
@@ -631,15 +628,12 @@ ExecCopySlotTuple(TupleTableSlot *slot)
631
628
Assert (!slot -> tts_isempty );
632
629
633
630
/*
634
- * If we have a physical tuple then just copy it.
631
+ * If we have a physical tuple (either format) then just copy it.
635
632
*/
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 );
643
637
644
638
/*
645
639
* Otherwise we need to build a tuple from the Datum array.
@@ -653,6 +647,7 @@ ExecCopySlotTuple(TupleTableSlot *slot)
653
647
* ExecCopySlotMinimalTuple
654
648
* Obtain a copy of a slot's minimal physical tuple. The copy is
655
649
* palloc'd in the current memory context.
650
+ * The slot itself is undisturbed.
656
651
* --------------------------------
657
652
*/
658
653
MinimalTuple
@@ -665,15 +660,13 @@ ExecCopySlotMinimalTuple(TupleTableSlot *slot)
665
660
Assert (!slot -> tts_isempty );
666
661
667
662
/*
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.
669
665
*/
666
+ if (slot -> tts_mintuple )
667
+ return heap_copy_minimal_tuple (slot -> tts_mintuple );
670
668
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 );
677
670
678
671
/*
679
672
* Otherwise we need to build a tuple from the Datum array.
@@ -689,9 +682,11 @@ ExecCopySlotMinimalTuple(TupleTableSlot *slot)
689
682
*
690
683
* If the slot contains a virtual tuple, we convert it to physical
691
684
* 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).
693
688
*
694
- * The difference between this and ExecMaterializeSlot() is that this
689
+ * The main difference between this and ExecMaterializeSlot() is that this
695
690
* does not guarantee that the contained tuple is local storage.
696
691
* Hence, the result must be treated as read-only.
697
692
* --------------------------------
@@ -708,7 +703,7 @@ ExecFetchSlotTuple(TupleTableSlot *slot)
708
703
/*
709
704
* If we have a regular physical tuple then just return it.
710
705
*/
711
- if (slot -> tts_tuple && slot -> tts_mintuple == NULL )
706
+ if (TTS_HAS_PHYSICAL_TUPLE ( slot ) )
712
707
return slot -> tts_tuple ;
713
708
714
709
/*
@@ -722,16 +717,17 @@ ExecFetchSlotTuple(TupleTableSlot *slot)
722
717
* Fetch the slot's minimal physical tuple.
723
718
*
724
719
* 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).
727
724
*
728
725
* As above, the result must be treated as read-only.
729
726
* --------------------------------
730
727
*/
731
728
MinimalTuple
732
729
ExecFetchSlotMinimalTuple (TupleTableSlot * slot )
733
730
{
734
- MinimalTuple newTuple ;
735
731
MemoryContext oldContext ;
736
732
737
733
/*
@@ -741,28 +737,30 @@ ExecFetchSlotMinimalTuple(TupleTableSlot *slot)
741
737
Assert (!slot -> tts_isempty );
742
738
743
739
/*
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.
745
741
*/
746
742
if (slot -> tts_mintuple )
747
743
return slot -> tts_mintuple ;
748
744
749
745
/*
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.
754
747
*
755
748
* We may be called in a context that is shorter-lived than the tuple
756
749
* slot, but we have to ensure that the materialized tuple will survive
757
750
* anyway.
758
751
*/
759
752
oldContext = MemoryContextSwitchTo (slot -> tts_mcxt );
760
- newTuple = ExecCopySlotMinimalTuple (slot );
753
+ slot -> tts_mintuple = ExecCopySlotMinimalTuple (slot );
754
+ slot -> tts_shouldFreeMin = true;
761
755
MemoryContextSwitchTo (oldContext );
762
756
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
+ */
764
763
765
- Assert (slot -> tts_mintuple );
766
764
return slot -> tts_mintuple ;
767
765
}
768
766
@@ -809,7 +807,6 @@ ExecFetchSlotTupleDatum(TupleTableSlot *slot)
809
807
HeapTuple
810
808
ExecMaterializeSlot (TupleTableSlot * slot )
811
809
{
812
- HeapTuple newTuple ;
813
810
MemoryContext oldContext ;
814
811
815
812
/*
@@ -822,24 +819,47 @@ ExecMaterializeSlot(TupleTableSlot *slot)
822
819
* If we have a regular physical tuple, and it's locally palloc'd, we have
823
820
* nothing to do.
824
821
*/
825
- if (slot -> tts_tuple && slot -> tts_shouldFree && slot -> tts_mintuple == NULL )
822
+ if (slot -> tts_tuple && slot -> tts_shouldFree )
826
823
return slot -> tts_tuple ;
827
824
828
825
/*
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.
833
827
*
834
828
* We may be called in a context that is shorter-lived than the tuple
835
829
* slot, but we have to ensure that the materialized tuple will survive
836
830
* anyway.
837
831
*/
838
832
oldContext = MemoryContextSwitchTo (slot -> tts_mcxt );
839
- newTuple = ExecCopySlotTuple (slot );
833
+ slot -> tts_tuple = ExecCopySlotTuple (slot );
834
+ slot -> tts_shouldFree = true;
840
835
MemoryContextSwitchTo (oldContext );
841
836
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 ;
843
863
844
864
return slot -> tts_tuple ;
845
865
}
0 commit comments