summaryrefslogtreecommitdiff
path: root/src/backend/access/nbtree
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/access/nbtree')
-rw-r--r--src/backend/access/nbtree/nbtdedup.c2
-rw-r--r--src/backend/access/nbtree/nbtpreprocesskeys.c4
-rw-r--r--src/backend/access/nbtree/nbtsearch.c21
-rw-r--r--src/backend/access/nbtree/nbtsort.c6
-rw-r--r--src/backend/access/nbtree/nbtsplitloc.c4
-rw-r--r--src/backend/access/nbtree/nbtutils.c68
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) &&