diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index ec6b7962c5..57ff13ee8d 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -544,6 +544,82 @@ heapgettup_initial_block(HeapScanDesc scan, ScanDirection dir) } } + +/* + * heapgettup_start_page - helper function for heapgettup() + * + * Return the next page to scan based on the scan->rs_cbuf and set *linesleft + * to the number of tuples on this page. Also set *lineoff to the first + * offset to scan with forward scans getting the first offset and backward + * getting the final offset on the page. + */ +static Page +heapgettup_start_page(HeapScanDesc scan, ScanDirection dir, int *linesleft, + OffsetNumber *lineoff) +{ + Page page; + + Assert(scan->rs_inited); + Assert(BufferIsValid(scan->rs_cbuf)); + + /* Caller is responsible for ensuring buffer is locked if needed */ + page = BufferGetPage(scan->rs_cbuf); + + TestForOldSnapshot(scan->rs_base.rs_snapshot, scan->rs_base.rs_rd, page); + + *linesleft = PageGetMaxOffsetNumber((Page) page) - FirstOffsetNumber + 1; + + if (ScanDirectionIsForward(dir)) + *lineoff = FirstOffsetNumber; + else + *lineoff = (OffsetNumber) (*linesleft); + + /* lineoff now references the physically previous or next tid */ + return page; +} + + +/* + * heapgettup_continue_page - helper function for heapgettup() + * + * Return the next page to scan based on the scan->rs_cbuf and set *linesleft + * to the number of tuples left to scan on this page. Also set *lineoff to + * the next offset to scan according to the ScanDirection in 'dir'. + */ +static inline Page +heapgettup_continue_page(HeapScanDesc scan, ScanDirection dir, int *linesleft, + OffsetNumber *lineoff) +{ + Page page; + + Assert(scan->rs_inited); + Assert(BufferIsValid(scan->rs_cbuf)); + + /* Caller is responsible for ensuring buffer is locked if needed */ + page = BufferGetPage(scan->rs_cbuf); + + TestForOldSnapshot(scan->rs_base.rs_snapshot, scan->rs_base.rs_rd, page); + + if (ScanDirectionIsForward(dir)) + { + *lineoff = OffsetNumberNext(scan->rs_coffset); + *linesleft = PageGetMaxOffsetNumber(page) - (*lineoff) + 1; + } + else + { + /* + * The previous returned tuple may have been vacuumed since the + * previous scan when we use a non-MVCC snapshot, so we must + * re-establish the lineoff <= PageGetMaxOffsetNumber(page) invariant + */ + *lineoff = Min(PageGetMaxOffsetNumber(page), OffsetNumberPrev(scan->rs_coffset)); + *linesleft = *lineoff; + } + + /* lineoff now references the physically previous or next tid */ + return page; +} + /* ---------------- * heapgettup - fetch next heap tuple * @@ -571,7 +647,6 @@ heapgettup(HeapScanDesc scan, ScanKey key) { HeapTuple tuple = &(scan->rs_ctup); - Snapshot snapshot = scan->rs_base.rs_snapshot; bool backward = ScanDirectionIsBackward(dir); BlockNumber block; bool finished; @@ -595,21 +670,12 @@ heapgettup(HeapScanDesc scan, tuple->t_data = NULL; return; } + scan->rs_inited = true; heapgetpage((TableScanDesc) scan, block); LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE); - page = BufferGetPage(scan->rs_cbuf); - TestForOldSnapshot(snapshot, scan->rs_base.rs_rd, page); - - linesleft = PageGetMaxOffsetNumber(page) - FirstOffsetNumber + 1; - - if (ScanDirectionIsForward(dir)) - lineoff = FirstOffsetNumber; /* first offnum */ - else - lineoff = (OffsetNumber) linesleft; - - scan->rs_inited = true; + page = heapgettup_start_page(scan, dir, &linesleft, &lineoff); } else { @@ -617,26 +683,7 @@ heapgettup(HeapScanDesc scan, block = scan->rs_cblock; LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE); - page = BufferGetPage(scan->rs_cbuf); - TestForOldSnapshot(snapshot, scan->rs_base.rs_rd, page); - - if (ScanDirectionIsForward(dir)) - { - lineoff = OffsetNumberNext(scan->rs_coffset); - linesleft = PageGetMaxOffsetNumber(page) - lineoff + 1; - } - else - { - /* - * The previous returned tuple may have been vacuumed since the - * previous scan when we use a non-MVCC snapshot, so we must - * re-establish the lineoff <= PageGetMaxOffsetNumber(page) - * invariant - */ - lineoff = Min(PageGetMaxOffsetNumber(page), - OffsetNumberPrev(scan->rs_coffset)); - linesleft = lineoff; - } + page = heapgettup_continue_page(scan, dir, &linesleft, &lineoff); } /* @@ -667,12 +714,12 @@ heapgettup(HeapScanDesc scan, * if current tuple qualifies, return it. */ valid = HeapTupleSatisfiesVisibility(tuple, - snapshot, + scan->rs_base.rs_snapshot, scan->rs_cbuf); HeapCheckForSerializableConflictOut(valid, scan->rs_base.rs_rd, tuple, scan->rs_cbuf, - snapshot); + scan->rs_base.rs_snapshot); if (valid && key != NULL) valid = HeapKeyTest(tuple, RelationGetDescr(scan->rs_base.rs_rd), @@ -773,7 +820,8 @@ heapgettup(HeapScanDesc scan, LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE); page = BufferGetPage(scan->rs_cbuf); - TestForOldSnapshot(snapshot, scan->rs_base.rs_rd, page); + TestForOldSnapshot(scan->rs_base.rs_snapshot, scan->rs_base.rs_rd, + page); linesleft = PageGetMaxOffsetNumber(page); if (backward) {