From c0d7155fb0af55295b3bcd598c083b4690c538dd Mon Sep 17 00:00:00 2001
From: Melanie Plageman <melanieplageman@gmail.com>
Date: Tue, 10 Jan 2023 14:06:56 -0500
Subject: [PATCH v7 4/6] Add heapgettup() helpers

Add heapgettup_start_page() and heapgettup_continue_page(), helper
functions for heapgettup().
---
 src/backend/access/heap/heapam.c | 110 ++++++++++++++++++++++---------
 1 file changed, 79 insertions(+), 31 deletions(-)

diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 4e238d9558..223bb1d5d3 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -545,6 +545,83 @@ heapgettup_initial_block(HeapScanDesc scan, ScanDirection dir)
 	return scan->rs_nblocks - 1;
 }
 
+
+/*
+ * heapgettup_start_page - helper for heapgettup()
+ *
+ * Given a scan descriptor with a valid buffer referenced in rs_cbuf containing
+ * a block which we have yet to scan, set our lineoff at the tuple we will
+ * start with and our linesleft to the number of tuples in the page. Return the
+ * page associated with that buffer.
+ */
+static inline Page
+heapgettup_start_page(HeapScanDesc scan, ScanDirection dir, int *linesleft,
+					  OffsetNumber *lineoff)
+{
+	Page		page;
+
+	Assert(scan->rs_inited);
+	Assert(BufferIsValid(scan->rs_cbuf));
+
+	/* Caller is responsible for ensuring buffer is locked if needed */
+	page = BufferGetPage(scan->rs_cbuf);
+
+	TestForOldSnapshot(scan->rs_base.rs_snapshot, scan->rs_base.rs_rd, page);
+
+	*linesleft = PageGetMaxOffsetNumber((Page) page) - FirstOffsetNumber + 1;
+
+	if (ScanDirectionIsForward(dir))
+		*lineoff = FirstOffsetNumber;
+	else
+		*lineoff = (OffsetNumber) (*linesleft);
+
+	/* lineoff now references the physically previous or next tid */
+	return page;
+}
+
+
+/*
+ * heapgettup_continue_page - helper for heapgettup()
+ *
+ * Given a scan descriptor with a valid buffer referenced in rs_cbuf containing
+ * a block from which we have already fetched some tuples, set the lineoff to
+ * the start of the next tuple to fetch and update linesleft. Return the page
+ * associated with that buffer.
+ */
+static inline Page
+heapgettup_continue_page(HeapScanDesc scan, ScanDirection dir, int *linesleft,
+						 OffsetNumber *lineoff)
+{
+	Page		page;
+
+	Assert(scan->rs_inited);
+	Assert(BufferIsValid(scan->rs_cbuf));
+
+	/* Caller is responsible for ensuring buffer is locked if needed */
+	page = BufferGetPage(scan->rs_cbuf);
+
+	TestForOldSnapshot(scan->rs_base.rs_snapshot, scan->rs_base.rs_rd, page);
+
+	if (ScanDirectionIsForward(dir))
+	{
+		*lineoff = OffsetNumberNext(scan->rs_cindex);
+		*linesleft = PageGetMaxOffsetNumber(page) - (*lineoff) + 1;
+	}
+	else
+	{
+		/*
+		 * The previous returned tuple may have been vacuumed since the
+		 * previous scan when we use a non-MVCC snapshot, so we must
+		 * re-establish the lineoff <= PageGetMaxOffsetNumber(page) invariant
+		 */
+		*lineoff = Min(PageGetMaxOffsetNumber(page), OffsetNumberPrev(scan->rs_cindex));
+		*linesleft = *lineoff;
+	}
+
+	/* lineoff now references the physically previous or next tid */
+	return page;
+}
+
 /* ----------------
  *		heapgettup - fetch next heap tuple
  *
@@ -605,43 +682,14 @@ heapgettup(HeapScanDesc scan,
 		heapgetpage((TableScanDesc) scan, block);
 
 		LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
-		page = BufferGetPage(scan->rs_cbuf);
-		TestForOldSnapshot(scan->rs_base.rs_snapshot, scan->rs_base.rs_rd,
-						   page);
-
-		linesleft = PageGetMaxOffsetNumber(page) - FirstOffsetNumber + 1;
-
-		if (ScanDirectionIsForward(dir))
-			lineoff = FirstOffsetNumber;
-		else
-			lineoff = (OffsetNumber) linesleft;
+		page = heapgettup_start_page(scan, dir, &linesleft, &lineoff);
 	}
 	else
 	{
 		block = scan->rs_cblock;
 
 		LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
-		page = BufferGetPage(scan->rs_cbuf);
-		TestForOldSnapshot(scan->rs_base.rs_snapshot, scan->rs_base.rs_rd, page);
-
-		if (ScanDirectionIsForward(dir))
-		{
-			lineoff = OffsetNumberNext(scan->rs_cindex);
-			linesleft = PageGetMaxOffsetNumber(page) - lineoff + 1;
-		}
-		else
-		{
-			/*
-			 * The previous returned tuple may have been vacuumed since the
-			 * previous scan when we use a non-MVCC snapshot, so we must
-			 * re-establish the lineoff <= PageGetMaxOffsetNumber(page)
-			 * invariant
-			 */
-			lineoff =
-				Min(PageGetMaxOffsetNumber(page),
-					OffsetNumberPrev(scan->rs_cindex));
-			linesleft = lineoff;
-		}
+		page = heapgettup_continue_page(scan, dir, &linesleft, &lineoff);
 	}
 
 
-- 
2.37.2

