diff --git a/src/backend/access/nbtree/nbtsearch.c b/src/backend/access/nbtree/nbtsearch.c index c33438c4bbd..b082cc80f6c 100644 --- a/src/backend/access/nbtree/nbtsearch.c +++ b/src/backend/access/nbtree/nbtsearch.c @@ -1568,6 +1568,7 @@ _bt_readpage(IndexScanDesc scan, ScanDirection dir, OffsetNumber offnum, Assert(!P_IGNORE(opaque)); Assert(BTScanPosIsPinned(so->currPos)); + Assert(!so->needPrimScan); if (scan->parallel_scan) { @@ -1594,7 +1595,6 @@ _bt_readpage(IndexScanDesc scan, ScanDirection dir, OffsetNumber offnum, maxoff = PageGetMaxOffsetNumber(page); /* initialize page-level state that we'll pass to _bt_checkkeys */ - pstate.dir = dir; pstate.minoff = minoff; pstate.maxoff = maxoff; pstate.finaltup = NULL; @@ -2088,7 +2088,7 @@ _bt_steppage(IndexScanDesc scan, ScanDirection dir) */ if (so->needPrimScan) { - if (ScanDirectionIsForward(dir)) + if (ScanDirectionIsForward(so->currPos.dir)) so->markPos.moreRight = true; else so->markPos.moreLeft = true; @@ -2109,6 +2109,15 @@ _bt_steppage(IndexScanDesc scan, ScanDirection dir) else blkno = so->currPos.prevPage; lastcurrblkno = so->currPos.currPage; + + /* + * 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; } else { @@ -2118,6 +2127,8 @@ _bt_steppage(IndexScanDesc scan, ScanDirection dir) */ if (!_bt_parallel_seize(scan, &blkno, &lastcurrblkno, false)) return false; + + Assert(!so->needPrimScan); } return _bt_readnextpage(scan, blkno, lastcurrblkno, dir); diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c index 76be65123c8..20227989c6d 100644 --- a/src/backend/access/nbtree/nbtutils.c +++ b/src/backend/access/nbtree/nbtutils.c @@ -1800,7 +1800,7 @@ _bt_advance_array_keys(IndexScanDesc scan, BTReadPageState *pstate, { BTScanOpaque so = (BTScanOpaque) scan->opaque; Relation rel = scan->indexRelation; - ScanDirection dir = pstate ? pstate->dir : ForwardScanDirection; + ScanDirection dir = so->currPos.dir; int arrayidx = 0; bool beyond_end_advance = false, has_required_opposite_direction_only = false, @@ -2400,8 +2400,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 */ @@ -3458,7 +3460,7 @@ _bt_checkkeys(IndexScanDesc scan, BTReadPageState *pstate, bool arrayKeys, { TupleDesc tupdesc = RelationGetDescr(scan->indexRelation); BTScanOpaque so = (BTScanOpaque) scan->opaque; - ScanDirection dir = pstate->dir; + ScanDirection dir = so->currPos.dir; int ikey = 0; bool res; @@ -4062,7 +4064,8 @@ static void _bt_checkkeys_look_ahead(IndexScanDesc scan, BTReadPageState *pstate, int tupnatts, TupleDesc tupdesc) { - ScanDirection dir = pstate->dir; + BTScanOpaque so = (BTScanOpaque) scan->opaque; + ScanDirection dir = so->currPos.dir; OffsetNumber aheadoffnum; IndexTuple ahead; diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h index 5fb523ecec3..123fba624db 100644 --- a/src/include/access/nbtree.h +++ b/src/include/access/nbtree.h @@ -1078,7 +1078,6 @@ typedef BTScanOpaqueData *BTScanOpaque; typedef struct BTReadPageState { /* Input parameters, set by _bt_readpage for _bt_checkkeys */ - ScanDirection dir; /* current scan direction */ OffsetNumber minoff; /* Lowest non-pivot tuple's offset */ OffsetNumber maxoff; /* Highest non-pivot tuple's offset */ IndexTuple finaltup; /* Needed by scans with array keys */