diff options
Diffstat (limited to 'src/backend/access/nbtree')
| -rw-r--r-- | src/backend/access/nbtree/nbtdedup.c | 2 | ||||
| -rw-r--r-- | src/backend/access/nbtree/nbtpreprocesskeys.c | 4 | ||||
| -rw-r--r-- | src/backend/access/nbtree/nbtsearch.c | 21 | ||||
| -rw-r--r-- | src/backend/access/nbtree/nbtsort.c | 6 | ||||
| -rw-r--r-- | src/backend/access/nbtree/nbtsplitloc.c | 4 | ||||
| -rw-r--r-- | src/backend/access/nbtree/nbtutils.c | 68 |
6 files changed, 73 insertions, 32 deletions
diff --git a/src/backend/access/nbtree/nbtdedup.c b/src/backend/access/nbtree/nbtdedup.c index 07e63962f81..a746de45dd3 100644 --- a/src/backend/access/nbtree/nbtdedup.c +++ b/src/backend/access/nbtree/nbtdedup.c @@ -859,7 +859,7 @@ _bt_singleval_fillfactor(Page page, BTDedupState state, Size newitemsz) * returned posting list tuple (they must be included in htids array.) */ IndexTuple -_bt_form_posting(IndexTuple base, ItemPointer htids, int nhtids) +_bt_form_posting(IndexTuple base, const ItemPointerData *htids, int nhtids) { uint32 keysize, newsize; diff --git a/src/backend/access/nbtree/nbtpreprocesskeys.c b/src/backend/access/nbtree/nbtpreprocesskeys.c index 7b7d7860d8f..a871bf62cab 100644 --- a/src/backend/access/nbtree/nbtpreprocesskeys.c +++ b/src/backend/access/nbtree/nbtpreprocesskeys.c @@ -67,7 +67,7 @@ static int _bt_num_array_keys(IndexScanDesc scan, Oid *skip_eq_ops_out, int *numSkipArrayKeys_out); static Datum _bt_find_extreme_element(IndexScanDesc scan, ScanKey skey, Oid elemtype, StrategyNumber strat, - Datum *elems, int nelems); + const Datum *elems, int nelems); static void _bt_setup_array_cmp(IndexScanDesc scan, ScanKey skey, Oid elemtype, FmgrInfo *orderproc, FmgrInfo **sortprocp); static int _bt_sort_array_elements(ScanKey skey, FmgrInfo *sortproc, @@ -2569,7 +2569,7 @@ _bt_num_array_keys(IndexScanDesc scan, Oid *skip_eq_ops_out, static Datum _bt_find_extreme_element(IndexScanDesc scan, ScanKey skey, Oid elemtype, StrategyNumber strat, - Datum *elems, int nelems) + const Datum *elems, int nelems) { Relation rel = scan->indexRelation; Oid cmp_op; diff --git a/src/backend/access/nbtree/nbtsearch.c b/src/backend/access/nbtree/nbtsearch.c index d69798795b4..0605356ec9f 100644 --- a/src/backend/access/nbtree/nbtsearch.c +++ b/src/backend/access/nbtree/nbtsearch.c @@ -37,7 +37,7 @@ static bool _bt_readpage(IndexScanDesc scan, ScanDirection dir, static void _bt_saveitem(BTScanOpaque so, int itemIndex, OffsetNumber offnum, IndexTuple itup); static int _bt_setuppostingitems(BTScanOpaque so, int itemIndex, - OffsetNumber offnum, ItemPointer heapTid, + OffsetNumber offnum, const ItemPointerData *heapTid, IndexTuple itup); static inline void _bt_savepostingitem(BTScanOpaque so, int itemIndex, OffsetNumber offnum, @@ -1288,6 +1288,8 @@ _bt_first(IndexScanDesc scan, ScanDirection dir) * our row compare header key must be the final startKeys[] entry. */ Assert(subkey->sk_flags & (SK_BT_REQFWD | SK_BT_REQBKWD)); + Assert(subkey->sk_strategy == bkey->sk_strategy); + Assert(subkey->sk_strategy == strat_total); Assert(i == keysz - 1); /* @@ -1344,9 +1346,9 @@ _bt_first(IndexScanDesc scan, ScanDirection dir) Assert(subkey->sk_strategy == bkey->sk_strategy); Assert(keysz < INDEX_MAX_KEYS); - memcpy(inskey.scankeys + keysz, subkey, - sizeof(ScanKeyData)); + memcpy(inskey.scankeys + keysz, subkey, sizeof(ScanKeyData)); keysz++; + if (subkey->sk_flags & SK_ROW_END) break; } @@ -1378,7 +1380,7 @@ _bt_first(IndexScanDesc scan, ScanDirection dir) } } - /* done adding to inskey (row comparison keys always come last) */ + /* Done (row compare header key is always last startKeys[] key) */ break; } @@ -2079,7 +2081,7 @@ _bt_saveitem(BTScanOpaque so, int itemIndex, */ static int _bt_setuppostingitems(BTScanOpaque so, int itemIndex, OffsetNumber offnum, - ItemPointer heapTid, IndexTuple itup) + const ItemPointerData *heapTid, IndexTuple itup) { BTScanPosItem *currItem = &so->currPos.items[itemIndex]; @@ -2246,12 +2248,9 @@ _bt_steppage(IndexScanDesc scan, ScanDirection dir) * * _bt_first caller passes us an offnum returned by _bt_binsrch, which might * be an out of bounds offnum such as "maxoff + 1" in certain corner cases. - * _bt_checkkeys will stop the scan as soon as an equality qual fails (when - * its scan key was marked required), so _bt_first _must_ pass us an offnum - * exactly at the beginning of where equal tuples are to be found. When we're - * passed an offnum past the end of the page, we might still manage to stop - * the scan on this page by calling _bt_checkkeys against the high key. See - * _bt_readpage for full details. + * When we're passed an offnum past the end of the page, we might still manage + * to stop the scan on this page by calling _bt_checkkeys against the high + * key. See _bt_readpage for full details. * * On entry, so->currPos must be pinned and locked (so offnum stays valid). * Parallel scan callers must have seized the scan before calling here. diff --git a/src/backend/access/nbtree/nbtsort.c b/src/backend/access/nbtree/nbtsort.c index 313fe66bc96..454adaee7dc 100644 --- a/src/backend/access/nbtree/nbtsort.c +++ b/src/backend/access/nbtree/nbtsort.c @@ -257,8 +257,8 @@ typedef struct BTWriteState static double _bt_spools_heapscan(Relation heap, Relation index, BTBuildState *buildstate, IndexInfo *indexInfo); static void _bt_spooldestroy(BTSpool *btspool); -static void _bt_spool(BTSpool *btspool, ItemPointer self, - Datum *values, bool *isnull); +static void _bt_spool(BTSpool *btspool, const ItemPointerData *self, + const Datum *values, const bool *isnull); static void _bt_leafbuild(BTSpool *btspool, BTSpool *btspool2); static void _bt_build_callback(Relation index, ItemPointer tid, Datum *values, bool *isnull, bool tupleIsAlive, void *state); @@ -525,7 +525,7 @@ _bt_spooldestroy(BTSpool *btspool) * spool an index entry into the sort file. */ static void -_bt_spool(BTSpool *btspool, ItemPointer self, Datum *values, bool *isnull) +_bt_spool(BTSpool *btspool, const ItemPointerData *self, const Datum *values, const bool *isnull) { tuplesort_putindextuplevalues(btspool->sortstate, btspool->index, self, values, isnull); diff --git a/src/backend/access/nbtree/nbtsplitloc.c b/src/backend/access/nbtree/nbtsplitloc.c index b88c396195a..f0082f88c76 100644 --- a/src/backend/access/nbtree/nbtsplitloc.c +++ b/src/backend/access/nbtree/nbtsplitloc.c @@ -69,7 +69,7 @@ static void _bt_deltasortsplits(FindSplitData *state, double fillfactormult, static int _bt_splitcmp(const void *arg1, const void *arg2); static bool _bt_afternewitemoff(FindSplitData *state, OffsetNumber maxoff, int leaffillfactor, bool *usemult); -static bool _bt_adjacenthtid(ItemPointer lowhtid, ItemPointer highhtid); +static bool _bt_adjacenthtid(const ItemPointerData *lowhtid, const ItemPointerData *highhtid); static OffsetNumber _bt_bestsplitloc(FindSplitData *state, int perfectpenalty, bool *newitemonleft, FindSplitStrat strategy); static int _bt_defaultinterval(FindSplitData *state); @@ -747,7 +747,7 @@ _bt_afternewitemoff(FindSplitData *state, OffsetNumber maxoff, * transaction. */ static bool -_bt_adjacenthtid(ItemPointer lowhtid, ItemPointer highhtid) +_bt_adjacenthtid(const ItemPointerData *lowhtid, const ItemPointerData *highhtid) { BlockNumber lowblk, highblk; diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c index 288da8b68ab..ab0f98b0287 100644 --- a/src/backend/access/nbtree/nbtutils.c +++ b/src/backend/access/nbtree/nbtutils.c @@ -63,7 +63,7 @@ static bool _bt_check_compare(IndexScanDesc scan, ScanDirection dir, bool advancenonrequired, bool forcenonrequired, bool *continuescan, int *ikey); static bool _bt_rowcompare_cmpresult(ScanKey subkey, int cmpresult); -static bool _bt_check_rowcompare(ScanKey skey, +static bool _bt_check_rowcompare(ScanKey header, IndexTuple tuple, int tupnatts, TupleDesc tupdesc, ScanDirection dir, bool forcenonrequired, bool *continuescan); static void _bt_checkkeys_look_ahead(IndexScanDesc scan, BTReadPageState *pstate, @@ -2969,11 +2969,6 @@ _bt_check_compare(IndexScanDesc scan, ScanDirection dir, * Tuple fails this qual. If it's a required qual for the current * scan direction, then we can conclude no further tuples will * pass, either. - * - * Note: because we stop the scan as soon as any required equality - * qual fails, it is critical that equality quals be used for the - * initial positioning in _bt_first() when they are available. See - * comments in _bt_first(). */ if (requiredSameDir) *continuescan = false; @@ -3013,6 +3008,8 @@ _bt_rowcompare_cmpresult(ScanKey subkey, int cmpresult) { bool satisfied; + Assert(subkey->sk_flags & SK_ROW_MEMBER); + switch (subkey->sk_strategy) { case BTLessStrategyNumber: @@ -3044,19 +3041,64 @@ _bt_rowcompare_cmpresult(ScanKey subkey, int cmpresult) * it's not possible for any future tuples in the current scan direction * to pass the qual. * - * This is a subroutine for _bt_checkkeys/_bt_check_compare. + * This is a subroutine for _bt_checkkeys/_bt_check_compare. Caller passes us + * a row compare header key taken from so->keyData[]. + * + * Row value comparisons can be described in terms of logical expansions that + * use only scalar operators. Consider the following example row comparison: + * + * "(a, b, c) > (7, 'bar', 62)" + * + * This can be evaluated as: + * + * "(a = 7 AND b = 'bar' AND c > 62) OR (a = 7 AND b > 'bar') OR (a > 7)". + * + * Notice that this condition is satisfied by _all_ rows that satisfy "a > 7", + * and by a subset of all rows that satisfy "a >= 7" (possibly all such rows). + * It _can't_ be satisfied by other rows (where "a < 7" or where "a IS NULL"). + * A row comparison header key can therefore often be treated as if it was a + * simple scalar inequality on the row compare's most significant column. + * (For example, _bt_advance_array_keys and most preprocessing routines treat + * row compares like any other same-strategy inequality on the same column.) + * + * Things get more complicated for our row compare given a row where "a = 7". + * Note that a row compare isn't necessarily satisfied by _every_ tuple that + * appears between the first and last satisfied tuple returned by the scan, + * due to the way that its lower-order subkeys are only conditionally applied. + * A forwards scan that uses our example qual might initially return a tuple + * "(a, b, c) = (7, 'zebra', 54)". But it won't subsequently return a tuple + * "(a, b, c) = (7, NULL, 1)" located to the right of the first matching tuple + * (assume that "b" was declared NULLS LAST here). The scan will only return + * additional matches upon reaching tuples where "a > 7". If you rereview our + * example row comparison's logical expansion, you'll understand why this is. + * (Here we assume that all subkeys could be marked required, guaranteeing + * that row comparison order matches index order. This is the common case.) + * + * Note that a row comparison header key behaves _exactly_ the same as a + * similar scalar inequality key on the row's most significant column once the + * scan reaches the point where it no longer needs to evaluate lower-order + * subkeys (or before the point where it starts needing to evaluate them). + * For example, once a forwards scan that uses our example qual reaches the + * first tuple "a > 7", we'll behave in just the same way as our caller would + * behave with a similar scalar inequality "a > 7" for the remainder of the + * scan (assuming that the scan never changes direction/never goes backwards). + * We'll even set continuescan=false according to exactly the same rules as + * the ones our caller applies with simple scalar inequalities, including the + * rules it applies when NULL tuple values don't satisfy an inequality qual. */ static bool -_bt_check_rowcompare(ScanKey skey, IndexTuple tuple, int tupnatts, +_bt_check_rowcompare(ScanKey header, IndexTuple tuple, int tupnatts, TupleDesc tupdesc, ScanDirection dir, bool forcenonrequired, bool *continuescan) { - ScanKey subkey = (ScanKey) DatumGetPointer(skey->sk_argument); + ScanKey subkey = (ScanKey) DatumGetPointer(header->sk_argument); int32 cmpresult = 0; bool result; /* First subkey should be same as the header says */ - Assert(subkey->sk_attno == skey->sk_attno); + Assert(header->sk_flags & SK_ROW_HEADER); + Assert(subkey->sk_attno == header->sk_attno); + Assert(subkey->sk_strategy == header->sk_strategy); /* Loop over columns of the row condition */ for (;;) @@ -3076,7 +3118,7 @@ _bt_check_rowcompare(ScanKey skey, IndexTuple tuple, int tupnatts, * columns are required for the scan direction, we can stop the * scan, because there can't be another tuple that will succeed. */ - Assert(subkey != (ScanKey) DatumGetPointer(skey->sk_argument)); + Assert(subkey != (ScanKey) DatumGetPointer(header->sk_argument)); subkey--; if (forcenonrequired) { @@ -3147,7 +3189,7 @@ _bt_check_rowcompare(ScanKey skey, IndexTuple tuple, int tupnatts, * can only happen with an "a" NULL some time after the scan * completely stops needing to use its "b" and "c" members.) */ - if (subkey == (ScanKey) DatumGetPointer(skey->sk_argument)) + if (subkey == (ScanKey) DatumGetPointer(header->sk_argument)) reqflags |= SK_BT_REQFWD; /* safe, first row member */ if ((subkey->sk_flags & reqflags) && @@ -3185,7 +3227,7 @@ _bt_check_rowcompare(ScanKey skey, IndexTuple tuple, int tupnatts, * happen with an "a" NULL some time after the scan completely * stops needing to use its "b" and "c" members.) */ - if (subkey == (ScanKey) DatumGetPointer(skey->sk_argument)) + if (subkey == (ScanKey) DatumGetPointer(header->sk_argument)) reqflags |= SK_BT_REQBKWD; /* safe, first row member */ if ((subkey->sk_flags & reqflags) && |
