From 9e0f7dfa43e0980172d07c2341896f4cb7bf5a14 Mon Sep 17 00:00:00 2001
From: Melanie Plageman <melanieplageman@gmail.com>
Date: Fri, 6 Jan 2023 12:39:38 -0500
Subject: [PATCH v6 1/6] Add no movement scan helper

No movement scan can be handled first in heapgettup() and
heapgettup_pagemode(). Refactor this case into its own helper function
to improve readability.
---
 src/backend/access/heap/heapam.c | 124 +++++++++++++++----------------
 1 file changed, 62 insertions(+), 62 deletions(-)

diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index e6024a980b..ab783b2af1 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -483,6 +483,52 @@ heapgetpage(TableScanDesc sscan, BlockNumber block)
 	scan->rs_ntuples = ntup;
 }
 
+
+/*
+ * helper function used by heapgettup() and heapgettup_pagemode() for
+ * NoMovementScanDirection scans.
+ * 'no movement' scans refetch the prior tuple.
+ */
+static void
+heapgettup_no_movement(HeapScanDesc scan)
+{
+	BlockNumber block;
+	OffsetNumber lineoff;
+	ItemId		lpp;
+	Page		page;
+	HeapTuple	tuple = &(scan->rs_ctup);
+
+	if (!scan->rs_inited)
+	{
+		Assert(!BufferIsValid(scan->rs_cbuf));
+		tuple->t_data = NULL;
+		return;
+	}
+
+	block = ItemPointerGetBlockNumber(&(tuple->t_self));
+	if (block != scan->rs_cblock)
+		heapgetpage((TableScanDesc) scan, block);
+
+	/* Since the tuple was previously fetched, needn't lock page here */
+	page = BufferGetPage(scan->rs_cbuf);
+	TestForOldSnapshot(scan->rs_base.rs_snapshot, scan->rs_base.rs_rd, page);
+	lineoff = ItemPointerGetOffsetNumber(&(tuple->t_self));
+	lpp = PageGetItemId(page, lineoff);
+	Assert(ItemIdIsNormal(lpp));
+
+	tuple->t_data = (HeapTupleHeader) PageGetItem(page, lpp);
+	tuple->t_len = ItemIdGetLength(lpp);
+
+	/* in pagemode, check that rs_cindex is in sync */
+	Assert((scan->rs_base.rs_flags & SO_ALLOW_PAGEMODE) == 0 ||
+		   scan->rs_cindex < scan->rs_ntuples);
+	Assert((scan->rs_base.rs_flags & SO_ALLOW_PAGEMODE) == 0 ||
+		   lineoff == scan->rs_vistuples[scan->rs_cindex]);
+
+	return;
+}
+
+
 /* ----------------
  *		heapgettup - fetch next heap tuple
  *
@@ -523,6 +569,12 @@ heapgettup(HeapScanDesc scan,
 	int			linesleft;
 	ItemId		lpp;
 
+	if (unlikely(ScanDirectionIsNoMovement(dir)))
+	{
+		heapgettup_no_movement(scan);
+		return;
+	}
+
 	/*
 	 * calculate next starting lineoff, given scan direction
 	 */
@@ -583,8 +635,9 @@ heapgettup(HeapScanDesc scan,
 
 		linesleft = lines - lineoff + 1;
 	}
-	else if (backward)
+	else
 	{
+		Assert(backward);
 		/* backward parallel scan not supported */
 		Assert(scan->rs_base.rs_parallel == NULL);
 
@@ -653,34 +706,6 @@ heapgettup(HeapScanDesc scan,
 
 		linesleft = lineoff;
 	}
-	else
-	{
-		/*
-		 * ``no movement'' scan direction: refetch prior tuple
-		 */
-		if (!scan->rs_inited)
-		{
-			Assert(!BufferIsValid(scan->rs_cbuf));
-			tuple->t_data = NULL;
-			return;
-		}
-
-		block = ItemPointerGetBlockNumber(&(tuple->t_self));
-		if (block != scan->rs_cblock)
-			heapgetpage((TableScanDesc) scan, block);
-
-		/* Since the tuple was previously fetched, needn't lock page here */
-		page = BufferGetPage(scan->rs_cbuf);
-		TestForOldSnapshot(snapshot, scan->rs_base.rs_rd, page);
-		lineoff = ItemPointerGetOffsetNumber(&(tuple->t_self));
-		lpp = PageGetItemId(page, lineoff);
-		Assert(ItemIdIsNormal(lpp));
-
-		tuple->t_data = (HeapTupleHeader) PageGetItem(page, lpp);
-		tuple->t_len = ItemIdGetLength(lpp);
-
-		return;
-	}
 
 	/*
 	 * advance the scan until we find a qualifying tuple or run out of stuff
@@ -861,6 +886,12 @@ heapgettup_pagemode(HeapScanDesc scan,
 	int			linesleft;
 	ItemId		lpp;
 
+	if (unlikely(ScanDirectionIsNoMovement(dir)))
+	{
+		heapgettup_no_movement(scan);
+		return;
+	}
+
 	/*
 	 * calculate next starting lineindex, given scan direction
 	 */
@@ -918,8 +949,9 @@ heapgettup_pagemode(HeapScanDesc scan,
 
 		linesleft = lines - lineindex;
 	}
-	else if (backward)
+	else
 	{
+		Assert(backward);
 		/* backward parallel scan not supported */
 		Assert(scan->rs_base.rs_parallel == NULL);
 
@@ -978,38 +1010,6 @@ heapgettup_pagemode(HeapScanDesc scan,
 
 		linesleft = lineindex + 1;
 	}
-	else
-	{
-		/*
-		 * ``no movement'' scan direction: refetch prior tuple
-		 */
-		if (!scan->rs_inited)
-		{
-			Assert(!BufferIsValid(scan->rs_cbuf));
-			tuple->t_data = NULL;
-			return;
-		}
-
-		block = ItemPointerGetBlockNumber(&(tuple->t_self));
-		if (block != scan->rs_cblock)
-			heapgetpage((TableScanDesc) scan, block);
-
-		/* Since the tuple was previously fetched, needn't lock page here */
-		page = BufferGetPage(scan->rs_cbuf);
-		TestForOldSnapshot(scan->rs_base.rs_snapshot, scan->rs_base.rs_rd, page);
-		lineoff = ItemPointerGetOffsetNumber(&(tuple->t_self));
-		lpp = PageGetItemId(page, lineoff);
-		Assert(ItemIdIsNormal(lpp));
-
-		tuple->t_data = (HeapTupleHeader) PageGetItem(page, lpp);
-		tuple->t_len = ItemIdGetLength(lpp);
-
-		/* check that rs_cindex is in sync */
-		Assert(scan->rs_cindex < scan->rs_ntuples);
-		Assert(lineoff == scan->rs_vistuples[scan->rs_cindex]);
-
-		return;
-	}
 
 	/*
 	 * advance the scan until we find a qualifying tuple or run out of stuff
-- 
2.34.1

