From 3d261105e8498a6309b612419a23cc3012caf03b Mon Sep 17 00:00:00 2001
From: Peter Geoghegan <pg@bowt.ie>
Date: Thu, 1 May 2025 14:58:02 -0400
Subject: [PATCH v1 2/2] Prevent prematurely nbtree array advancement.

Prevent forcenonrequired from prematurely advancing the scan's array
keys beyond key space that the scan has yet to read tuples from.  Do
this by defensively resetting the scan's array keys (to the first array
elements for the current scan direction) before the _bt_checkkeys call
for pstate.finaltup.  Otherwise, it's possible for the scan to fail to
return matching tuples in rare edge cases.

Oversight in commit 8a510275.
---
 src/backend/access/nbtree/nbtsearch.c | 3 +++
 src/backend/access/nbtree/nbtutils.c  | 2 ++
 2 files changed, 5 insertions(+)

diff --git a/src/backend/access/nbtree/nbtsearch.c b/src/backend/access/nbtree/nbtsearch.c
index 77264ddee..e9e53cd7e 100644
--- a/src/backend/access/nbtree/nbtsearch.c
+++ b/src/backend/access/nbtree/nbtsearch.c
@@ -1791,6 +1791,8 @@ _bt_readpage(IndexScanDesc scan, ScanDirection dir, OffsetNumber offnum,
 			int			truncatt;
 
 			truncatt = BTreeTupleGetNAtts(itup, rel);
+			if (pstate.forcenonrequired)
+				_bt_start_array_keys(scan, dir);
 			pstate.forcenonrequired = false;
 			pstate.startikey = 0;	/* _bt_set_startikey ignores P_HIKEY */
 			_bt_checkkeys(scan, &pstate, arrayKeys, itup, truncatt);
@@ -1881,6 +1883,7 @@ _bt_readpage(IndexScanDesc scan, ScanDirection dir, OffsetNumber offnum,
 			{
 				pstate.forcenonrequired = false;
 				pstate.startikey = 0;
+				_bt_start_array_keys(scan, dir);
 			}
 			passes_quals = _bt_checkkeys(scan, &pstate, arrayKeys,
 										 itup, indnatts);
diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c
index 2fbbbc31f..91ff52868 100644
--- a/src/backend/access/nbtree/nbtutils.c
+++ b/src/backend/access/nbtree/nbtutils.c
@@ -2546,6 +2546,8 @@ _bt_set_startikey(IndexScanDesc scan, BTReadPageState *pstate)
 			 * Can't let pstate.startikey get set to an ikey beyond a
 			 * RowCompare inequality
 			 */
+			if (start_past_saop_eq || so->skipScan)
+				return;
 			break;				/* unsafe */
 		}
 		if (key->sk_strategy != BTEqualStrategyNumber)
-- 
2.49.0

