@@ -1391,6 +1391,153 @@ heap_getnextslot(TableScanDesc sscan, ScanDirection direction, TupleTableSlot *s
13911391 return true;
13921392}
13931393
1394+ void
1395+ heap_set_tidrange (TableScanDesc sscan , ItemPointer mintid ,
1396+ ItemPointer maxtid )
1397+ {
1398+ HeapScanDesc scan = (HeapScanDesc ) sscan ;
1399+ BlockNumber startBlk ;
1400+ BlockNumber numBlks ;
1401+ ItemPointerData highestItem ;
1402+ ItemPointerData lowestItem ;
1403+
1404+ /*
1405+ * For relations without any pages, we can simply leave the TID range
1406+ * unset. There will be no tuples to scan, therefore no tuples outside
1407+ * the given TID range.
1408+ */
1409+ if (scan -> rs_nblocks == 0 )
1410+ return ;
1411+
1412+ /*
1413+ * Set up some ItemPointers which point to the first and last possible
1414+ * tuples in the heap.
1415+ */
1416+ ItemPointerSet (& highestItem , scan -> rs_nblocks - 1 , MaxOffsetNumber );
1417+ ItemPointerSet (& lowestItem , 0 , FirstOffsetNumber );
1418+
1419+ /*
1420+ * If the given maximum TID is below the highest possible TID in the
1421+ * relation, then restrict the range to that, otherwise we scan to the end
1422+ * of the relation.
1423+ */
1424+ if (ItemPointerCompare (maxtid , & highestItem ) < 0 )
1425+ ItemPointerCopy (maxtid , & highestItem );
1426+
1427+ /*
1428+ * If the given minimum TID is above the lowest possible TID in the
1429+ * relation, then restrict the range to only scan for TIDs above that.
1430+ */
1431+ if (ItemPointerCompare (mintid , & lowestItem ) > 0 )
1432+ ItemPointerCopy (mintid , & lowestItem );
1433+
1434+ /*
1435+ * Check for an empty range and protect from would be negative results
1436+ * from the numBlks calculation below.
1437+ */
1438+ if (ItemPointerCompare (& highestItem , & lowestItem ) < 0 )
1439+ {
1440+ /* Set an empty range of blocks to scan */
1441+ heap_setscanlimits (sscan , 0 , 0 );
1442+ return ;
1443+ }
1444+
1445+ /*
1446+ * Calculate the first block and the number of blocks we must scan. We
1447+ * could be more aggressive here and perform some more validation to try
1448+ * and further narrow the scope of blocks to scan by checking if the
1449+ * lowerItem has an offset above MaxOffsetNumber. In this case, we could
1450+ * advance startBlk by one. Likewise, if highestItem has an offset of 0
1451+ * we could scan one fewer blocks. However, such an optimization does not
1452+ * seem worth troubling over, currently.
1453+ */
1454+ startBlk = ItemPointerGetBlockNumberNoCheck (& lowestItem );
1455+
1456+ numBlks = ItemPointerGetBlockNumberNoCheck (& highestItem ) -
1457+ ItemPointerGetBlockNumberNoCheck (& lowestItem ) + 1 ;
1458+
1459+ /* Set the start block and number of blocks to scan */
1460+ heap_setscanlimits (sscan , startBlk , numBlks );
1461+
1462+ /* Finally, set the TID range in sscan */
1463+ ItemPointerCopy (& lowestItem , & sscan -> rs_mintid );
1464+ ItemPointerCopy (& highestItem , & sscan -> rs_maxtid );
1465+ }
1466+
1467+ bool
1468+ heap_getnextslot_tidrange (TableScanDesc sscan , ScanDirection direction ,
1469+ TupleTableSlot * slot )
1470+ {
1471+ HeapScanDesc scan = (HeapScanDesc ) sscan ;
1472+ ItemPointer mintid = & sscan -> rs_mintid ;
1473+ ItemPointer maxtid = & sscan -> rs_maxtid ;
1474+
1475+ /* Note: no locking manipulations needed */
1476+ for (;;)
1477+ {
1478+ if (sscan -> rs_flags & SO_ALLOW_PAGEMODE )
1479+ heapgettup_pagemode (scan , direction , sscan -> rs_nkeys , sscan -> rs_key );
1480+ else
1481+ heapgettup (scan , direction , sscan -> rs_nkeys , sscan -> rs_key );
1482+
1483+ if (scan -> rs_ctup .t_data == NULL )
1484+ {
1485+ ExecClearTuple (slot );
1486+ return false;
1487+ }
1488+
1489+ /*
1490+ * heap_set_tidrange will have used heap_setscanlimits to limit the
1491+ * range of pages we scan to only ones that can contain the TID range
1492+ * we're scanning for. Here we must filter out any tuples from these
1493+ * pages that are outwith that range.
1494+ */
1495+ if (ItemPointerCompare (& scan -> rs_ctup .t_self , mintid ) < 0 )
1496+ {
1497+ ExecClearTuple (slot );
1498+
1499+ /*
1500+ * When scanning backwards, the TIDs will be in descending order.
1501+ * Future tuples in this direction will be lower still, so we can
1502+ * just return false to indicate there will be no more tuples.
1503+ */
1504+ if (ScanDirectionIsBackward (direction ))
1505+ return false;
1506+
1507+ continue ;
1508+ }
1509+
1510+ /*
1511+ * Likewise for the final page, we must filter out TIDs greater than
1512+ * maxtid.
1513+ */
1514+ if (ItemPointerCompare (& scan -> rs_ctup .t_self , maxtid ) > 0 )
1515+ {
1516+ ExecClearTuple (slot );
1517+
1518+ /*
1519+ * When scanning forward, the TIDs will be in ascending order.
1520+ * Future tuples in this direction will be higher still, so we can
1521+ * just return false to indicate there will be no more tuples.
1522+ */
1523+ if (ScanDirectionIsForward (direction ))
1524+ return false;
1525+ continue ;
1526+ }
1527+
1528+ break ;
1529+ }
1530+
1531+ /*
1532+ * if we get here it means we have a new current scan tuple, so point to
1533+ * the proper return buffer and return the tuple.
1534+ */
1535+ pgstat_count_heap_getnext (scan -> rs_base .rs_rd );
1536+
1537+ ExecStoreBufferHeapTuple (& scan -> rs_ctup , slot , scan -> rs_cbuf );
1538+ return true;
1539+ }
1540+
13941541/*
13951542 * heap_fetch - retrieve tuple with given tid
13961543 *
0 commit comments