@@ -567,7 +567,7 @@ heapgettup_start_page(HeapScanDesc scan, ScanDirection dir, int *linesleft,
567567
568568 TestForOldSnapshot (scan -> rs_base .rs_snapshot , scan -> rs_base .rs_rd , page );
569569
570- * linesleft = PageGetMaxOffsetNumber (( Page ) page ) - FirstOffsetNumber + 1 ;
570+ * linesleft = PageGetMaxOffsetNumber (page ) - FirstOffsetNumber + 1 ;
571571
572572 if (ScanDirectionIsForward (dir ))
573573 * lineoff = FirstOffsetNumber ;
@@ -732,34 +732,17 @@ heapgettup(HeapScanDesc scan,
732732 ScanKey key )
733733{
734734 HeapTuple tuple = & (scan -> rs_ctup );
735- bool backward = ScanDirectionIsBackward (dir );
736735 BlockNumber block ;
737736 Page page ;
738737 OffsetNumber lineoff ;
739738 int linesleft ;
740- ItemId lpp ;
741739
742740 if (unlikely (!scan -> rs_inited ))
743741 {
744742 block = heapgettup_initial_block (scan , dir );
745-
746- /*
747- * Check if we have reached the end of the scan already. This could
748- * happen if the table is empty or if the parallel workers have
749- * already finished the scan before we did anything ourselves
750- */
751- if (block == InvalidBlockNumber )
752- {
753- Assert (!BufferIsValid (scan -> rs_cbuf ));
754- tuple -> t_data = NULL ;
755- return ;
756- }
743+ /* ensure rs_cbuf is invalid when we get InvalidBlockNumber */
744+ Assert (block != InvalidBlockNumber || !BufferIsValid (scan -> rs_cbuf ));
757745 scan -> rs_inited = true;
758-
759- heapgetpage ((TableScanDesc ) scan , block );
760-
761- LockBuffer (scan -> rs_cbuf , BUFFER_LOCK_SHARE );
762- page = heapgettup_start_page (scan , dir , & linesleft , & lineoff );
763746 }
764747 else
765748 {
@@ -768,69 +751,60 @@ heapgettup(HeapScanDesc scan,
768751
769752 LockBuffer (scan -> rs_cbuf , BUFFER_LOCK_SHARE );
770753 page = heapgettup_continue_page (scan , dir , & linesleft , & lineoff );
754+ goto continue_page ;
771755 }
772756
773757 /*
774758 * advance the scan until we find a qualifying tuple or run out of stuff
775759 * to scan
776760 */
777- lpp = PageGetItemId (page , lineoff );
778- for (;;)
761+ while (block != InvalidBlockNumber )
779762 {
763+ heapgetpage ((TableScanDesc ) scan , block );
764+ LockBuffer (scan -> rs_cbuf , BUFFER_LOCK_SHARE );
765+ page = heapgettup_start_page (scan , dir , & linesleft , & lineoff );
766+ continue_page :
767+
780768 /*
781769 * Only continue scanning the page while we have lines left.
782770 *
783771 * Note that this protects us from accessing line pointers past
784772 * PageGetMaxOffsetNumber(); both for forward scans when we resume the
785773 * table scan, and for when we start scanning a new page.
786774 */
787- while ( linesleft > 0 )
775+ for (; linesleft > 0 ; linesleft -- , lineoff += dir )
788776 {
789- if (ItemIdIsNormal (lpp ))
790- {
791- bool valid ;
777+ bool visible ;
778+ ItemId lpp = PageGetItemId (page , lineoff );
792779
793- tuple -> t_data = (HeapTupleHeader ) PageGetItem (page , lpp );
794- tuple -> t_len = ItemIdGetLength (lpp );
795- ItemPointerSet (& (tuple -> t_self ), block , lineoff );
780+ if (!ItemIdIsNormal (lpp ))
781+ continue ;
796782
797- /*
798- * if current tuple qualifies, return it.
799- */
800- valid = HeapTupleSatisfiesVisibility (tuple ,
801- scan -> rs_base .rs_snapshot ,
802- scan -> rs_cbuf );
783+ tuple -> t_data = (HeapTupleHeader ) PageGetItem (page , lpp );
784+ tuple -> t_len = ItemIdGetLength (lpp );
785+ ItemPointerSet (& (tuple -> t_self ), block , lineoff );
803786
804- HeapCheckForSerializableConflictOut ( valid , scan -> rs_base . rs_rd ,
805- tuple , scan -> rs_cbuf ,
806- scan -> rs_base . rs_snapshot );
787+ visible = HeapTupleSatisfiesVisibility ( tuple ,
788+ scan -> rs_base . rs_snapshot ,
789+ scan -> rs_cbuf );
807790
808- if ( valid && key != NULL )
809- valid = HeapKeyTest ( tuple , RelationGetDescr ( scan -> rs_base . rs_rd ) ,
810- nkeys , key );
791+ HeapCheckForSerializableConflictOut ( visible , scan -> rs_base . rs_rd ,
792+ tuple , scan -> rs_cbuf ,
793+ scan -> rs_base . rs_snapshot );
811794
812- if (valid )
813- {
814- LockBuffer (scan -> rs_cbuf , BUFFER_LOCK_UNLOCK );
815- scan -> rs_coffset = lineoff ;
816- return ;
817- }
818- }
795+ /* skip tuples not visible to this snapshot */
796+ if (!visible )
797+ continue ;
819798
820- /*
821- * otherwise move to the next item on the page
822- */
823- -- linesleft ;
824- if (backward )
825- {
826- -- lpp ; /* move back in this page's ItemId array */
827- -- lineoff ;
828- }
829- else
830- {
831- ++ lpp ; /* move forward in this page's ItemId array */
832- ++ lineoff ;
833- }
799+ /* skip any tuples that don't match the scan key */
800+ if (key != NULL &&
801+ !HeapKeyTest (tuple , RelationGetDescr (scan -> rs_base .rs_rd ),
802+ nkeys , key ))
803+ continue ;
804+
805+ LockBuffer (scan -> rs_cbuf , BUFFER_LOCK_UNLOCK );
806+ scan -> rs_coffset = lineoff ;
807+ return ;
834808 }
835809
836810 /*
@@ -841,40 +815,16 @@ heapgettup(HeapScanDesc scan,
841815
842816 /* get the BlockNumber to scan next */
843817 block = heapgettup_advance_block (scan , block , dir );
818+ }
844819
845- /*
846- * return NULL if we've exhausted all the pages
847- */
848- if (block == InvalidBlockNumber )
849- {
850- if (BufferIsValid (scan -> rs_cbuf ))
851- ReleaseBuffer (scan -> rs_cbuf );
852- scan -> rs_cbuf = InvalidBuffer ;
853- scan -> rs_cblock = InvalidBlockNumber ;
854- tuple -> t_data = NULL ;
855- scan -> rs_inited = false;
856- return ;
857- }
858-
859- heapgetpage ((TableScanDesc ) scan , block );
860-
861- LockBuffer (scan -> rs_cbuf , BUFFER_LOCK_SHARE );
820+ /* end of scan */
821+ if (BufferIsValid (scan -> rs_cbuf ))
822+ ReleaseBuffer (scan -> rs_cbuf );
862823
863- page = BufferGetPage (scan -> rs_cbuf );
864- TestForOldSnapshot (scan -> rs_base .rs_snapshot , scan -> rs_base .rs_rd ,
865- page );
866- linesleft = PageGetMaxOffsetNumber (page );
867- if (backward )
868- {
869- lineoff = linesleft ;
870- lpp = PageGetItemId (page , linesleft );
871- }
872- else
873- {
874- lineoff = FirstOffsetNumber ;
875- lpp = PageGetItemId (page , FirstOffsetNumber );
876- }
877- }
824+ scan -> rs_cbuf = InvalidBuffer ;
825+ scan -> rs_cblock = InvalidBlockNumber ;
826+ tuple -> t_data = NULL ;
827+ scan -> rs_inited = false;
878828}
879829
880830/* ----------------
@@ -897,35 +847,16 @@ heapgettup_pagemode(HeapScanDesc scan,
897847 ScanKey key )
898848{
899849 HeapTuple tuple = & (scan -> rs_ctup );
900- bool backward = ScanDirectionIsBackward (dir );
901850 BlockNumber block ;
902851 Page page ;
903852 int lineindex ;
904- OffsetNumber lineoff ;
905853 int linesleft ;
906- ItemId lpp ;
907854
908855 if (unlikely (!scan -> rs_inited ))
909856 {
910857 block = heapgettup_initial_block (scan , dir );
911-
912- /*
913- * Check if we have reached the end of the scan already. This could
914- * happen if the table is empty or if the other workers in a parallel
915- * scan have already finished the scan.
916- */
917- if (block == InvalidBlockNumber )
918- {
919- Assert (!BufferIsValid (scan -> rs_cbuf ));
920- tuple -> t_data = NULL ;
921- return ;
922- }
923-
924- heapgetpage ((TableScanDesc ) scan , block );
925- page = BufferGetPage (scan -> rs_cbuf );
926- TestForOldSnapshot (scan -> rs_base .rs_snapshot , scan -> rs_base .rs_rd , page );
927- linesleft = scan -> rs_ntuples ;
928- lineindex = ScanDirectionIsForward (dir ) ? 0 : linesleft - 1 ;
858+ /* ensure rs_cbuf is invalid when we get InvalidBlockNumber */
859+ Assert (block != InvalidBlockNumber || !BufferIsValid (scan -> rs_cbuf ));
929860 scan -> rs_inited = true;
930861 }
931862 else
@@ -940,16 +871,31 @@ heapgettup_pagemode(HeapScanDesc scan,
940871 linesleft = scan -> rs_ntuples - lineindex ;
941872 else
942873 linesleft = scan -> rs_cindex ;
874+ /* lineindex now references the next or previous visible tid */
875+
876+ goto continue_page ;
943877 }
944878
945879 /*
946880 * advance the scan until we find a qualifying tuple or run out of stuff
947881 * to scan
948882 */
949- for (;; )
883+ while ( block != InvalidBlockNumber )
950884 {
951- while (linesleft > 0 )
885+ heapgetpage ((TableScanDesc ) scan , block );
886+ page = BufferGetPage (scan -> rs_cbuf );
887+ TestForOldSnapshot (scan -> rs_base .rs_snapshot , scan -> rs_base .rs_rd , page );
888+ linesleft = scan -> rs_ntuples ;
889+ lineindex = ScanDirectionIsForward (dir ) ? 0 : linesleft - 1 ;
890+
891+ /* lineindex now references the next or previous visible tid */
892+ continue_page :
893+
894+ for (; linesleft > 0 ; linesleft -- , lineindex += dir )
952895 {
896+ ItemId lpp ;
897+ OffsetNumber lineoff ;
898+
953899 lineoff = scan -> rs_vistuples [lineindex ];
954900 lpp = PageGetItemId (page , lineoff );
955901 Assert (ItemIdIsNormal (lpp ));
@@ -958,64 +904,27 @@ heapgettup_pagemode(HeapScanDesc scan,
958904 tuple -> t_len = ItemIdGetLength (lpp );
959905 ItemPointerSet (& (tuple -> t_self ), block , lineoff );
960906
961- /*
962- * if current tuple qualifies, return it.
963- */
964- if (key != NULL )
965- {
966- bool valid ;
967-
968- valid = HeapKeyTest (tuple , RelationGetDescr (scan -> rs_base .rs_rd ),
969- nkeys , key );
970- if (valid )
971- {
972- scan -> rs_cindex = lineindex ;
973- return ;
974- }
975- }
976- else
977- {
978- scan -> rs_cindex = lineindex ;
979- return ;
980- }
907+ /* skip any tuples that don't match the scan key */
908+ if (key != NULL &&
909+ !HeapKeyTest (tuple , RelationGetDescr (scan -> rs_base .rs_rd ),
910+ nkeys , key ))
911+ continue ;
981912
982- /*
983- * otherwise move to the next item on the page
984- */
985- -- linesleft ;
986- if (backward )
987- -- lineindex ;
988- else
989- ++ lineindex ;
913+ scan -> rs_cindex = lineindex ;
914+ return ;
990915 }
991916
992917 /* get the BlockNumber to scan next */
993918 block = heapgettup_advance_block (scan , block , dir );
994-
995- /*
996- * return NULL if we've exhausted all the pages
997- */
998- if (block == InvalidBlockNumber )
999- {
1000- if (BufferIsValid (scan -> rs_cbuf ))
1001- ReleaseBuffer (scan -> rs_cbuf );
1002- scan -> rs_cbuf = InvalidBuffer ;
1003- scan -> rs_cblock = InvalidBlockNumber ;
1004- tuple -> t_data = NULL ;
1005- scan -> rs_inited = false;
1006- return ;
1007- }
1008-
1009- heapgetpage ((TableScanDesc ) scan , block );
1010-
1011- page = BufferGetPage (scan -> rs_cbuf );
1012- TestForOldSnapshot (scan -> rs_base .rs_snapshot , scan -> rs_base .rs_rd , page );
1013- linesleft = scan -> rs_ntuples ;
1014- if (backward )
1015- lineindex = linesleft - 1 ;
1016- else
1017- lineindex = 0 ;
1018919 }
920+
921+ /* end of scan */
922+ if (BufferIsValid (scan -> rs_cbuf ))
923+ ReleaseBuffer (scan -> rs_cbuf );
924+ scan -> rs_cbuf = InvalidBuffer ;
925+ scan -> rs_cblock = InvalidBlockNumber ;
926+ tuple -> t_data = NULL ;
927+ scan -> rs_inited = false;
1019928}
1020929
1021930
0 commit comments