postgres.git / summary / log / commit / refs

commit    b36d72cbc6b008da062ac84850254a9de0da93d4
Author:   Peter Geoghegan <pg@bowt.ie>
Date:     Thu Sep 28 23:29:24 2023 +0000
First released in: 17.0, 11.22, 12.17, 13.13, 14.10, 15.5, 16.1

    Fix btmarkpos/btrestrpos array key wraparound bug.
    
    nbtree's mark/restore processing failed to correctly handle an edge case
    involving array key advancement and related search-type scan key state.
    Scans with ScalarArrayScalarArrayOpExpr quals requiring mark/restore
    processing (for a merge join) could incorrectly conclude that an
    affected array/scan key must not have advanced during the time between
    marking and restoring the scan's position.
    
    As a result of all this, array key handling within btrestrpos could skip
    a required call to _bt_preprocess_keys().  This confusion allowed later
    primitive index scans to overlook tuples matching the true current array
    keys.  The scan's search-type scan keys would still have spurious values
    corresponding to the final array element(s) -- not values matching the
    first/now-current array element(s).
    
    To fix, remember that "array key wraparound" has taken place during the
    ongoing btrescan in a flag variable stored in the scan's state, and use
    that information at the point where btrestrpos decides if another call
    to _bt_preprocess_keys is required.
    
    Oversight in commit 70bc5833, which taught nbtree to handle array keys
    during mark/restore processing, but missed this subtlety.  That commit
    was itself a bug fix for an issue in commit 9e8da0f7, which taught
    nbtree to handle ScalarArrayOpExpr quals natively.
    
    Author: Peter Geoghegan <pg@bowt.ie>
    Discussion: https://postgr.es/m/CAH2-WzkgP3DDRJxw6DgjCxo-cu-DKrvjEv_ArkP2ctBJatDCYg@mail.gmail.com
    Backpatch: 11- (all supported branches).


src/backend/access/nbtree/nbtree.c | 1 + src/backend/access/nbtree/nbtutils.c | 17 ++++++++++++++++- src/include/access/nbtree.h | 4 +++- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c index c2e83d3ee5e..cfc0ad48fcd 100644 --- a/src/backend/access/nbtree/nbtree.c +++ b/src/backend/access/nbtree/nbtree.c @@ -366,6 +366,7 @@ btbeginscan(Relation rel, int nkeys, int norderbys) so->keyData = NULL; so->arrayKeyData = NULL; /* assume no array keys for now */ + so->arraysStarted = false; so->numArrayKeys = 0; so->arrayKeys = NULL; so->arrayContext = NULL; diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c index ff6d3330fa2..0e9cc574df4 100644 --- a/src/backend/access/nbtree/nbtutils.c +++ b/src/backend/access/nbtree/nbtutils.c @@ -534,6 +534,8 @@ _bt_start_array_keys(IndexScanDesc scan, ScanDirection dir) curArrayKey->cur_elem = 0; skey->sk_argument = curArrayKey->elem_values[curArrayKey->cur_elem]; } + + so->arraysStarted = true; } /* @@ -593,6 +595,14 @@ _bt_advance_array_keys(IndexScanDesc scan, ScanDirection dir) if (scan->parallel_scan != NULL) _bt_parallel_advance_array_keys(scan); + /* + * When no new array keys were found, the scan is "past the end" of the + * array keys. _bt_start_array_keys can still "restart" the array keys if + * a rescan is required. + */ + if (!found) + so->arraysStarted = false; + return found; } @@ -646,8 +656,13 @@ _bt_restore_array_keys(IndexScanDesc scan) * If we changed any keys, we must redo _bt_preprocess_keys. That might * sound like overkill, but in cases with multiple keys per index column * it seems necessary to do the full set of pushups. + * + * Also do this whenever the scan's set of array keys "wrapped around" at + * the end of the last primitive index scan. There won't have been a call + * to _bt_preprocess_keys from some other place following wrap around, so + * we do it for ourselves. */ - if (changed) + if (changed || !so->arraysStarted) { _bt_preprocess_keys(scan); /* The mark should have been set on a consistent set of keys... */ diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h index 8f81663e5c0..883c7dc3cfc 100644 --- a/src/include/access/nbtree.h +++ b/src/include/access/nbtree.h @@ -628,8 +628,10 @@ typedef struct BTArrayKeyInfo typedef struct BTScanOpaqueData { - /* these fields are set by _bt_preprocess_keys(): */ + /* all fields (except arraysStarted) are set by _bt_preprocess_keys(): */ bool qual_ok; /* false if qual can never be satisfied */ + bool arraysStarted; /* Started array keys, but have yet to "reach + * past the end" of all arrays? */ int numberOfKeys; /* number of preprocessed scan keys */ ScanKey keyData; /* array of preprocessed scan keys */ [parent: d6425987ba76]