Clarify why _bt_killitems sorts its items array.
authorPeter Geoghegan <[email protected]>
Thu, 11 Dec 2025 01:50:47 +0000 (20:50 -0500)
committerPeter Geoghegan <[email protected]>
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 <[email protected]>
Suggested-by: Victor Yegorov <[email protected]>
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)