Clarify why _bt_killitems sorts its items array.
authorPeter Geoghegan <pg@bowt.ie>
Thu, 11 Dec 2025 01:50:47 +0000 (20:50 -0500)
committerPeter Geoghegan <pg@bowt.ie>
Thu, 11 Dec 2025 01:50:47 +0000 (20:50 -0500)
Make it clear why _bt_killitems sorts the scan's so->killedItems[]
array.  Also add an assertion to the _bt_killitems loop (that iterates
through this array) to verify it accesses tuples in leaf page order.

Follow-up to commit bfb335df58.

Author: Peter Geoghegan <pg@bowt.ie>
Suggested-by: Victor Yegorov <vyegorov@gmail.com>
Discussion: https://postgr.es/m/CAGnEboirgArezZDNeFrR8FOGvKF-Xok333s2iVwWi65gZf8MEA@mail.gmail.com

src/backend/access/nbtree/nbtutils.c

index 16e23a517b2340fc9cef9a0d6f47ec2b5de6d7a5..a451d48e11ed12a4387571f6b3ea2646ee0ab873 100644 (file)
@@ -222,11 +222,12 @@ _bt_killitems(IndexScanDesc scan)
    so->numKilled = 0;
 
    /*
-    * so->killedItems[] is in whatever order the scan returned items in.
-    * Items will appear in descending order during backwards scans.  And
-    * scrollable cursor scans might have duplicate items.
+    * We need to iterate through so->killedItems[] in leaf page order; the
+    * loop below expects this (when marking posting list tuples, at least).
+    * so->killedItems[] is now in whatever order the scan returned items in.
+    * Scrollable cursor scans might have even saved the same item/TID twice.
     *
-    * Sort and uniqueify so->killedItems[] to deal with all this.
+    * Sort and unique-ify so->killedItems[] to deal with all this.
     */
    if (numKilled > 1)
    {
@@ -271,6 +272,7 @@ _bt_killitems(IndexScanDesc scan)
    minoff = P_FIRSTDATAKEY(opaque);
    maxoff = PageGetMaxOffsetNumber(page);
 
+   /* Iterate through so->killedItems[] in leaf page order */
    for (int i = 0; i < numKilled; i++)
    {
        int         itemIndex = so->killedItems[i];
@@ -279,6 +281,9 @@ _bt_killitems(IndexScanDesc scan)
 
        Assert(itemIndex >= so->currPos.firstItem &&
               itemIndex <= so->currPos.lastItem);
+       Assert(i == 0 ||
+              offnum >= so->currPos.items[so->killedItems[i - 1]].indexOffset);
+
        if (offnum < minoff)
            continue;           /* pure paranoia */
        while (offnum <= maxoff)