19
19
*
20
20
* At ExecutorStart()
21
21
* ----------------
22
-
22
+ *
23
23
* - ExecInitSeqScan() calls ExecInitScanTupleSlot() to construct a
24
24
* TupleTableSlots for the tuples returned by the access method, and
25
25
* ExecInitResultTypeTL() to define the node's return
@@ -272,7 +272,6 @@ tts_virtual_copy_heap_tuple(TupleTableSlot *slot)
272
272
return heap_form_tuple (slot -> tts_tupleDescriptor ,
273
273
slot -> tts_values ,
274
274
slot -> tts_isnull );
275
-
276
275
}
277
276
278
277
static MinimalTuple
@@ -334,6 +333,8 @@ tts_heap_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
334
333
{
335
334
HeapTupleTableSlot * hslot = (HeapTupleTableSlot * ) slot ;
336
335
336
+ Assert (!TTS_EMPTY (slot ));
337
+
337
338
return heap_getsysattr (hslot -> tuple , attnum ,
338
339
slot -> tts_tupleDescriptor , isnull );
339
340
}
@@ -346,14 +347,19 @@ tts_heap_materialize(TupleTableSlot *slot)
346
347
347
348
Assert (!TTS_EMPTY (slot ));
348
349
349
- /* This slot has it's tuple already materialized. Nothing to do. */
350
+ /* If slot has its tuple already materialized, nothing to do. */
350
351
if (TTS_SHOULDFREE (slot ))
351
352
return ;
352
353
353
- slot -> tts_flags |= TTS_FLAG_SHOULDFREE ;
354
-
355
354
oldContext = MemoryContextSwitchTo (slot -> tts_mcxt );
356
355
356
+ /*
357
+ * Have to deform from scratch, otherwise tts_values[] entries could point
358
+ * into the non-materialized tuple (which might be gone when accessed).
359
+ */
360
+ slot -> tts_nvalid = 0 ;
361
+ hslot -> off = 0 ;
362
+
357
363
if (!hslot -> tuple )
358
364
hslot -> tuple = heap_form_tuple (slot -> tts_tupleDescriptor ,
359
365
slot -> tts_values ,
@@ -368,12 +374,7 @@ tts_heap_materialize(TupleTableSlot *slot)
368
374
hslot -> tuple = heap_copytuple (hslot -> tuple );
369
375
}
370
376
371
- /*
372
- * Have to deform from scratch, otherwise tts_values[] entries could point
373
- * into the non-materialized tuple (which might be gone when accessed).
374
- */
375
- slot -> tts_nvalid = 0 ;
376
- hslot -> off = 0 ;
377
+ slot -> tts_flags |= TTS_FLAG_SHOULDFREE ;
377
378
378
379
MemoryContextSwitchTo (oldContext );
379
380
}
@@ -436,7 +437,7 @@ tts_heap_store_tuple(TupleTableSlot *slot, HeapTuple tuple, bool shouldFree)
436
437
slot -> tts_nvalid = 0 ;
437
438
hslot -> tuple = tuple ;
438
439
hslot -> off = 0 ;
439
- slot -> tts_flags &= ~TTS_FLAG_EMPTY ;
440
+ slot -> tts_flags &= ~( TTS_FLAG_EMPTY | TTS_FLAG_SHOULDFREE ) ;
440
441
slot -> tts_tid = tuple -> t_self ;
441
442
442
443
if (shouldFree )
@@ -509,13 +510,19 @@ tts_minimal_materialize(TupleTableSlot *slot)
509
510
510
511
Assert (!TTS_EMPTY (slot ));
511
512
512
- /* This slot has it's tuple already materialized. Nothing to do. */
513
+ /* If slot has its tuple already materialized, nothing to do. */
513
514
if (TTS_SHOULDFREE (slot ))
514
515
return ;
515
516
516
- slot -> tts_flags |= TTS_FLAG_SHOULDFREE ;
517
517
oldContext = MemoryContextSwitchTo (slot -> tts_mcxt );
518
518
519
+ /*
520
+ * Have to deform from scratch, otherwise tts_values[] entries could point
521
+ * into the non-materialized tuple (which might be gone when accessed).
522
+ */
523
+ slot -> tts_nvalid = 0 ;
524
+ mslot -> off = 0 ;
525
+
519
526
if (!mslot -> mintuple )
520
527
{
521
528
mslot -> mintuple = heap_form_minimal_tuple (slot -> tts_tupleDescriptor ,
@@ -532,19 +539,14 @@ tts_minimal_materialize(TupleTableSlot *slot)
532
539
mslot -> mintuple = heap_copy_minimal_tuple (mslot -> mintuple );
533
540
}
534
541
542
+ slot -> tts_flags |= TTS_FLAG_SHOULDFREE ;
543
+
535
544
Assert (mslot -> tuple == & mslot -> minhdr );
536
545
537
546
mslot -> minhdr .t_len = mslot -> mintuple -> t_len + MINIMAL_TUPLE_OFFSET ;
538
547
mslot -> minhdr .t_data = (HeapTupleHeader ) ((char * ) mslot -> mintuple - MINIMAL_TUPLE_OFFSET );
539
548
540
549
MemoryContextSwitchTo (oldContext );
541
-
542
- /*
543
- * Have to deform from scratch, otherwise tts_values[] entries could point
544
- * into the non-materialized tuple (which might be gone when accessed).
545
- */
546
- slot -> tts_nvalid = 0 ;
547
- mslot -> off = 0 ;
548
550
}
549
551
550
552
static void
@@ -615,8 +617,6 @@ tts_minimal_store_tuple(TupleTableSlot *slot, MinimalTuple mtup, bool shouldFree
615
617
616
618
if (shouldFree )
617
619
slot -> tts_flags |= TTS_FLAG_SHOULDFREE ;
618
- else
619
- Assert (!TTS_SHOULDFREE (slot ));
620
620
}
621
621
622
622
@@ -651,8 +651,6 @@ tts_buffer_heap_clear(TupleTableSlot *slot)
651
651
652
652
heap_freetuple (bslot -> base .tuple );
653
653
slot -> tts_flags &= ~TTS_FLAG_SHOULDFREE ;
654
-
655
- Assert (!BufferIsValid (bslot -> buffer ));
656
654
}
657
655
658
656
if (BufferIsValid (bslot -> buffer ))
@@ -681,6 +679,8 @@ tts_buffer_heap_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
681
679
{
682
680
BufferHeapTupleTableSlot * bslot = (BufferHeapTupleTableSlot * ) slot ;
683
681
682
+ Assert (!TTS_EMPTY (slot ));
683
+
684
684
return heap_getsysattr (bslot -> base .tuple , attnum ,
685
685
slot -> tts_tupleDescriptor , isnull );
686
686
}
@@ -693,14 +693,19 @@ tts_buffer_heap_materialize(TupleTableSlot *slot)
693
693
694
694
Assert (!TTS_EMPTY (slot ));
695
695
696
- /* If already materialized nothing to do. */
696
+ /* If slot has its tuple already materialized, nothing to do. */
697
697
if (TTS_SHOULDFREE (slot ))
698
698
return ;
699
699
700
- slot -> tts_flags |= TTS_FLAG_SHOULDFREE ;
701
-
702
700
oldContext = MemoryContextSwitchTo (slot -> tts_mcxt );
703
701
702
+ /*
703
+ * Have to deform from scratch, otherwise tts_values[] entries could point
704
+ * into the non-materialized tuple (which might be gone when accessed).
705
+ */
706
+ bslot -> base .off = 0 ;
707
+ slot -> tts_nvalid = 0 ;
708
+
704
709
if (!bslot -> base .tuple )
705
710
{
706
711
/*
@@ -713,7 +718,6 @@ tts_buffer_heap_materialize(TupleTableSlot *slot)
713
718
bslot -> base .tuple = heap_form_tuple (slot -> tts_tupleDescriptor ,
714
719
slot -> tts_values ,
715
720
slot -> tts_isnull );
716
-
717
721
}
718
722
else
719
723
{
@@ -723,19 +727,21 @@ tts_buffer_heap_materialize(TupleTableSlot *slot)
723
727
* A heap tuple stored in a BufferHeapTupleTableSlot should have a
724
728
* buffer associated with it, unless it's materialized or virtual.
725
729
*/
726
- Assert (BufferIsValid (bslot -> buffer ));
727
730
if (likely (BufferIsValid (bslot -> buffer )))
728
731
ReleaseBuffer (bslot -> buffer );
729
732
bslot -> buffer = InvalidBuffer ;
730
733
}
731
- MemoryContextSwitchTo (oldContext );
732
734
733
735
/*
734
- * Have to deform from scratch, otherwise tts_values[] entries could point
735
- * into the non-materialized tuple (which might be gone when accessed).
736
+ * We don't set TTS_FLAG_SHOULDFREE until after releasing the buffer, if
737
+ * any. This avoids having a transient state that would fall foul of our
738
+ * assertions that a slot with TTS_FLAG_SHOULDFREE doesn't own a buffer.
739
+ * In the unlikely event that ReleaseBuffer() above errors out, we'd
740
+ * effectively leak the copied tuple, but that seems fairly harmless.
736
741
*/
737
- bslot -> base .off = 0 ;
738
- slot -> tts_nvalid = 0 ;
742
+ slot -> tts_flags |= TTS_FLAG_SHOULDFREE ;
743
+
744
+ MemoryContextSwitchTo (oldContext );
739
745
}
740
746
741
747
static void
@@ -756,10 +762,10 @@ tts_buffer_heap_copyslot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
756
762
MemoryContext oldContext ;
757
763
758
764
ExecClearTuple (dstslot );
759
- dstslot -> tts_flags |= TTS_FLAG_SHOULDFREE ;
760
765
dstslot -> tts_flags &= ~TTS_FLAG_EMPTY ;
761
766
oldContext = MemoryContextSwitchTo (dstslot -> tts_mcxt );
762
767
bdstslot -> base .tuple = ExecCopySlotHeapTuple (srcslot );
768
+ dstslot -> tts_flags |= TTS_FLAG_SHOULDFREE ;
763
769
MemoryContextSwitchTo (oldContext );
764
770
}
765
771
else
@@ -1444,10 +1450,10 @@ ExecForceStoreHeapTuple(HeapTuple tuple,
1444
1450
BufferHeapTupleTableSlot * bslot = (BufferHeapTupleTableSlot * ) slot ;
1445
1451
1446
1452
ExecClearTuple (slot );
1447
- slot -> tts_flags |= TTS_FLAG_SHOULDFREE ;
1448
1453
slot -> tts_flags &= ~TTS_FLAG_EMPTY ;
1449
1454
oldContext = MemoryContextSwitchTo (slot -> tts_mcxt );
1450
1455
bslot -> base .tuple = heap_copytuple (tuple );
1456
+ slot -> tts_flags |= TTS_FLAG_SHOULDFREE ;
1451
1457
MemoryContextSwitchTo (oldContext );
1452
1458
1453
1459
if (shouldFree )
@@ -1856,7 +1862,6 @@ slot_getmissingattrs(TupleTableSlot *slot, int startAttNum, int lastAttNum)
1856
1862
slot -> tts_values [missattnum ] = attrmiss [missattnum ].am_value ;
1857
1863
slot -> tts_isnull [missattnum ] = !attrmiss [missattnum ].am_present ;
1858
1864
}
1859
-
1860
1865
}
1861
1866
}
1862
1867
0 commit comments