postgres.git / summary / log / commit / refs

commit    712ce074a841bf4a0cf0eb372ece19726e3726dd
Author:   David Rowley <drowley@postgresql.org>
Date:     Mon Jan 25 07:00:16 2021 +0000
First released in: 14.0, 9.5.25, 9.6.21, 10.16, 11.11, 12.6, 13.2

    Fix hypothetical bug in heap backward scans
    
    Both heapgettup() and heapgettup_pagemode() incorrectly set the first page
    to scan in a backward scan in which the number of pages to scan was
    specified by heap_setscanlimits().  The code incorrectly started the scan
    at the end of the relation when startBlk was 0, or otherwise at
    startBlk - 1, neither of which is correct when only scanning a subset of
    pages.
    
    The fix here checks if heap_setscanlimits() has changed the number of
    pages to scan and if so we set the first page to scan as the final page in
    the specified range during backward scans.
    
    Proper adjustment of this code was forgotten when heap_setscanlimits() was
    added in 7516f5259 back in 9.5.  However, practice, nowhere in core code
    performs backward scans after having used heap_setscanlimits(), yet, it is
    possible an extension uses the heap functions in this way, hence
    backpatch.
    
    An upcoming patch does use heap_setscanlimits() with backward scans, so
    this must be fixed before that can go in.
    
    Author: David Rowley
    Discussion: https://postgr.es/m/CAApHDvpGc9h0_oVD2CtgBcxCS1N-qDYZSeBRnUh+0CWJA9cMaA@mail.gmail.com
    Backpatch-through: 9.5, all supported versions


src/backend/access/heap/heapam.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index 3a7095e85b8..0c59ff11e54 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -567,8 +567,14 @@ heapgettup(HeapScanDesc scan, * forward scanners. */ scan->rs_syncscan = false; - /* start from last page of the scan */ - if (scan->rs_startblock > 0) + + /* + * Start from last page of the scan. Ensure we take into account + * rs_numblocks if it's been adjusted by heap_setscanlimits(). + */ + if (scan->rs_numblocks != InvalidBlockNumber) + page = (scan->rs_startblock + scan->rs_numblocks - 1) % scan->rs_nblocks; + else if (scan->rs_startblock > 0) page = scan->rs_startblock - 1; else page = scan->rs_nblocks - 1; @@ -866,8 +872,14 @@ heapgettup_pagemode(HeapScanDesc scan, * forward scanners. */ scan->rs_syncscan = false; - /* start from last page of the scan */ - if (scan->rs_startblock > 0) + + /* + * Start from last page of the scan. Ensure we take into account + * rs_numblocks if it's been adjusted by heap_setscanlimits(). + */ + if (scan->rs_numblocks != InvalidBlockNumber) + page = (scan->rs_startblock + scan->rs_numblocks - 1) % scan->rs_nblocks; + else if (scan->rs_startblock > 0) page = scan->rs_startblock - 1; else page = scan->rs_nblocks - 1; [parent: 728971d5f10e]