@@ -620,6 +620,91 @@ heapgettup_continue_page(HeapScanDesc scan, ScanDirection dir, int *linesleft,
620620 return page ;
621621}
622622
623+ /*
624+ * heapgettup_advance_block - helper for heapgettup() and heapgettup_pagemode()
625+ *
626+ * Given the current block number, the scan direction, and various information
627+ * contained in the scan descriptor, calculate the BlockNumber to scan next
628+ * and return it. If there are no further blocks to scan, return
629+ * InvalidBlockNumber to indicate this fact to the caller.
630+ *
631+ * This should not be called to determine the initial block number -- only for
632+ * subsequent blocks.
633+ *
634+ * This also adjusts rs_numblocks when a limit has been imposed by
635+ * heap_setscanlimits().
636+ */
637+ static inline BlockNumber
638+ heapgettup_advance_block (HeapScanDesc scan , BlockNumber block , ScanDirection dir )
639+ {
640+ if (ScanDirectionIsForward (dir ))
641+ {
642+ if (scan -> rs_base .rs_parallel == NULL )
643+ {
644+ block ++ ;
645+
646+ /* wrap back to the start of the heap */
647+ if (block >= scan -> rs_nblocks )
648+ block = 0 ;
649+
650+ /* we're done if we're back at where we started */
651+ if (block == scan -> rs_startblock )
652+ return InvalidBlockNumber ;
653+
654+ /* check if the limit imposed by heap_setscanlimits() is met */
655+ if (scan -> rs_numblocks != InvalidBlockNumber )
656+ {
657+ if (-- scan -> rs_numblocks == 0 )
658+ return InvalidBlockNumber ;
659+ }
660+
661+ /*
662+ * Report our new scan position for synchronization purposes. We
663+ * don't do that when moving backwards, however. That would just
664+ * mess up any other forward-moving scanners.
665+ *
666+ * Note: we do this before checking for end of scan so that the
667+ * final state of the position hint is back at the start of the
668+ * rel. That's not strictly necessary, but otherwise when you run
669+ * the same query multiple times the starting position would shift
670+ * a little bit backwards on every invocation, which is confusing.
671+ * We don't guarantee any specific ordering in general, though.
672+ */
673+ if (scan -> rs_base .rs_flags & SO_ALLOW_SYNC )
674+ ss_report_location (scan -> rs_base .rs_rd , block );
675+
676+ return block ;
677+ }
678+ else
679+ {
680+ return table_block_parallelscan_nextpage (scan -> rs_base .rs_rd ,
681+ scan -> rs_parallelworkerdata , (ParallelBlockTableScanDesc )
682+ scan -> rs_base .rs_parallel );
683+ }
684+ }
685+ else
686+ {
687+ /* we're done if the last block is the start position */
688+ if (block == scan -> rs_startblock )
689+ return InvalidBlockNumber ;
690+
691+ /* check if the limit imposed by heap_setscanlimits() is met */
692+ if (scan -> rs_numblocks != InvalidBlockNumber )
693+ {
694+ if (-- scan -> rs_numblocks == 0 )
695+ return InvalidBlockNumber ;
696+ }
697+
698+ /* wrap to the end of the heap when the last page was page 0 */
699+ if (block == 0 )
700+ block = scan -> rs_nblocks ;
701+
702+ block -- ;
703+
704+ return block ;
705+ }
706+ }
707+
623708/* ----------------
624709 * heapgettup - fetch next heap tuple
625710 *
@@ -649,7 +734,6 @@ heapgettup(HeapScanDesc scan,
649734 HeapTuple tuple = & (scan -> rs_ctup );
650735 bool backward = ScanDirectionIsBackward (dir );
651736 BlockNumber block ;
652- bool finished ;
653737 Page page ;
654738 OffsetNumber lineoff ;
655739 int linesleft ;
@@ -755,56 +839,13 @@ heapgettup(HeapScanDesc scan,
755839 */
756840 LockBuffer (scan -> rs_cbuf , BUFFER_LOCK_UNLOCK );
757841
758- /*
759- * advance to next/prior page and detect end of scan
760- */
761- if (backward )
762- {
763- finished = (block == scan -> rs_startblock ) ||
764- (scan -> rs_numblocks != InvalidBlockNumber ? -- scan -> rs_numblocks == 0 : false);
765- if (block == 0 )
766- block = scan -> rs_nblocks ;
767- block -- ;
768- }
769- else if (scan -> rs_base .rs_parallel != NULL )
770- {
771- ParallelBlockTableScanDesc pbscan =
772- (ParallelBlockTableScanDesc ) scan -> rs_base .rs_parallel ;
773- ParallelBlockTableScanWorker pbscanwork =
774- scan -> rs_parallelworkerdata ;
775-
776- block = table_block_parallelscan_nextpage (scan -> rs_base .rs_rd ,
777- pbscanwork , pbscan );
778- finished = (block == InvalidBlockNumber );
779- }
780- else
781- {
782- block ++ ;
783- if (block >= scan -> rs_nblocks )
784- block = 0 ;
785- finished = (block == scan -> rs_startblock ) ||
786- (scan -> rs_numblocks != InvalidBlockNumber ? -- scan -> rs_numblocks == 0 : false);
787-
788- /*
789- * Report our new scan position for synchronization purposes. We
790- * don't do that when moving backwards, however. That would just
791- * mess up any other forward-moving scanners.
792- *
793- * Note: we do this before checking for end of scan so that the
794- * final state of the position hint is back at the start of the
795- * rel. That's not strictly necessary, but otherwise when you run
796- * the same query multiple times the starting position would shift
797- * a little bit backwards on every invocation, which is confusing.
798- * We don't guarantee any specific ordering in general, though.
799- */
800- if (scan -> rs_base .rs_flags & SO_ALLOW_SYNC )
801- ss_report_location (scan -> rs_base .rs_rd , block );
802- }
842+ /* get the BlockNumber to scan next */
843+ block = heapgettup_advance_block (scan , block , dir );
803844
804845 /*
805846 * return NULL if we've exhausted all the pages
806847 */
807- if (finished )
848+ if (block == InvalidBlockNumber )
808849 {
809850 if (BufferIsValid (scan -> rs_cbuf ))
810851 ReleaseBuffer (scan -> rs_cbuf );
@@ -858,7 +899,6 @@ heapgettup_pagemode(HeapScanDesc scan,
858899 HeapTuple tuple = & (scan -> rs_ctup );
859900 bool backward = ScanDirectionIsBackward (dir );
860901 BlockNumber block ;
861- bool finished ;
862902 Page page ;
863903 int lineindex ;
864904 OffsetNumber lineoff ;
@@ -949,57 +989,13 @@ heapgettup_pagemode(HeapScanDesc scan,
949989 ++ lineindex ;
950990 }
951991
952- /*
953- * if we get here, it means we've exhausted the items on this page and
954- * it's time to move to the next.
955- */
956- if (backward )
957- {
958- finished = (block == scan -> rs_startblock ) ||
959- (scan -> rs_numblocks != InvalidBlockNumber ? -- scan -> rs_numblocks == 0 : false);
960- if (block == 0 )
961- block = scan -> rs_nblocks ;
962- block -- ;
963- }
964- else if (scan -> rs_base .rs_parallel != NULL )
965- {
966- ParallelBlockTableScanDesc pbscan =
967- (ParallelBlockTableScanDesc ) scan -> rs_base .rs_parallel ;
968- ParallelBlockTableScanWorker pbscanwork =
969- scan -> rs_parallelworkerdata ;
970-
971- block = table_block_parallelscan_nextpage (scan -> rs_base .rs_rd ,
972- pbscanwork , pbscan );
973- finished = (block == InvalidBlockNumber );
974- }
975- else
976- {
977- block ++ ;
978- if (block >= scan -> rs_nblocks )
979- block = 0 ;
980- finished = (block == scan -> rs_startblock ) ||
981- (scan -> rs_numblocks != InvalidBlockNumber ? -- scan -> rs_numblocks == 0 : false);
982-
983- /*
984- * Report our new scan position for synchronization purposes. We
985- * don't do that when moving backwards, however. That would just
986- * mess up any other forward-moving scanners.
987- *
988- * Note: we do this before checking for end of scan so that the
989- * final state of the position hint is back at the start of the
990- * rel. That's not strictly necessary, but otherwise when you run
991- * the same query multiple times the starting position would shift
992- * a little bit backwards on every invocation, which is confusing.
993- * We don't guarantee any specific ordering in general, though.
994- */
995- if (scan -> rs_base .rs_flags & SO_ALLOW_SYNC )
996- ss_report_location (scan -> rs_base .rs_rd , block );
997- }
992+ /* get the BlockNumber to scan next */
993+ block = heapgettup_advance_block (scan , block , dir );
998994
999995 /*
1000996 * return NULL if we've exhausted all the pages
1001997 */
1002- if (finished )
998+ if (block == InvalidBlockNumber )
1003999 {
10041000 if (BufferIsValid (scan -> rs_cbuf ))
10051001 ReleaseBuffer (scan -> rs_cbuf );
0 commit comments