diff --git a/src/backend/access/nbtree/nbtsearch.c b/src/backend/access/nbtree/nbtsearch.c index 15f3bec1ab0..e0bbb97cbec 100644 --- a/src/backend/access/nbtree/nbtsearch.c +++ b/src/backend/access/nbtree/nbtsearch.c @@ -1628,6 +1628,7 @@ _bt_readpage(IndexScanDesc scan, ScanDirection dir, OffsetNumber offnum, * corresponding need for the left-link, since splits always go right. */ so->currPos.nextPage = opaque->btpo_next; + so->currPos.dir = dir; /* initialize tuple workspace to empty */ so->currPos.nextTupleOffset = 0; @@ -2083,16 +2084,24 @@ _bt_steppage(IndexScanDesc scan, ScanDirection dir) * In effect, btrestpos leaves advancing the arrays up to the first * _bt_readpage call (that takes place after it has restored markPos). */ - Assert(so->markPos.dir == dir); if (so->needPrimScan) { - if (ScanDirectionIsForward(dir)) + if (ScanDirectionIsForward(so->currPos.dir)) so->markPos.moreRight = true; else so->markPos.moreLeft = true; } } + /* + * Cancel primitive index scans that were scheduled when the call to + * _bt_readpage for currPos happened to use the opposite direction to the + * one that we're stepping in now. (It's okay to leave the scan's array + * keys as-is, since the next _bt_readpage will advance them.) + */ + if (so->currPos.dir != dir) + so->needPrimScan = false; + if (ScanDirectionIsForward(dir)) { /* Walk right to the next page with data */ @@ -2653,7 +2662,6 @@ _bt_endpoint(IndexScanDesc scan, ScanDirection dir) static inline void _bt_initialize_more_data(BTScanOpaque so, ScanDirection dir) { - so->currPos.dir = dir; if (so->needPrimScan) { Assert(so->numArrayKeys); diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c index c22ccec789d..8d047d8873f 100644 --- a/src/backend/access/nbtree/nbtutils.c +++ b/src/backend/access/nbtree/nbtutils.c @@ -2426,8 +2426,10 @@ new_prim_scan: /* * End this primitive index scan, but schedule another. * - * Note: If the scan direction happens to change, this scheduled primitive - * index scan won't go ahead after all. + * Note: We make a soft assumption that the current scan direction will + * also be used within _bt_next, when it is asked to step off this page. + * It is up to _bt_next to cancel this scheduled primitive index scan + * whenever it steps to a page in the direction opposite currPos.dir. */ pstate->continuescan = false; /* Tell _bt_readpage we're done... */ so->needPrimScan = true; /* ...but call _bt_first again */