Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 714780d

Browse files
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 70bc583, 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 9e8da0f, 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).
1 parent 9f71e10 commit 714780d

File tree

3 files changed

+19
-1
lines changed

3 files changed

+19
-1
lines changed

src/backend/access/nbtree/nbtree.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,7 @@ btbeginscan(Relation rel, int nkeys, int norderbys)
364364
so->keyData = NULL;
365365

366366
so->arrayKeyData = NULL; /* assume no array keys for now */
367+
so->arraysStarted = false;
367368
so->numArrayKeys = 0;
368369
so->arrayKeys = NULL;
369370
so->arrayContext = NULL;

src/backend/access/nbtree/nbtutils.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,8 @@ _bt_start_array_keys(IndexScanDesc scan, ScanDirection dir)
539539
curArrayKey->cur_elem = 0;
540540
skey->sk_argument = curArrayKey->elem_values[curArrayKey->cur_elem];
541541
}
542+
543+
so->arraysStarted = true;
542544
}
543545

544546
/*
@@ -598,6 +600,14 @@ _bt_advance_array_keys(IndexScanDesc scan, ScanDirection dir)
598600
if (scan->parallel_scan != NULL)
599601
_bt_parallel_advance_array_keys(scan);
600602

603+
/*
604+
* When no new array keys were found, the scan is "past the end" of the
605+
* array keys. _bt_start_array_keys can still "restart" the array keys if
606+
* a rescan is required.
607+
*/
608+
if (!found)
609+
so->arraysStarted = false;
610+
601611
return found;
602612
}
603613

@@ -651,8 +661,13 @@ _bt_restore_array_keys(IndexScanDesc scan)
651661
* If we changed any keys, we must redo _bt_preprocess_keys. That might
652662
* sound like overkill, but in cases with multiple keys per index column
653663
* it seems necessary to do the full set of pushups.
664+
*
665+
* Also do this whenever the scan's set of array keys "wrapped around" at
666+
* the end of the last primitive index scan. There won't have been a call
667+
* to _bt_preprocess_keys from some other place following wrap around, so
668+
* we do it for ourselves.
654669
*/
655-
if (changed)
670+
if (changed || !so->arraysStarted)
656671
{
657672
_bt_preprocess_keys(scan);
658673
/* The mark should have been set on a consistent set of keys... */

src/include/access/nbtree.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1043,6 +1043,8 @@ typedef struct BTScanOpaqueData
10431043

10441044
/* workspace for SK_SEARCHARRAY support */
10451045
ScanKey arrayKeyData; /* modified copy of scan->keyData */
1046+
bool arraysStarted; /* Started array keys, but have yet to "reach
1047+
* past the end" of all arrays? */
10461048
int numArrayKeys; /* number of equality-type array keys (-1 if
10471049
* there are any unsatisfiable array keys) */
10481050
int arrayKeyCount; /* count indicating number of array scan keys

0 commit comments

Comments
 (0)