Coverage Report

Created: 2026-10-16 06:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/postgres/src/backend/access/nbtree/nbtreadpage.c
Line
Count
Source
1
/*-------------------------------------------------------------------------
2
 *
3
 * nbtreadpage.c
4
 *    Leaf page reading for btree index scans.
5
 *
6
 * NOTES
7
 *    This file contains code to return items that satisfy the scan's
8
 *    search-type scan keys within caller-supplied btree leaf page.
9
 *
10
 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
11
 * Portions Copyright (c) 1994, Regents of the University of California
12
 *
13
 * IDENTIFICATION
14
 *    src/backend/access/nbtree/nbtreadpage.c
15
 *
16
 *-------------------------------------------------------------------------
17
 */
18
19
#include "postgres.h"
20
21
#include "access/nbtree.h"
22
#include "access/relscan.h"
23
#include "storage/predicate.h"
24
#include "utils/datum.h"
25
#include "utils/rel.h"
26
27
28
/*
29
 * _bt_readpage state used across _bt_checkkeys calls for a page
30
 */
31
typedef struct BTReadPageState
32
{
33
  /* Input parameters, set by _bt_readpage for _bt_checkkeys */
34
  ScanDirection dir;      /* current scan direction */
35
  OffsetNumber minoff;    /* Lowest non-pivot tuple's offset */
36
  OffsetNumber maxoff;    /* Highest non-pivot tuple's offset */
37
  IndexTuple  finaltup;   /* Needed by scans with array keys */
38
  Page    page;     /* Page being read */
39
  bool    firstpage;    /* page is first for primitive scan? */
40
  bool    forcenonrequired; /* treat all keys as nonrequired? */
41
  int     startikey;    /* start comparisons from this scan key */
42
43
  /* Per-tuple input parameters, set by _bt_readpage for _bt_checkkeys */
44
  OffsetNumber offnum;    /* current tuple's page offset number */
45
46
  /* Output parameters, set by _bt_checkkeys for _bt_readpage */
47
  OffsetNumber skip;      /* Array keys "look ahead" skip offnum */
48
  bool    continuescan; /* Terminate ongoing (primitive) index scan? */
49
50
  /*
51
   * Private _bt_checkkeys state used to manage "look ahead" optimization
52
   * and primscan scheduling (only used during scans with array keys)
53
   */
54
  int16   rechecks;
55
  int16   targetdistance;
56
  int16   nskipadvances;
57
58
} BTReadPageState;
59
60
61
static void _bt_set_startikey(IndexScanDesc scan, BTReadPageState *pstate);
62
static bool _bt_scanbehind_checkkeys(IndexScanDesc scan, ScanDirection dir,
63
                   IndexTuple finaltup);
64
static bool _bt_oppodir_checkkeys(IndexScanDesc scan, ScanDirection dir,
65
                  IndexTuple finaltup);
66
static void _bt_saveitem(BTScanOpaque so, int itemIndex,
67
             OffsetNumber offnum, IndexTuple itup);
68
static int  _bt_setuppostingitems(BTScanOpaque so, int itemIndex,
69
                  OffsetNumber offnum, const ItemPointerData *heapTid,
70
                  IndexTuple itup);
71
static inline void _bt_savepostingitem(BTScanOpaque so, int itemIndex,
72
                     OffsetNumber offnum,
73
                     ItemPointer heapTid, int tupleOffset);
74
static bool _bt_checkkeys(IndexScanDesc scan, BTReadPageState *pstate, bool arrayKeys,
75
              IndexTuple tuple, int tupnatts);
76
static bool _bt_check_compare(IndexScanDesc scan, ScanDirection dir,
77
                IndexTuple tuple, int tupnatts, TupleDesc tupdesc,
78
                bool advancenonrequired, bool forcenonrequired,
79
                bool *continuescan, int *ikey);
80
static bool _bt_check_rowcompare(ScanKey header,
81
                 IndexTuple tuple, int tupnatts, TupleDesc tupdesc,
82
                 ScanDirection dir, bool forcenonrequired, bool *continuescan);
83
static bool _bt_rowcompare_cmpresult(ScanKey subkey, int cmpresult);
84
static bool _bt_tuple_before_array_skeys(IndexScanDesc scan, ScanDirection dir,
85
                     IndexTuple tuple, TupleDesc tupdesc, int tupnatts,
86
                     bool readpagetup, int sktrig, bool *scanBehind);
87
static void _bt_checkkeys_look_ahead(IndexScanDesc scan, BTReadPageState *pstate,
88
                   int tupnatts, TupleDesc tupdesc);
89
static bool _bt_advance_array_keys(IndexScanDesc scan, BTReadPageState *pstate,
90
                   IndexTuple tuple, int tupnatts, TupleDesc tupdesc,
91
                   int sktrig, bool sktrig_required);
92
static bool _bt_advance_array_keys_increment(IndexScanDesc scan, ScanDirection dir,
93
                       bool *skip_array_set);
94
static bool _bt_array_increment(Relation rel, ScanKey skey, BTArrayKeyInfo *array);
95
static bool _bt_array_decrement(Relation rel, ScanKey skey, BTArrayKeyInfo *array);
96
static void _bt_array_set_low_or_high(Relation rel, ScanKey skey,
97
                    BTArrayKeyInfo *array, bool low_not_high);
98
static void _bt_skiparray_set_element(Relation rel, ScanKey skey, BTArrayKeyInfo *array,
99
                    int32 set_elem_result, Datum tupdatum, bool tupnull);
100
static void _bt_skiparray_set_isnull(Relation rel, ScanKey skey, BTArrayKeyInfo *array);
101
static inline int32 _bt_compare_array_skey(FmgrInfo *orderproc,
102
                       Datum tupdatum, bool tupnull,
103
                       Datum arrdatum, ScanKey cur);
104
static void _bt_binsrch_skiparray_skey(bool cur_elem_trig, ScanDirection dir,
105
                     Datum tupdatum, bool tupnull,
106
                     BTArrayKeyInfo *array, ScanKey cur,
107
                     int32 *set_elem_result);
108
#ifdef USE_ASSERT_CHECKING
109
static bool _bt_verify_keys_with_arraykeys(IndexScanDesc scan);
110
#endif
111
112
113
/*
114
 *  _bt_readpage() -- Load data from current index page into so->currPos
115
 *
116
 * Caller must have pinned and read-locked so->currPos.buf; the buffer's state
117
 * is not changed here.  Also, currPos.moreLeft and moreRight must be valid;
118
 * they are updated as appropriate.  All other fields of so->currPos are
119
 * initialized from scratch here.
120
 *
121
 * We scan the current page starting at offnum and moving in the indicated
122
 * direction.  All items matching the scan keys are loaded into currPos.items.
123
 * moreLeft or moreRight (as appropriate) is cleared if _bt_checkkeys reports
124
 * that there can be no more matching tuples in the current scan direction
125
 * (could just be for the current primitive index scan when scan has arrays).
126
 *
127
 * In the case of a parallel scan, caller must have called _bt_parallel_seize
128
 * prior to calling this function; this function will invoke
129
 * _bt_parallel_release before returning.
130
 *
131
 * Returns true if any matching items found on the page, false if none.
132
 */
133
bool
134
_bt_readpage(IndexScanDesc scan, ScanDirection dir, OffsetNumber offnum,
135
       bool firstpage)
136
0
{
137
0
  Relation  rel = scan->indexRelation;
138
0
  BTScanOpaque so = (BTScanOpaque) scan->opaque;
139
0
  Page    page;
140
0
  BTPageOpaque opaque;
141
0
  OffsetNumber minoff;
142
0
  OffsetNumber maxoff;
143
0
  BTReadPageState pstate;
144
0
  bool    arrayKeys,
145
0
        ignore_killed_tuples = scan->ignore_killed_tuples;
146
0
  int     itemIndex,
147
0
        indnatts;
148
149
  /* save the page/buffer block number, along with its sibling links */
150
0
  page = BufferGetPage(so->currPos.buf);
151
0
  opaque = BTPageGetOpaque(page);
152
0
  so->currPos.currPage = BufferGetBlockNumber(so->currPos.buf);
153
0
  so->currPos.prevPage = opaque->btpo_prev;
154
0
  so->currPos.nextPage = opaque->btpo_next;
155
  /* delay setting so->currPos.lsn until _bt_drop_lock_and_maybe_pin */
156
0
  pstate.dir = so->currPos.dir = dir;
157
0
  so->currPos.nextTupleOffset = 0;
158
159
  /* either moreRight or moreLeft should be set now (may be unset later) */
160
0
  Assert(ScanDirectionIsForward(dir) ? so->currPos.moreRight :
161
0
       so->currPos.moreLeft);
162
0
  Assert(!P_IGNORE(opaque));
163
0
  Assert(BTScanPosIsPinned(so->currPos));
164
0
  Assert(!so->needPrimScan);
165
166
  /* initialize local variables */
167
0
  indnatts = IndexRelationGetNumberOfAttributes(rel);
168
0
  arrayKeys = so->numArrayKeys != 0;
169
0
  minoff = P_FIRSTDATAKEY(opaque);
170
0
  maxoff = PageGetMaxOffsetNumber(page);
171
172
  /* initialize page-level state that we'll pass to _bt_checkkeys */
173
0
  pstate.minoff = minoff;
174
0
  pstate.maxoff = maxoff;
175
0
  pstate.finaltup = NULL;
176
0
  pstate.page = page;
177
0
  pstate.firstpage = firstpage;
178
0
  pstate.forcenonrequired = false;
179
0
  pstate.startikey = 0;
180
0
  pstate.offnum = InvalidOffsetNumber;
181
0
  pstate.skip = InvalidOffsetNumber;
182
0
  pstate.continuescan = true; /* default assumption */
183
0
  pstate.rechecks = 0;
184
0
  pstate.targetdistance = 0;
185
0
  pstate.nskipadvances = 0;
186
187
0
  if (scan->parallel_scan)
188
0
  {
189
    /* allow next/prev page to be read by other worker without delay */
190
0
    if (ScanDirectionIsForward(dir))
191
0
      _bt_parallel_release(scan, so->currPos.nextPage,
192
0
                 so->currPos.currPage);
193
0
    else
194
0
      _bt_parallel_release(scan, so->currPos.prevPage,
195
0
                 so->currPos.currPage);
196
0
  }
197
198
0
  PredicateLockPage(rel, so->currPos.currPage, scan->xs_snapshot);
199
200
0
  if (ScanDirectionIsForward(dir))
201
0
  {
202
    /* SK_SEARCHARRAY forward scans must provide high key up front */
203
0
    if (arrayKeys)
204
0
    {
205
0
      if (!P_RIGHTMOST(opaque))
206
0
      {
207
0
        ItemId    iid = PageGetItemId(page, P_HIKEY);
208
209
0
        pstate.finaltup = (IndexTuple) PageGetItem(page, iid);
210
211
0
        if (unlikely(so->scanBehind) &&
212
0
          !_bt_scanbehind_checkkeys(scan, dir, pstate.finaltup))
213
0
        {
214
          /* Schedule another primitive index scan after all */
215
0
          so->currPos.moreRight = false;
216
0
          so->needPrimScan = true;
217
0
          if (scan->parallel_scan)
218
0
            _bt_parallel_primscan_schedule(scan,
219
0
                             so->currPos.currPage);
220
0
          return false;
221
0
        }
222
0
      }
223
224
0
      so->scanBehind = so->oppositeDirCheck = false;  /* reset */
225
0
    }
226
227
    /*
228
     * Consider pstate.startikey optimization once the ongoing primitive
229
     * index scan has already read at least one page
230
     */
231
0
    if (!pstate.firstpage && minoff < maxoff)
232
0
      _bt_set_startikey(scan, &pstate);
233
234
    /* load items[] in ascending order */
235
0
    itemIndex = 0;
236
237
0
    offnum = Max(offnum, minoff);
238
239
0
    while (offnum <= maxoff)
240
0
    {
241
0
      ItemId    iid = PageGetItemId(page, offnum);
242
0
      IndexTuple  itup;
243
0
      bool    passes_quals;
244
245
      /*
246
       * If the scan specifies not to return killed tuples, then we
247
       * treat a killed tuple as not passing the qual
248
       */
249
0
      if (ignore_killed_tuples && ItemIdIsDead(iid))
250
0
      {
251
0
        offnum = OffsetNumberNext(offnum);
252
0
        continue;
253
0
      }
254
255
0
      itup = (IndexTuple) PageGetItem(page, iid);
256
0
      Assert(!BTreeTupleIsPivot(itup));
257
258
0
      pstate.offnum = offnum;
259
0
      passes_quals = _bt_checkkeys(scan, &pstate, arrayKeys,
260
0
                     itup, indnatts);
261
262
      /*
263
       * Check if we need to skip ahead to a later tuple (only possible
264
       * when the scan uses array keys)
265
       */
266
0
      if (arrayKeys && OffsetNumberIsValid(pstate.skip))
267
0
      {
268
0
        Assert(!passes_quals && pstate.continuescan);
269
0
        Assert(offnum < pstate.skip);
270
0
        Assert(!pstate.forcenonrequired);
271
272
0
        offnum = pstate.skip;
273
0
        pstate.skip = InvalidOffsetNumber;
274
0
        continue;
275
0
      }
276
277
0
      if (passes_quals)
278
0
      {
279
        /* tuple passes all scan key conditions */
280
0
        if (!BTreeTupleIsPosting(itup))
281
0
        {
282
          /* Remember it */
283
0
          _bt_saveitem(so, itemIndex, offnum, itup);
284
0
          itemIndex++;
285
0
        }
286
0
        else
287
0
        {
288
0
          int     tupleOffset;
289
290
          /* Set up posting list state (and remember first TID) */
291
0
          tupleOffset =
292
0
            _bt_setuppostingitems(so, itemIndex, offnum,
293
0
                        BTreeTupleGetPostingN(itup, 0),
294
0
                        itup);
295
0
          itemIndex++;
296
297
          /* Remember all later TIDs (must be at least one) */
298
0
          for (int i = 1; i < BTreeTupleGetNPosting(itup); i++)
299
0
          {
300
0
            _bt_savepostingitem(so, itemIndex, offnum,
301
0
                      BTreeTupleGetPostingN(itup, i),
302
0
                      tupleOffset);
303
0
            itemIndex++;
304
0
          }
305
0
        }
306
0
      }
307
      /* When !continuescan, there can't be any more matches, so stop */
308
0
      if (!pstate.continuescan)
309
0
        break;
310
311
0
      offnum = OffsetNumberNext(offnum);
312
0
    }
313
314
    /*
315
     * We don't need to visit page to the right when the high key
316
     * indicates that no more matches will be found there.
317
     *
318
     * Checking the high key like this works out more often than you might
319
     * think.  Leaf page splits pick a split point between the two most
320
     * dissimilar tuples (this is weighed against the need to evenly share
321
     * free space).  Leaf pages with high key attribute values that can
322
     * only appear on non-pivot tuples on the right sibling page are
323
     * common.
324
     */
325
0
    if (pstate.continuescan && !so->scanBehind && !P_RIGHTMOST(opaque))
326
0
    {
327
0
      ItemId    iid = PageGetItemId(page, P_HIKEY);
328
0
      IndexTuple  itup = (IndexTuple) PageGetItem(page, iid);
329
0
      int     truncatt;
330
331
      /* Reset arrays, per _bt_set_startikey contract */
332
0
      if (pstate.forcenonrequired)
333
0
        _bt_start_array_keys(scan, dir);
334
0
      pstate.forcenonrequired = false;
335
0
      pstate.startikey = 0; /* _bt_set_startikey ignores P_HIKEY */
336
337
0
      truncatt = BTreeTupleGetNAtts(itup, rel);
338
0
      _bt_checkkeys(scan, &pstate, arrayKeys, itup, truncatt);
339
0
    }
340
341
0
    if (!pstate.continuescan)
342
0
      so->currPos.moreRight = false;
343
344
0
    Assert(itemIndex <= MaxTIDsPerBTreePage);
345
0
    so->currPos.firstItem = 0;
346
0
    so->currPos.lastItem = itemIndex - 1;
347
0
    so->currPos.itemIndex = 0;
348
0
  }
349
0
  else
350
0
  {
351
    /* SK_SEARCHARRAY backward scans must provide final tuple up front */
352
0
    if (arrayKeys)
353
0
    {
354
0
      if (minoff <= maxoff && !P_LEFTMOST(opaque))
355
0
      {
356
0
        ItemId    iid = PageGetItemId(page, minoff);
357
358
0
        pstate.finaltup = (IndexTuple) PageGetItem(page, iid);
359
360
0
        if (unlikely(so->scanBehind) &&
361
0
          !_bt_scanbehind_checkkeys(scan, dir, pstate.finaltup))
362
0
        {
363
          /* Schedule another primitive index scan after all */
364
0
          so->currPos.moreLeft = false;
365
0
          so->needPrimScan = true;
366
0
          if (scan->parallel_scan)
367
0
            _bt_parallel_primscan_schedule(scan,
368
0
                             so->currPos.currPage);
369
0
          return false;
370
0
        }
371
0
      }
372
373
0
      so->scanBehind = so->oppositeDirCheck = false;  /* reset */
374
0
    }
375
376
    /*
377
     * Consider pstate.startikey optimization once the ongoing primitive
378
     * index scan has already read at least one page
379
     */
380
0
    if (!pstate.firstpage && minoff < maxoff)
381
0
      _bt_set_startikey(scan, &pstate);
382
383
    /* load items[] in descending order */
384
0
    itemIndex = MaxTIDsPerBTreePage;
385
386
0
    offnum = Min(offnum, maxoff);
387
388
0
    while (offnum >= minoff)
389
0
    {
390
0
      ItemId    iid = PageGetItemId(page, offnum);
391
0
      IndexTuple  itup;
392
0
      bool    tuple_alive;
393
0
      bool    passes_quals;
394
395
      /*
396
       * If the scan specifies not to return killed tuples, then we
397
       * treat a killed tuple as not passing the qual.  Most of the
398
       * time, it's a win to not bother examining the tuple's index
399
       * keys, but just skip to the next tuple (previous, actually,
400
       * since we're scanning backwards).  However, if this is the first
401
       * tuple on the page, we do check the index keys, to prevent
402
       * uselessly advancing to the page to the left.  This is similar
403
       * to the high key optimization used by forward scans.
404
       */
405
0
      if (ignore_killed_tuples && ItemIdIsDead(iid))
406
0
      {
407
0
        if (offnum > minoff)
408
0
        {
409
0
          offnum = OffsetNumberPrev(offnum);
410
0
          continue;
411
0
        }
412
413
0
        tuple_alive = false;
414
0
      }
415
0
      else
416
0
        tuple_alive = true;
417
418
0
      itup = (IndexTuple) PageGetItem(page, iid);
419
0
      Assert(!BTreeTupleIsPivot(itup));
420
421
0
      pstate.offnum = offnum;
422
0
      if (arrayKeys && offnum == minoff && pstate.forcenonrequired)
423
0
      {
424
        /* Reset arrays, per _bt_set_startikey contract */
425
0
        pstate.forcenonrequired = false;
426
0
        pstate.startikey = 0;
427
0
        _bt_start_array_keys(scan, dir);
428
0
      }
429
0
      passes_quals = _bt_checkkeys(scan, &pstate, arrayKeys,
430
0
                     itup, indnatts);
431
432
0
      if (arrayKeys && so->scanBehind)
433
0
      {
434
        /*
435
         * Done scanning this page, but not done with the current
436
         * primscan.
437
         *
438
         * Note: Forward scans don't check this explicitly, since they
439
         * prefer to reuse pstate.skip for this instead.
440
         */
441
0
        Assert(!passes_quals && pstate.continuescan);
442
0
        Assert(!pstate.forcenonrequired);
443
444
0
        break;
445
0
      }
446
447
      /*
448
       * Check if we need to skip ahead to a later tuple (only possible
449
       * when the scan uses array keys)
450
       */
451
0
      if (arrayKeys && OffsetNumberIsValid(pstate.skip))
452
0
      {
453
0
        Assert(!passes_quals && pstate.continuescan);
454
0
        Assert(offnum > pstate.skip);
455
0
        Assert(!pstate.forcenonrequired);
456
457
0
        offnum = pstate.skip;
458
0
        pstate.skip = InvalidOffsetNumber;
459
0
        continue;
460
0
      }
461
462
0
      if (passes_quals && tuple_alive)
463
0
      {
464
        /* tuple passes all scan key conditions */
465
0
        if (!BTreeTupleIsPosting(itup))
466
0
        {
467
          /* Remember it */
468
0
          itemIndex--;
469
0
          _bt_saveitem(so, itemIndex, offnum, itup);
470
0
        }
471
0
        else
472
0
        {
473
0
          uint16    nitems = BTreeTupleGetNPosting(itup);
474
0
          int     tupleOffset;
475
476
          /* Set up posting list state (and remember last TID) */
477
0
          itemIndex--;
478
0
          tupleOffset =
479
0
            _bt_setuppostingitems(so, itemIndex, offnum,
480
0
                        BTreeTupleGetPostingN(itup, nitems - 1),
481
0
                        itup);
482
483
          /* Remember all prior TIDs (must be at least one) */
484
0
          for (int i = nitems - 2; i >= 0; i--)
485
0
          {
486
0
            itemIndex--;
487
0
            _bt_savepostingitem(so, itemIndex, offnum,
488
0
                      BTreeTupleGetPostingN(itup, i),
489
0
                      tupleOffset);
490
0
          }
491
0
        }
492
0
      }
493
      /* When !continuescan, there can't be any more matches, so stop */
494
0
      if (!pstate.continuescan)
495
0
        break;
496
497
0
      offnum = OffsetNumberPrev(offnum);
498
0
    }
499
500
    /*
501
     * We don't need to visit page to the left when no more matches will
502
     * be found there
503
     */
504
0
    if (!pstate.continuescan)
505
0
      so->currPos.moreLeft = false;
506
507
0
    Assert(itemIndex >= 0);
508
0
    so->currPos.firstItem = itemIndex;
509
0
    so->currPos.lastItem = MaxTIDsPerBTreePage - 1;
510
0
    so->currPos.itemIndex = MaxTIDsPerBTreePage - 1;
511
0
  }
512
513
  /*
514
   * If _bt_set_startikey told us to temporarily treat the scan's keys as
515
   * nonrequired (possible only during scans with array keys), there must be
516
   * no lasting consequences for the scan's array keys.  The scan's arrays
517
   * should now have exactly the same elements as they would have had if the
518
   * nonrequired behavior had never been used.  (In general, a scan's arrays
519
   * are expected to track its progress through the index's key space.)
520
   *
521
   * We are required (by _bt_set_startikey) to call _bt_checkkeys against
522
   * pstate.finaltup with pstate.forcenonrequired=false to allow the scan's
523
   * arrays to recover.  Assert that that step hasn't been missed.
524
   */
525
0
  Assert(!pstate.forcenonrequired);
526
527
0
  return (so->currPos.firstItem <= so->currPos.lastItem);
528
0
}
529
530
/*
531
 * _bt_start_array_keys() -- Initialize array keys at start of a scan
532
 *
533
 * Set up the cur_elem counters and fill in the first sk_argument value for
534
 * each array scankey.
535
 */
536
void
537
_bt_start_array_keys(IndexScanDesc scan, ScanDirection dir)
538
0
{
539
0
  Relation  rel = scan->indexRelation;
540
0
  BTScanOpaque so = (BTScanOpaque) scan->opaque;
541
542
0
  Assert(so->numArrayKeys);
543
0
  Assert(so->qual_ok);
544
545
0
  for (int i = 0; i < so->numArrayKeys; i++)
546
0
  {
547
0
    BTArrayKeyInfo *array = &so->arrayKeys[i];
548
0
    ScanKey   skey = &so->keyData[array->scan_key];
549
550
0
    Assert(skey->sk_flags & SK_SEARCHARRAY);
551
0
    Assert(skey->sk_strategy == BTEqualStrategyNumber);
552
553
0
    _bt_array_set_low_or_high(rel, skey, array,
554
0
                  ScanDirectionIsForward(dir));
555
0
  }
556
0
  so->scanBehind = so->oppositeDirCheck = false;  /* reset */
557
0
}
558
559
/*
560
 * Determines an offset to the first scan key (an so->keyData[]-wise offset)
561
 * that is _not_ guaranteed to be satisfied by every tuple from pstate.page,
562
 * which is set in pstate.startikey for _bt_checkkeys calls for the page.
563
 * This allows caller to save cycles on comparisons of a prefix of keys while
564
 * reading pstate.page.
565
 *
566
 * Also determines if later calls to _bt_checkkeys (for pstate.page) should be
567
 * forced to treat all required scan keys >= pstate.startikey as nonrequired
568
 * (that is, if they're to be treated as if any SK_BT_REQFWD/SK_BT_REQBKWD
569
 * markings that were set by preprocessing were not set at all, for the
570
 * duration of _bt_checkkeys calls prior to the call for pstate.finaltup).
571
 * This is indicated to caller by setting pstate.forcenonrequired.
572
 *
573
 * Call here at the start of reading a leaf page beyond the first one for the
574
 * primitive index scan.  We consider all non-pivot tuples, so it doesn't make
575
 * sense to call here when only a subset of those tuples can ever be read.
576
 * This is also a good idea on performance grounds; not calling here when on
577
 * the first page (first for the current primitive scan) avoids wasting cycles
578
 * during selective point queries.  They typically don't stand to gain as much
579
 * when we can set pstate.startikey, and are likely to notice the overhead of
580
 * calling here.  (Also, allowing pstate.forcenonrequired to be set on a
581
 * primscan's first page would mislead _bt_advance_array_keys, which expects
582
 * pstate.nskipadvances to be representative of every first page's key space.)
583
 *
584
 * Caller must call _bt_start_array_keys and reset startikey/forcenonrequired
585
 * ahead of the finaltup _bt_checkkeys call when we set forcenonrequired=true.
586
 * This will give _bt_checkkeys the opportunity to call _bt_advance_array_keys
587
 * with sktrig_required=true, restoring the invariant that the scan's required
588
 * arrays always track the scan's progress through the index's key space.
589
 * Caller won't need to do this on the rightmost/leftmost page in the index
590
 * (where pstate.finaltup isn't ever set), since forcenonrequired will never
591
 * be set here in the first place.
592
 */
593
static void
594
_bt_set_startikey(IndexScanDesc scan, BTReadPageState *pstate)
595
0
{
596
0
  BTScanOpaque so = (BTScanOpaque) scan->opaque;
597
0
  Relation  rel = scan->indexRelation;
598
0
  TupleDesc tupdesc = RelationGetDescr(rel);
599
0
  ItemId    iid;
600
0
  IndexTuple  firsttup,
601
0
        lasttup;
602
0
  int     startikey = 0,
603
0
        arrayidx = 0,
604
0
        firstchangingattnum;
605
0
  bool    start_past_saop_eq = false;
606
607
0
  Assert(!so->scanBehind);
608
0
  Assert(pstate->minoff < pstate->maxoff);
609
0
  Assert(!pstate->firstpage);
610
0
  Assert(pstate->startikey == 0);
611
0
  Assert(!so->numArrayKeys || pstate->finaltup ||
612
0
       P_RIGHTMOST(BTPageGetOpaque(pstate->page)) ||
613
0
       P_LEFTMOST(BTPageGetOpaque(pstate->page)));
614
615
0
  if (so->numberOfKeys == 0)
616
0
    return;
617
618
  /* minoff is an offset to the lowest non-pivot tuple on the page */
619
0
  iid = PageGetItemId(pstate->page, pstate->minoff);
620
0
  firsttup = (IndexTuple) PageGetItem(pstate->page, iid);
621
622
  /* maxoff is an offset to the highest non-pivot tuple on the page */
623
0
  iid = PageGetItemId(pstate->page, pstate->maxoff);
624
0
  lasttup = (IndexTuple) PageGetItem(pstate->page, iid);
625
626
  /* Determine the first attribute whose values change on caller's page */
627
0
  firstchangingattnum = _bt_keep_natts_fast(rel, firsttup, lasttup);
628
629
0
  for (; startikey < so->numberOfKeys; startikey++)
630
0
  {
631
0
    ScanKey   key = so->keyData + startikey;
632
0
    BTArrayKeyInfo *array;
633
0
    Datum   firstdatum,
634
0
          lastdatum;
635
0
    bool    firstnull,
636
0
          lastnull;
637
0
    int32   result;
638
639
    /*
640
     * Determine if it's safe to set pstate.startikey to an offset to a
641
     * key that comes after this key, by examining this key
642
     */
643
0
    if (key->sk_flags & SK_ROW_HEADER)
644
0
    {
645
      /* RowCompare inequality (header key) */
646
0
      ScanKey   subkey = (ScanKey) DatumGetPointer(key->sk_argument);
647
0
      bool    satisfied = false;
648
649
0
      for (;;)
650
0
      {
651
0
        int     cmpresult;
652
0
        bool    firstsatisfies = false;
653
654
0
        if (subkey->sk_attno > firstchangingattnum) /* >, not >= */
655
0
          break;   /* unsafe, preceding attr has multiple
656
                 * distinct values */
657
658
0
        if (subkey->sk_flags & SK_ISNULL)
659
0
          break;   /* unsafe, unsatisfiable NULL subkey arg */
660
661
0
        firstdatum = index_getattr(firsttup, subkey->sk_attno,
662
0
                       tupdesc, &firstnull);
663
0
        lastdatum = index_getattr(lasttup, subkey->sk_attno,
664
0
                      tupdesc, &lastnull);
665
666
0
        if (firstnull || lastnull)
667
0
          break;   /* unsafe, NULL value won't satisfy subkey */
668
669
        /*
670
         * Compare the first tuple's datum for this row compare member
671
         */
672
0
        cmpresult = DatumGetInt32(FunctionCall2Coll(&subkey->sk_func,
673
0
                              subkey->sk_collation,
674
0
                              firstdatum,
675
0
                              subkey->sk_argument));
676
0
        if (subkey->sk_flags & SK_BT_DESC)
677
0
          INVERT_COMPARE_RESULT(cmpresult);
678
679
0
        if (cmpresult != 0 || (subkey->sk_flags & SK_ROW_END))
680
0
        {
681
0
          firstsatisfies = _bt_rowcompare_cmpresult(subkey,
682
0
                                cmpresult);
683
0
          if (!firstsatisfies)
684
0
          {
685
            /* Unsafe, firstdatum does not satisfy subkey */
686
0
            break;
687
0
          }
688
0
        }
689
690
        /*
691
         * Compare the last tuple's datum for this row compare member
692
         */
693
0
        cmpresult = DatumGetInt32(FunctionCall2Coll(&subkey->sk_func,
694
0
                              subkey->sk_collation,
695
0
                              lastdatum,
696
0
                              subkey->sk_argument));
697
0
        if (subkey->sk_flags & SK_BT_DESC)
698
0
          INVERT_COMPARE_RESULT(cmpresult);
699
700
0
        if (cmpresult != 0 || (subkey->sk_flags & SK_ROW_END))
701
0
        {
702
0
          if (!firstsatisfies)
703
0
          {
704
            /*
705
             * It's only safe to set startikey beyond the row
706
             * compare header key when both firsttup and lasttup
707
             * satisfy the key as a whole based on the same
708
             * deciding subkey/attribute.  That can't happen now.
709
             */
710
0
            break;  /* unsafe */
711
0
          }
712
713
0
          satisfied = _bt_rowcompare_cmpresult(subkey, cmpresult);
714
0
          break;   /* safe iff 'satisfied' is true */
715
0
        }
716
717
        /* Move on to next row member/subkey */
718
0
        if (subkey->sk_flags & SK_ROW_END)
719
0
          break;   /* defensive */
720
0
        subkey++;
721
722
        /*
723
         * We deliberately don't check if the next subkey has the same
724
         * strategy as this iteration's subkey (which happens when
725
         * subkeys for both ASC and DESC columns are used together),
726
         * nor if any subkey is marked required.  This is safe because
727
         * in general all prior index attributes must have only one
728
         * distinct value (across all of the tuples on the page) in
729
         * order for us to even consider any subkey's attribute.
730
         */
731
0
      }
732
733
0
      if (satisfied)
734
0
      {
735
        /* Safe, row compare satisfied by every tuple on page */
736
0
        continue;
737
0
      }
738
739
0
      break;       /* unsafe */
740
0
    }
741
0
    if (key->sk_strategy != BTEqualStrategyNumber)
742
0
    {
743
      /*
744
       * Scalar inequality key.
745
       *
746
       * It's definitely safe for _bt_checkkeys to avoid assessing this
747
       * inequality when the page's first and last non-pivot tuples both
748
       * satisfy the inequality (since the same must also be true of all
749
       * the tuples in between these two).
750
       *
751
       * Unlike the "=" case, it doesn't matter if this attribute has
752
       * more than one distinct value (though it _is_ necessary for any
753
       * and all _prior_ attributes to contain no more than one distinct
754
       * value amongst all of the tuples from pstate.page).
755
       */
756
0
      if (key->sk_attno > firstchangingattnum) /* >, not >= */
757
0
        break;     /* unsafe, preceding attr has multiple
758
                 * distinct values */
759
760
0
      firstdatum = index_getattr(firsttup, key->sk_attno, tupdesc, &firstnull);
761
0
      lastdatum = index_getattr(lasttup, key->sk_attno, tupdesc, &lastnull);
762
763
0
      if (key->sk_flags & SK_ISNULL)
764
0
      {
765
        /* IS NOT NULL key */
766
0
        Assert(key->sk_flags & SK_SEARCHNOTNULL);
767
768
0
        if (firstnull || lastnull)
769
0
          break;   /* unsafe */
770
771
        /* Safe, IS NOT NULL key satisfied by every tuple */
772
0
        continue;
773
0
      }
774
775
      /* Test firsttup */
776
0
      if (firstnull ||
777
0
        !DatumGetBool(FunctionCall2Coll(&key->sk_func,
778
0
                        key->sk_collation, firstdatum,
779
0
                        key->sk_argument)))
780
0
        break;     /* unsafe */
781
782
      /* Test lasttup */
783
0
      if (lastnull ||
784
0
        !DatumGetBool(FunctionCall2Coll(&key->sk_func,
785
0
                        key->sk_collation, lastdatum,
786
0
                        key->sk_argument)))
787
0
        break;     /* unsafe */
788
789
      /* Safe, scalar inequality satisfied by every tuple */
790
0
      continue;
791
0
    }
792
793
    /* Some = key (could be a scalar = key, could be an array = key) */
794
0
    Assert(key->sk_strategy == BTEqualStrategyNumber);
795
796
0
    if (!(key->sk_flags & SK_SEARCHARRAY))
797
0
    {
798
      /*
799
       * Scalar = key (possibly an IS NULL key).
800
       *
801
       * It is unsafe to set pstate.startikey to an ikey beyond this
802
       * key, unless the = key is satisfied by every possible tuple on
803
       * the page (possible only when attribute has just one distinct
804
       * value among all tuples on the page).
805
       */
806
0
      if (key->sk_attno >= firstchangingattnum)
807
0
        break;     /* unsafe, multiple distinct attr values */
808
809
0
      firstdatum = index_getattr(firsttup, key->sk_attno, tupdesc,
810
0
                     &firstnull);
811
0
      if (key->sk_flags & SK_ISNULL)
812
0
      {
813
        /* IS NULL key */
814
0
        Assert(key->sk_flags & SK_SEARCHNULL);
815
816
0
        if (!firstnull)
817
0
          break;   /* unsafe */
818
819
        /* Safe, IS NULL key satisfied by every tuple */
820
0
        continue;
821
0
      }
822
0
      if (firstnull ||
823
0
        !DatumGetBool(FunctionCall2Coll(&key->sk_func,
824
0
                        key->sk_collation, firstdatum,
825
0
                        key->sk_argument)))
826
0
        break;     /* unsafe */
827
828
      /* Safe, scalar = key satisfied by every tuple */
829
0
      continue;
830
0
    }
831
832
    /* = array key (could be a SAOP array, could be a skip array) */
833
0
    array = &so->arrayKeys[arrayidx++];
834
0
    Assert(array->scan_key == startikey);
835
0
    if (array->num_elems != -1)
836
0
    {
837
      /*
838
       * SAOP array = key.
839
       *
840
       * Handle this like we handle scalar = keys (though binary search
841
       * for a matching element, to avoid relying on key's sk_argument).
842
       */
843
0
      if (key->sk_attno >= firstchangingattnum)
844
0
        break;     /* unsafe, multiple distinct attr values */
845
846
0
      firstdatum = index_getattr(firsttup, key->sk_attno, tupdesc,
847
0
                     &firstnull);
848
0
      _bt_binsrch_array_skey(&so->orderProcs[startikey],
849
0
                   false, NoMovementScanDirection,
850
0
                   firstdatum, firstnull, array, key,
851
0
                   &result);
852
0
      if (result != 0)
853
0
        break;     /* unsafe */
854
855
      /* Safe, SAOP = key satisfied by every tuple */
856
0
      start_past_saop_eq = true;
857
0
      continue;
858
0
    }
859
860
    /*
861
     * Skip array = key
862
     */
863
0
    Assert(key->sk_flags & SK_BT_SKIP);
864
0
    if (array->null_elem)
865
0
    {
866
      /*
867
       * Non-range skip array = key.
868
       *
869
       * Safe, non-range skip array "satisfied" by every tuple on page
870
       * (safe even when "key->sk_attno > firstchangingattnum").
871
       */
872
0
      continue;
873
0
    }
874
875
    /*
876
     * Range skip array = key.
877
     *
878
     * Handle this like we handle scalar inequality keys (but avoid using
879
     * key's sk_argument directly, as in the SAOP array case).
880
     */
881
0
    if (key->sk_attno > firstchangingattnum) /* >, not >= */
882
0
      break;       /* unsafe, preceding attr has multiple
883
                 * distinct values */
884
885
0
    firstdatum = index_getattr(firsttup, key->sk_attno, tupdesc, &firstnull);
886
0
    lastdatum = index_getattr(lasttup, key->sk_attno, tupdesc, &lastnull);
887
888
    /* Test firsttup */
889
0
    _bt_binsrch_skiparray_skey(false, ForwardScanDirection,
890
0
                   firstdatum, firstnull, array, key,
891
0
                   &result);
892
0
    if (result != 0)
893
0
      break;       /* unsafe */
894
895
    /* Test lasttup */
896
0
    _bt_binsrch_skiparray_skey(false, ForwardScanDirection,
897
0
                   lastdatum, lastnull, array, key,
898
0
                   &result);
899
0
    if (result != 0)
900
0
      break;       /* unsafe */
901
902
    /* Safe, range skip array satisfied by every tuple on page */
903
0
  }
904
905
  /*
906
   * Use of forcenonrequired is typically undesirable, since it'll force
907
   * _bt_readpage caller to read every tuple on the page -- even though, in
908
   * general, it might well be possible to end the scan on an earlier tuple.
909
   * However, caller must use forcenonrequired when start_past_saop_eq=true,
910
   * since the usual required array behavior might fail to roll over to the
911
   * SAOP array.
912
   *
913
   * We always prefer forcenonrequired=true during scans with skip arrays
914
   * (except on the first page of each primitive index scan), though -- even
915
   * when "startikey == 0".  That way, _bt_advance_array_keys's low-order
916
   * key precheck optimization can always be used (unless on the first page
917
   * of the scan).  It seems slightly preferable to check more tuples when
918
   * that allows us to do significantly less skip array maintenance.
919
   */
920
0
  pstate->forcenonrequired = (start_past_saop_eq || so->skipScan);
921
0
  pstate->startikey = startikey;
922
923
  /*
924
   * _bt_readpage caller is required to call _bt_checkkeys against page's
925
   * finaltup with forcenonrequired=false whenever we initially set
926
   * forcenonrequired=true.  That way the scan's arrays will reliably track
927
   * its progress through the index's key space.
928
   *
929
   * We don't expect this when _bt_readpage caller has no finaltup due to
930
   * its page being the rightmost (or the leftmost, during backwards scans).
931
   * When we see that _bt_readpage has no finaltup, back out of everything.
932
   */
933
0
  Assert(!pstate->forcenonrequired || so->numArrayKeys);
934
0
  if (pstate->forcenonrequired && !pstate->finaltup)
935
0
  {
936
0
    pstate->forcenonrequired = false;
937
0
    pstate->startikey = 0;
938
0
  }
939
0
}
940
941
/*
942
 * Test whether caller's finaltup tuple is still before the start of matches
943
 * for the current array keys.
944
 *
945
 * Called at the start of reading a page during a scan with array keys, though
946
 * only when the so->scanBehind flag was set on the scan's prior page.
947
 *
948
 * Returns false if the tuple is still before the start of matches.  When that
949
 * happens, caller should cut its losses and start a new primitive index scan.
950
 * Otherwise returns true.
951
 */
952
static bool
953
_bt_scanbehind_checkkeys(IndexScanDesc scan, ScanDirection dir,
954
             IndexTuple finaltup)
955
0
{
956
0
  Relation  rel = scan->indexRelation;
957
0
  TupleDesc tupdesc = RelationGetDescr(rel);
958
0
  BTScanOpaque so = (BTScanOpaque) scan->opaque;
959
0
  int     nfinaltupatts = BTreeTupleGetNAtts(finaltup, rel);
960
0
  bool    scanBehind;
961
962
0
  Assert(so->numArrayKeys);
963
964
0
  if (_bt_tuple_before_array_skeys(scan, dir, finaltup, tupdesc,
965
0
                   nfinaltupatts, false, 0, &scanBehind))
966
0
    return false;
967
968
  /*
969
   * If scanBehind was set, all of the untruncated attribute values from
970
   * finaltup that correspond to an array match the array's current element,
971
   * but there are other keys associated with truncated suffix attributes.
972
   * Array advancement must have incremented the scan's arrays on the
973
   * previous page, resulting in a set of array keys that happen to be an
974
   * exact match for the current page high key's untruncated prefix values.
975
   *
976
   * This page definitely doesn't contain tuples that the scan will need to
977
   * return.  The next page may or may not contain relevant tuples.  Handle
978
   * this by cutting our losses and starting a new primscan.
979
   */
980
0
  if (scanBehind)
981
0
    return false;
982
983
0
  if (!so->oppositeDirCheck)
984
0
    return true;
985
986
0
  return _bt_oppodir_checkkeys(scan, dir, finaltup);
987
0
}
988
989
/*
990
 * Test whether an indextuple fails to satisfy an inequality required in the
991
 * opposite direction only.
992
 *
993
 * Caller's finaltup tuple is the page high key (for forwards scans), or the
994
 * first non-pivot tuple (for backwards scans).  Called during scans with
995
 * required array keys and required opposite-direction inequalities.
996
 *
997
 * Returns false if an inequality scan key required in the opposite direction
998
 * only isn't satisfied (and any earlier required scan keys are satisfied).
999
 * Otherwise returns true.
1000
 *
1001
 * An unsatisfied inequality required in the opposite direction only might
1002
 * well enable skipping over many leaf pages, provided another _bt_first call
1003
 * takes place.  This type of unsatisfied inequality won't usually cause
1004
 * _bt_checkkeys to stop the scan to consider array advancement/starting a new
1005
 * primitive index scan.
1006
 */
1007
static bool
1008
_bt_oppodir_checkkeys(IndexScanDesc scan, ScanDirection dir,
1009
            IndexTuple finaltup)
1010
0
{
1011
0
  Relation  rel = scan->indexRelation;
1012
0
  TupleDesc tupdesc = RelationGetDescr(rel);
1013
0
  BTScanOpaque so = (BTScanOpaque) scan->opaque;
1014
0
  int     nfinaltupatts = BTreeTupleGetNAtts(finaltup, rel);
1015
0
  bool    continuescan;
1016
0
  ScanDirection flipped = -dir;
1017
0
  int     ikey = 0;
1018
1019
0
  Assert(so->numArrayKeys);
1020
1021
0
  _bt_check_compare(scan, flipped, finaltup, nfinaltupatts, tupdesc, false,
1022
0
            false, &continuescan,
1023
0
            &ikey);
1024
1025
0
  if (!continuescan && so->keyData[ikey].sk_strategy != BTEqualStrategyNumber)
1026
0
    return false;
1027
1028
0
  return true;
1029
0
}
1030
1031
/* Save an index item into so->currPos.items[itemIndex] */
1032
static void
1033
_bt_saveitem(BTScanOpaque so, int itemIndex,
1034
       OffsetNumber offnum, IndexTuple itup)
1035
0
{
1036
0
  BTScanPosItem *currItem = &so->currPos.items[itemIndex];
1037
1038
0
  Assert(!BTreeTupleIsPivot(itup) && !BTreeTupleIsPosting(itup));
1039
1040
0
  currItem->heapTid = itup->t_tid;
1041
0
  currItem->indexOffset = offnum;
1042
0
  if (so->currTuples)
1043
0
  {
1044
0
    Size    itupsz = IndexTupleSize(itup);
1045
1046
0
    currItem->tupleOffset = so->currPos.nextTupleOffset;
1047
0
    memcpy(so->currTuples + so->currPos.nextTupleOffset, itup, itupsz);
1048
0
    so->currPos.nextTupleOffset += MAXALIGN(itupsz);
1049
0
  }
1050
0
}
1051
1052
/*
1053
 * Setup state to save TIDs/items from a single posting list tuple.
1054
 *
1055
 * Saves an index item into so->currPos.items[itemIndex] for TID that is
1056
 * returned to scan first.  Second or subsequent TIDs for posting list should
1057
 * be saved by calling _bt_savepostingitem().
1058
 *
1059
 * Returns an offset into tuple storage space that main tuple is stored at if
1060
 * needed.
1061
 */
1062
static int
1063
_bt_setuppostingitems(BTScanOpaque so, int itemIndex, OffsetNumber offnum,
1064
            const ItemPointerData *heapTid, IndexTuple itup)
1065
0
{
1066
0
  BTScanPosItem *currItem = &so->currPos.items[itemIndex];
1067
1068
0
  Assert(BTreeTupleIsPosting(itup));
1069
1070
0
  currItem->heapTid = *heapTid;
1071
0
  currItem->indexOffset = offnum;
1072
0
  if (so->currTuples)
1073
0
  {
1074
    /* Save base IndexTuple (truncate posting list) */
1075
0
    IndexTuple  base;
1076
0
    Size    itupsz = BTreeTupleGetPostingOffset(itup);
1077
1078
0
    itupsz = MAXALIGN(itupsz);
1079
0
    currItem->tupleOffset = so->currPos.nextTupleOffset;
1080
0
    base = (IndexTuple) (so->currTuples + so->currPos.nextTupleOffset);
1081
0
    memcpy(base, itup, itupsz);
1082
    /* Defensively reduce work area index tuple header size */
1083
0
    base->t_info &= ~INDEX_SIZE_MASK;
1084
0
    base->t_info |= itupsz;
1085
0
    so->currPos.nextTupleOffset += itupsz;
1086
1087
0
    return currItem->tupleOffset;
1088
0
  }
1089
1090
0
  return 0;
1091
0
}
1092
1093
/*
1094
 * Save an index item into so->currPos.items[itemIndex] for current posting
1095
 * tuple.
1096
 *
1097
 * Assumes that _bt_setuppostingitems() has already been called for current
1098
 * posting list tuple.  Caller passes its return value as tupleOffset.
1099
 */
1100
static inline void
1101
_bt_savepostingitem(BTScanOpaque so, int itemIndex, OffsetNumber offnum,
1102
          ItemPointer heapTid, int tupleOffset)
1103
0
{
1104
0
  BTScanPosItem *currItem = &so->currPos.items[itemIndex];
1105
1106
0
  currItem->heapTid = *heapTid;
1107
0
  currItem->indexOffset = offnum;
1108
1109
  /*
1110
   * Have index-only scans return the same base IndexTuple for every TID
1111
   * that originates from the same posting list
1112
   */
1113
0
  if (so->currTuples)
1114
0
    currItem->tupleOffset = tupleOffset;
1115
0
}
1116
1117
0
#define LOOK_AHEAD_REQUIRED_RECHECKS  3
1118
0
#define LOOK_AHEAD_DEFAULT_DISTANCE   5
1119
0
#define NSKIPADVANCES_THRESHOLD     3
1120
1121
/*
1122
 * Test whether an indextuple satisfies all the scankey conditions.
1123
 *
1124
 * Returns true if so, false if not.  If not,
1125
 * we also determine whether there's any need to continue the scan beyond
1126
 * this tuple, and set pstate.continuescan accordingly.  See comments for
1127
 * _bt_preprocess_keys() about how this is done.
1128
 *
1129
 * Forward scan callers can pass a high key tuple in the hopes of having
1130
 * us set pstate.continuescan to false, avoiding an unnecessary visit to
1131
 * the page to the right.
1132
 *
1133
 * Advances the scan's array keys when necessary for arrayKeys=true callers.
1134
 * Scans without any array keys must always pass arrayKeys=false.
1135
 *
1136
 * Also stops and starts primitive index scans for arrayKeys=true callers.
1137
 * Scans with array keys are required to set up page state that helps us with
1138
 * this.  The page's finaltup tuple (the page high key for a forward scan, or
1139
 * the page's first non-pivot tuple for a backward scan) must be set in
1140
 * pstate.finaltup ahead of the first call here for the page.  Set it to
1141
 * NULL for rightmost page (or the leftmost page for backwards scans).
1142
 *
1143
 * scan: index scan descriptor (containing a search-type scankey)
1144
 * pstate: page level input and output parameters
1145
 * arrayKeys: should we advance the scan's array keys if necessary?
1146
 * tuple: index tuple to test
1147
 * tupnatts: number of attributes in tupnatts (high key may be truncated)
1148
 */
1149
static bool
1150
_bt_checkkeys(IndexScanDesc scan, BTReadPageState *pstate, bool arrayKeys,
1151
        IndexTuple tuple, int tupnatts)
1152
0
{
1153
0
  TupleDesc tupdesc = RelationGetDescr(scan->indexRelation);
1154
0
  BTScanOpaque so PG_USED_FOR_ASSERTS_ONLY = (BTScanOpaque) scan->opaque;
1155
0
  ScanDirection dir = pstate->dir;
1156
0
  int     ikey = pstate->startikey;
1157
0
  bool    res;
1158
1159
0
  Assert(BTreeTupleGetNAtts(tuple, scan->indexRelation) == tupnatts);
1160
0
  Assert(!so->needPrimScan && !so->scanBehind && !so->oppositeDirCheck);
1161
0
  Assert(arrayKeys || so->numArrayKeys == 0);
1162
1163
0
  res = _bt_check_compare(scan, dir, tuple, tupnatts, tupdesc, arrayKeys,
1164
0
              pstate->forcenonrequired, &pstate->continuescan,
1165
0
              &ikey);
1166
1167
  /*
1168
   * If _bt_check_compare relied on the pstate.startikey optimization, call
1169
   * again (in assert-enabled builds) to verify it didn't affect our answer.
1170
   *
1171
   * Note: we can't do this when !pstate.forcenonrequired, since any arrays
1172
   * before pstate.startikey won't have advanced on this page at all.
1173
   */
1174
0
  Assert(!pstate->forcenonrequired || arrayKeys);
1175
#ifdef USE_ASSERT_CHECKING
1176
  if (pstate->startikey > 0 && !pstate->forcenonrequired)
1177
  {
1178
    bool    dres,
1179
          dcontinuescan;
1180
    int     dikey = 0;
1181
1182
    /* Pass advancenonrequired=false to avoid array side-effects */
1183
    dres = _bt_check_compare(scan, dir, tuple, tupnatts, tupdesc, false,
1184
                 pstate->forcenonrequired, &dcontinuescan,
1185
                 &dikey);
1186
    Assert(res == dres);
1187
    Assert(pstate->continuescan == dcontinuescan);
1188
1189
    /*
1190
     * Should also get the same ikey result.  We need a slightly weaker
1191
     * assertion during arrayKeys calls, since they might be using an
1192
     * array that couldn't be marked required during preprocessing.
1193
     */
1194
    Assert(arrayKeys || ikey == dikey);
1195
    Assert(ikey <= dikey);
1196
  }
1197
#endif
1198
1199
  /*
1200
   * Only one _bt_check_compare call is required when there are no array
1201
   * scan keys.  Otherwise, we can only accept _bt_check_compare's answer
1202
   * unreservedly when it set pstate.continuescan=true.
1203
   */
1204
0
  if (!arrayKeys || pstate->continuescan)
1205
0
    return res;
1206
1207
  /*
1208
   * _bt_check_compare call set continuescan=false in the presence of array
1209
   * keys.  This could mean that the tuple is just past the end of matches
1210
   * for the current array keys.
1211
   *
1212
   * It's also possible that the scan is still _before_ the _start_ of
1213
   * tuples matching the current set of array keys.  Check for that first.
1214
   */
1215
0
  Assert(!pstate->forcenonrequired);
1216
0
  if (_bt_tuple_before_array_skeys(scan, dir, tuple, tupdesc, tupnatts, true,
1217
0
                   ikey, NULL))
1218
0
  {
1219
    /* Override _bt_check_compare, continue primitive scan */
1220
0
    pstate->continuescan = true;
1221
1222
    /*
1223
     * We will end up here repeatedly given a group of tuples > the
1224
     * previous array keys and < the now-current keys (for a backwards
1225
     * scan it's just the same, though the operators swap positions).
1226
     *
1227
     * We must avoid allowing this linear search process to scan very many
1228
     * tuples from well before the start of tuples matching the current
1229
     * array keys (or from well before the point where we'll once again
1230
     * have to advance the scan's array keys).
1231
     *
1232
     * We keep the overhead under control by speculatively "looking ahead"
1233
     * to later still-unscanned items from this same leaf page.  We'll
1234
     * only attempt this once the number of tuples that the linear search
1235
     * process has examined starts to get out of hand.
1236
     */
1237
0
    pstate->rechecks++;
1238
0
    if (pstate->rechecks >= LOOK_AHEAD_REQUIRED_RECHECKS)
1239
0
    {
1240
      /* See if we should skip ahead within the current leaf page */
1241
0
      _bt_checkkeys_look_ahead(scan, pstate, tupnatts, tupdesc);
1242
1243
      /*
1244
       * Might have set pstate.skip to a later page offset.  When that
1245
       * happens then _bt_readpage caller will inexpensively skip ahead
1246
       * to a later tuple from the same page (the one just after the
1247
       * tuple we successfully "looked ahead" to).
1248
       */
1249
0
    }
1250
1251
    /* This indextuple doesn't match the current qual, in any case */
1252
0
    return false;
1253
0
  }
1254
1255
  /*
1256
   * Caller's tuple is >= the current set of array keys and other equality
1257
   * constraint scan keys (or <= if this is a backwards scan).  It's now
1258
   * clear that we _must_ advance any required array keys in lockstep with
1259
   * the scan.
1260
   */
1261
0
  return _bt_advance_array_keys(scan, pstate, tuple, tupnatts, tupdesc,
1262
0
                  ikey, true);
1263
0
}
1264
1265
/*
1266
 * Test whether an indextuple satisfies current scan condition.
1267
 *
1268
 * Return true if so, false if not.  If not, also sets *continuescan to false
1269
 * when it's also not possible for any later tuples to pass the current qual
1270
 * (with the scan's current set of array keys, in the current scan direction),
1271
 * in addition to setting *ikey to the so->keyData[] subscript/offset for the
1272
 * unsatisfied scan key (needed when caller must consider advancing the scan's
1273
 * array keys).
1274
 *
1275
 * This is a subroutine for _bt_checkkeys.  We provisionally assume that
1276
 * reaching the end of the current set of required keys (in particular the
1277
 * current required array keys) ends the ongoing (primitive) index scan.
1278
 * Callers without array keys should just end the scan right away when they
1279
 * find that continuescan has been set to false here by us.  Things are more
1280
 * complicated for callers with array keys.
1281
 *
1282
 * Callers with array keys must first consider advancing the arrays when
1283
 * continuescan has been set to false here by us.  They must then consider if
1284
 * it really does make sense to end the current (primitive) index scan, in
1285
 * light of everything that is known at that point.  (In general when we set
1286
 * continuescan=false for these callers it must be treated as provisional.)
1287
 *
1288
 * We deal with advancing unsatisfied non-required arrays directly, though.
1289
 * This is safe, since by definition non-required keys can't end the scan.
1290
 * This is just how we determine if non-required arrays are just unsatisfied
1291
 * by the current array key, or if they're truly unsatisfied (that is, if
1292
 * they're unsatisfied by every possible array key).
1293
 *
1294
 * Pass advancenonrequired=false to avoid all array related side effects.
1295
 * This allows _bt_advance_array_keys caller to avoid infinite recursion.
1296
 *
1297
 * Pass forcenonrequired=true to instruct us to treat all keys as nonrequired.
1298
 * This is used to make it safe to temporarily stop properly maintaining the
1299
 * scan's required arrays.  _bt_checkkeys caller (_bt_readpage, actually)
1300
 * determines a prefix of keys that must satisfy every possible corresponding
1301
 * index attribute value from its page, which is passed to us via *ikey arg
1302
 * (this is the first key that might be unsatisfied by tuples on the page).
1303
 * Obviously, we won't maintain any array keys from before *ikey, so it's
1304
 * quite possible for such arrays to "fall behind" the index's keyspace.
1305
 * Caller will need to "catch up" by passing forcenonrequired=true (alongside
1306
 * an *ikey=0) once the page's finaltup is reached.
1307
 *
1308
 * Note: it's safe to pass an *ikey > 0 with forcenonrequired=false, but only
1309
 * when caller determines that it won't affect array maintenance.
1310
 */
1311
static bool
1312
_bt_check_compare(IndexScanDesc scan, ScanDirection dir,
1313
          IndexTuple tuple, int tupnatts, TupleDesc tupdesc,
1314
          bool advancenonrequired, bool forcenonrequired,
1315
          bool *continuescan, int *ikey)
1316
0
{
1317
0
  BTScanOpaque so = (BTScanOpaque) scan->opaque;
1318
1319
0
  *continuescan = true;   /* default assumption */
1320
1321
0
  for (; *ikey < so->numberOfKeys; (*ikey)++)
1322
0
  {
1323
0
    ScanKey   key = so->keyData + *ikey;
1324
0
    Datum   datum;
1325
0
    bool    isNull;
1326
0
    bool    requiredSameDir = false,
1327
0
          requiredOppositeDirOnly = false;
1328
1329
    /*
1330
     * Check if the key is required in the current scan direction, in the
1331
     * opposite scan direction _only_, or in neither direction (except
1332
     * when we're forced to treat all scan keys as nonrequired)
1333
     */
1334
0
    if (forcenonrequired)
1335
0
    {
1336
      /* treating scan's keys as non-required */
1337
0
    }
1338
0
    else if (((key->sk_flags & SK_BT_REQFWD) && ScanDirectionIsForward(dir)) ||
1339
0
         ((key->sk_flags & SK_BT_REQBKWD) && ScanDirectionIsBackward(dir)))
1340
0
      requiredSameDir = true;
1341
0
    else if (((key->sk_flags & SK_BT_REQFWD) && ScanDirectionIsBackward(dir)) ||
1342
0
         ((key->sk_flags & SK_BT_REQBKWD) && ScanDirectionIsForward(dir)))
1343
0
      requiredOppositeDirOnly = true;
1344
1345
0
    if (key->sk_attno > tupnatts)
1346
0
    {
1347
      /*
1348
       * This attribute is truncated (must be high key).  The value for
1349
       * this attribute in the first non-pivot tuple on the page to the
1350
       * right could be any possible value.  Assume that truncated
1351
       * attribute passes the qual.
1352
       */
1353
0
      Assert(BTreeTupleIsPivot(tuple));
1354
0
      continue;
1355
0
    }
1356
1357
    /*
1358
     * A skip array scan key uses one of several sentinel values.  We just
1359
     * fall back on _bt_tuple_before_array_skeys when we see such a value.
1360
     */
1361
0
    if (key->sk_flags & (SK_BT_MINVAL | SK_BT_MAXVAL |
1362
0
               SK_BT_NEXT | SK_BT_PRIOR))
1363
0
    {
1364
0
      Assert(key->sk_flags & SK_SEARCHARRAY);
1365
0
      Assert(key->sk_flags & SK_BT_SKIP);
1366
0
      Assert(requiredSameDir || forcenonrequired);
1367
1368
      /*
1369
       * Cannot fall back on _bt_tuple_before_array_skeys when we're
1370
       * treating the scan's keys as nonrequired, though.  Just handle
1371
       * this like any other non-required equality-type array key.
1372
       */
1373
0
      if (forcenonrequired)
1374
0
        return _bt_advance_array_keys(scan, NULL, tuple, tupnatts,
1375
0
                        tupdesc, *ikey, false);
1376
1377
0
      *continuescan = false;
1378
0
      return false;
1379
0
    }
1380
1381
    /* row-comparison keys need special processing */
1382
0
    if (key->sk_flags & SK_ROW_HEADER)
1383
0
    {
1384
0
      if (_bt_check_rowcompare(key, tuple, tupnatts, tupdesc, dir,
1385
0
                   forcenonrequired, continuescan))
1386
0
        continue;
1387
0
      return false;
1388
0
    }
1389
1390
0
    datum = index_getattr(tuple,
1391
0
                key->sk_attno,
1392
0
                tupdesc,
1393
0
                &isNull);
1394
1395
0
    if (key->sk_flags & SK_ISNULL)
1396
0
    {
1397
      /* Handle IS NULL/NOT NULL tests */
1398
0
      if (key->sk_flags & SK_SEARCHNULL)
1399
0
      {
1400
0
        if (isNull)
1401
0
          continue; /* tuple satisfies this qual */
1402
0
      }
1403
0
      else
1404
0
      {
1405
0
        Assert(key->sk_flags & SK_SEARCHNOTNULL);
1406
0
        Assert(!(key->sk_flags & SK_BT_SKIP));
1407
0
        if (!isNull)
1408
0
          continue; /* tuple satisfies this qual */
1409
0
      }
1410
1411
      /*
1412
       * Tuple fails this qual.  If it's a required qual for the current
1413
       * scan direction, then we can conclude no further tuples will
1414
       * pass, either.
1415
       */
1416
0
      if (requiredSameDir)
1417
0
        *continuescan = false;
1418
0
      else if (unlikely(key->sk_flags & SK_BT_SKIP))
1419
0
      {
1420
        /*
1421
         * If we're treating scan keys as nonrequired, and encounter a
1422
         * skip array scan key whose current element is NULL, then it
1423
         * must be a non-range skip array.  It must be satisfied, so
1424
         * there's no need to call _bt_advance_array_keys to check.
1425
         */
1426
0
        Assert(forcenonrequired && *ikey > 0);
1427
0
        continue;
1428
0
      }
1429
1430
      /*
1431
       * This indextuple doesn't match the qual.
1432
       */
1433
0
      return false;
1434
0
    }
1435
1436
0
    if (isNull)
1437
0
    {
1438
      /*
1439
       * Scalar scan key isn't satisfied by NULL tuple value.
1440
       *
1441
       * If we're treating scan keys as nonrequired, and key is for a
1442
       * skip array, then we must attempt to advance the array to NULL
1443
       * (if we're successful then the tuple might match the qual).
1444
       */
1445
0
      if (unlikely(forcenonrequired && key->sk_flags & SK_BT_SKIP))
1446
0
        return _bt_advance_array_keys(scan, NULL, tuple, tupnatts,
1447
0
                        tupdesc, *ikey, false);
1448
1449
0
      if (key->sk_flags & SK_BT_NULLS_FIRST)
1450
0
      {
1451
        /*
1452
         * Since NULLs are sorted before non-NULLs, we know we have
1453
         * reached the lower limit of the range of values for this
1454
         * index attr.  On a backward scan, we can stop if this qual
1455
         * is one of the "must match" subset.  We can stop regardless
1456
         * of whether the qual is > or <, so long as it's required,
1457
         * because it's not possible for any future tuples to pass. On
1458
         * a forward scan, however, we must keep going, because we may
1459
         * have initially positioned to the start of the index.
1460
         * (_bt_advance_array_keys also relies on this behavior during
1461
         * forward scans.)
1462
         */
1463
0
        if ((requiredSameDir || requiredOppositeDirOnly) &&
1464
0
          ScanDirectionIsBackward(dir))
1465
0
          *continuescan = false;
1466
0
      }
1467
0
      else
1468
0
      {
1469
        /*
1470
         * Since NULLs are sorted after non-NULLs, we know we have
1471
         * reached the upper limit of the range of values for this
1472
         * index attr.  On a forward scan, we can stop if this qual is
1473
         * one of the "must match" subset.  We can stop regardless of
1474
         * whether the qual is > or <, so long as it's required,
1475
         * because it's not possible for any future tuples to pass. On
1476
         * a backward scan, however, we must keep going, because we
1477
         * may have initially positioned to the end of the index.
1478
         * (_bt_advance_array_keys also relies on this behavior during
1479
         * backward scans.)
1480
         */
1481
0
        if ((requiredSameDir || requiredOppositeDirOnly) &&
1482
0
          ScanDirectionIsForward(dir))
1483
0
          *continuescan = false;
1484
0
      }
1485
1486
      /*
1487
       * This indextuple doesn't match the qual.
1488
       */
1489
0
      return false;
1490
0
    }
1491
1492
0
    if (!DatumGetBool(FunctionCall2Coll(&key->sk_func, key->sk_collation,
1493
0
                      datum, key->sk_argument)))
1494
0
    {
1495
      /*
1496
       * Tuple fails this qual.  If it's a required qual for the current
1497
       * scan direction, then we can conclude no further tuples will
1498
       * pass, either.
1499
       */
1500
0
      if (requiredSameDir)
1501
0
        *continuescan = false;
1502
1503
      /*
1504
       * If this is a non-required array key, the tuple needs to be
1505
       * checked against every possible array key.  Handle this by
1506
       * "advancing" the scan key's array to a matching value (if we're
1507
       * successful then the tuple might match the qual).
1508
       */
1509
0
      else if (advancenonrequired && (key->sk_flags & SK_SEARCHARRAY))
1510
0
        return _bt_advance_array_keys(scan, NULL, tuple, tupnatts,
1511
0
                        tupdesc, *ikey, false);
1512
1513
      /*
1514
       * This indextuple doesn't match the qual.
1515
       */
1516
0
      return false;
1517
0
    }
1518
0
  }
1519
1520
  /* If we get here, the tuple passes all index quals. */
1521
0
  return true;
1522
0
}
1523
1524
/*
1525
 * Test whether an indextuple satisfies a row-comparison scan condition.
1526
 *
1527
 * Return true if so, false if not.  If not, also clear *continuescan if
1528
 * it's not possible for any future tuples in the current scan direction
1529
 * to pass the qual.
1530
 *
1531
 * This is a subroutine for _bt_checkkeys/_bt_check_compare.  Caller passes us
1532
 * a row compare header key taken from so->keyData[].
1533
 *
1534
 * Row value comparisons can be described in terms of logical expansions that
1535
 * use only scalar operators.  Consider the following example row comparison:
1536
 *
1537
 * "(a, b, c) > (7, 'bar', 62)"
1538
 *
1539
 * This can be evaluated as:
1540
 *
1541
 * "(a = 7 AND b = 'bar' AND c > 62) OR (a = 7 AND b > 'bar') OR (a > 7)".
1542
 *
1543
 * Notice that this condition is satisfied by _all_ rows that satisfy "a > 7",
1544
 * and by a subset of all rows that satisfy "a >= 7" (possibly all such rows).
1545
 * It _can't_ be satisfied by other rows (where "a < 7" or where "a IS NULL").
1546
 * A row comparison header key can therefore often be treated as if it was a
1547
 * simple scalar inequality on the row compare's most significant column.
1548
 * (For example, _bt_advance_array_keys and most preprocessing routines treat
1549
 * row compares like any other same-strategy inequality on the same column.)
1550
 *
1551
 * Things get more complicated for our row compare given a row where "a = 7".
1552
 * Note that a row compare isn't necessarily satisfied by _every_ tuple that
1553
 * appears between the first and last satisfied tuple returned by the scan,
1554
 * due to the way that its lower-order subkeys are only conditionally applied.
1555
 * A forwards scan that uses our example qual might initially return a tuple
1556
 * "(a, b, c) = (7, 'zebra', 54)".  But it won't subsequently return a tuple
1557
 * "(a, b, c) = (7, NULL, 1)" located to the right of the first matching tuple
1558
 * (assume that "b" was declared NULLS LAST here).  The scan will only return
1559
 * additional matches upon reaching tuples where "a > 7".  If you rereview our
1560
 * example row comparison's logical expansion, you'll understand why this is.
1561
 * (Here we assume that all subkeys could be marked required, guaranteeing
1562
 * that row comparison order matches index order.  This is the common case.)
1563
 *
1564
 * Note that a row comparison header key behaves _exactly_ the same as a
1565
 * similar scalar inequality key on the row's most significant column once the
1566
 * scan reaches the point where it no longer needs to evaluate lower-order
1567
 * subkeys (or before the point where it starts needing to evaluate them).
1568
 * For example, once a forwards scan that uses our example qual reaches the
1569
 * first tuple "a > 7", we'll behave in just the same way as our caller would
1570
 * behave with a similar scalar inequality "a > 7" for the remainder of the
1571
 * scan (assuming that the scan never changes direction/never goes backwards).
1572
 * We'll even set continuescan=false according to exactly the same rules as
1573
 * the ones our caller applies with simple scalar inequalities, including the
1574
 * rules it applies when NULL tuple values don't satisfy an inequality qual.
1575
 */
1576
static bool
1577
_bt_check_rowcompare(ScanKey header, IndexTuple tuple, int tupnatts,
1578
           TupleDesc tupdesc, ScanDirection dir,
1579
           bool forcenonrequired, bool *continuescan)
1580
0
{
1581
0
  ScanKey   subkey = (ScanKey) DatumGetPointer(header->sk_argument);
1582
0
  int32   cmpresult = 0;
1583
0
  bool    result;
1584
1585
  /* First subkey should be same as the header says */
1586
0
  Assert(header->sk_flags & SK_ROW_HEADER);
1587
0
  Assert(subkey->sk_attno == header->sk_attno);
1588
0
  Assert(subkey->sk_strategy == header->sk_strategy);
1589
1590
  /* Loop over columns of the row condition */
1591
0
  for (;;)
1592
0
  {
1593
0
    Datum   datum;
1594
0
    bool    isNull;
1595
1596
0
    Assert(subkey->sk_flags & SK_ROW_MEMBER);
1597
1598
    /* When a NULL row member is compared, the row never matches */
1599
0
    if (subkey->sk_flags & SK_ISNULL)
1600
0
    {
1601
      /*
1602
       * Unlike the simple-scankey case, this isn't a disallowed case
1603
       * (except when it's the first row element that has the NULL arg).
1604
       * But it can never match.  If all the earlier row comparison
1605
       * columns are required for the scan direction, we can stop the
1606
       * scan, because there can't be another tuple that will succeed.
1607
       */
1608
0
      Assert(subkey != (ScanKey) DatumGetPointer(header->sk_argument));
1609
0
      subkey--;
1610
0
      if (forcenonrequired)
1611
0
      {
1612
        /* treating scan's keys as non-required */
1613
0
      }
1614
0
      else if ((subkey->sk_flags & SK_BT_REQFWD) &&
1615
0
           ScanDirectionIsForward(dir))
1616
0
        *continuescan = false;
1617
0
      else if ((subkey->sk_flags & SK_BT_REQBKWD) &&
1618
0
           ScanDirectionIsBackward(dir))
1619
0
        *continuescan = false;
1620
0
      return false;
1621
0
    }
1622
1623
0
    if (subkey->sk_attno > tupnatts)
1624
0
    {
1625
      /*
1626
       * This attribute is truncated (must be high key).  The value for
1627
       * this attribute in the first non-pivot tuple on the page to the
1628
       * right could be any possible value.  Assume that truncated
1629
       * attribute passes the qual.
1630
       */
1631
0
      Assert(BTreeTupleIsPivot(tuple));
1632
0
      return true;
1633
0
    }
1634
1635
0
    datum = index_getattr(tuple,
1636
0
                subkey->sk_attno,
1637
0
                tupdesc,
1638
0
                &isNull);
1639
1640
0
    if (isNull)
1641
0
    {
1642
0
      int     reqflags;
1643
1644
0
      if (forcenonrequired)
1645
0
      {
1646
        /* treating scan's keys as non-required */
1647
0
      }
1648
0
      else if (subkey->sk_flags & SK_BT_NULLS_FIRST)
1649
0
      {
1650
        /*
1651
         * Since NULLs are sorted before non-NULLs, we know we have
1652
         * reached the lower limit of the range of values for this
1653
         * index attr.  On a backward scan, we can stop if this qual
1654
         * is one of the "must match" subset.  However, on a forwards
1655
         * scan, we must keep going, because we may have initially
1656
         * positioned to the start of the index.
1657
         *
1658
         * All required NULLS FIRST > row members can use NULL tuple
1659
         * values to end backwards scans, just like with other values.
1660
         * A qual "WHERE (a, b, c) > (9, 42, 'foo')" can terminate a
1661
         * backwards scan upon reaching the index's rightmost "a = 9"
1662
         * tuple whose "b" column contains a NULL (if not sooner).
1663
         * Since "b" is NULLS FIRST, we can treat its NULLs as "<" 42.
1664
         */
1665
0
        reqflags = SK_BT_REQBKWD;
1666
1667
        /*
1668
         * When a most significant required NULLS FIRST < row compare
1669
         * member sees NULL tuple values during a backwards scan, it
1670
         * signals the end of matches for the whole row compare/scan.
1671
         * A qual "WHERE (a, b, c) < (9, 42, 'foo')" will terminate a
1672
         * backwards scan upon reaching the rightmost tuple whose "a"
1673
         * column has a NULL.  The "a" NULL value is "<" 9, and yet
1674
         * our < row compare will still end the scan.  (This isn't
1675
         * safe with later/lower-order row members.  Notice that it
1676
         * can only happen with an "a" NULL some time after the scan
1677
         * completely stops needing to use its "b" and "c" members.)
1678
         */
1679
0
        if (subkey == (ScanKey) DatumGetPointer(header->sk_argument))
1680
0
          reqflags |= SK_BT_REQFWD; /* safe, first row member */
1681
1682
0
        if ((subkey->sk_flags & reqflags) &&
1683
0
          ScanDirectionIsBackward(dir))
1684
0
          *continuescan = false;
1685
0
      }
1686
0
      else
1687
0
      {
1688
        /*
1689
         * Since NULLs are sorted after non-NULLs, we know we have
1690
         * reached the upper limit of the range of values for this
1691
         * index attr.  On a forward scan, we can stop if this qual is
1692
         * one of the "must match" subset.  However, on a backward
1693
         * scan, we must keep going, because we may have initially
1694
         * positioned to the end of the index.
1695
         *
1696
         * All required NULLS LAST < row members can use NULL tuple
1697
         * values to end forwards scans, just like with other values.
1698
         * A qual "WHERE (a, b, c) < (9, 42, 'foo')" can terminate a
1699
         * forwards scan upon reaching the index's leftmost "a = 9"
1700
         * tuple whose "b" column contains a NULL (if not sooner).
1701
         * Since "b" is NULLS LAST, we can treat its NULLs as ">" 42.
1702
         */
1703
0
        reqflags = SK_BT_REQFWD;
1704
1705
        /*
1706
         * When a most significant required NULLS LAST > row compare
1707
         * member sees NULL tuple values during a forwards scan, it
1708
         * signals the end of matches for the whole row compare/scan.
1709
         * A qual "WHERE (a, b, c) > (9, 42, 'foo')" will terminate a
1710
         * forwards scan upon reaching the leftmost tuple whose "a"
1711
         * column has a NULL.  The "a" NULL value is ">" 9, and yet
1712
         * our > row compare will end the scan.  (This isn't safe with
1713
         * later/lower-order row members.  Notice that it can only
1714
         * happen with an "a" NULL some time after the scan completely
1715
         * stops needing to use its "b" and "c" members.)
1716
         */
1717
0
        if (subkey == (ScanKey) DatumGetPointer(header->sk_argument))
1718
0
          reqflags |= SK_BT_REQBKWD; /* safe, first row member */
1719
1720
0
        if ((subkey->sk_flags & reqflags) &&
1721
0
          ScanDirectionIsForward(dir))
1722
0
          *continuescan = false;
1723
0
      }
1724
1725
      /*
1726
       * In any case, this indextuple doesn't match the qual.
1727
       */
1728
0
      return false;
1729
0
    }
1730
1731
    /* Perform the test --- three-way comparison not bool operator */
1732
0
    cmpresult = DatumGetInt32(FunctionCall2Coll(&subkey->sk_func,
1733
0
                          subkey->sk_collation,
1734
0
                          datum,
1735
0
                          subkey->sk_argument));
1736
1737
0
    if (subkey->sk_flags & SK_BT_DESC)
1738
0
      INVERT_COMPARE_RESULT(cmpresult);
1739
1740
    /* Done comparing if unequal, else advance to next column */
1741
0
    if (cmpresult != 0)
1742
0
      break;
1743
1744
0
    if (subkey->sk_flags & SK_ROW_END)
1745
0
      break;
1746
0
    subkey++;
1747
0
  }
1748
1749
  /* Final subkey/column determines if row compare is satisfied */
1750
0
  result = _bt_rowcompare_cmpresult(subkey, cmpresult);
1751
1752
0
  if (!result && !forcenonrequired)
1753
0
  {
1754
    /*
1755
     * Tuple fails this qual.  If it's a required qual for the current
1756
     * scan direction, then we can conclude no further tuples will pass,
1757
     * either.  Note we have to look at the deciding column, not
1758
     * necessarily the first or last column of the row condition.
1759
     */
1760
0
    if ((subkey->sk_flags & SK_BT_REQFWD) &&
1761
0
      ScanDirectionIsForward(dir))
1762
0
      *continuescan = false;
1763
0
    else if ((subkey->sk_flags & SK_BT_REQBKWD) &&
1764
0
         ScanDirectionIsBackward(dir))
1765
0
      *continuescan = false;
1766
0
  }
1767
1768
0
  return result;
1769
0
}
1770
1771
/*
1772
 * Call here when a row compare member returns a non-zero result, or with the
1773
 * result for the final ROW_END row compare member (no matter the cmpresult).
1774
 *
1775
 * cmpresult indicates the overall result of the row comparison (must already
1776
 * be commuted for DESC subkeys), and subkey is the deciding row member.
1777
 */
1778
static bool
1779
_bt_rowcompare_cmpresult(ScanKey subkey, int cmpresult)
1780
0
{
1781
0
  bool    satisfied;
1782
1783
0
  Assert(subkey->sk_flags & SK_ROW_MEMBER);
1784
1785
0
  switch (subkey->sk_strategy)
1786
0
  {
1787
0
    case BTLessStrategyNumber:
1788
0
      satisfied = (cmpresult < 0);
1789
0
      break;
1790
0
    case BTLessEqualStrategyNumber:
1791
0
      satisfied = (cmpresult <= 0);
1792
0
      break;
1793
0
    case BTGreaterEqualStrategyNumber:
1794
0
      satisfied = (cmpresult >= 0);
1795
0
      break;
1796
0
    case BTGreaterStrategyNumber:
1797
0
      satisfied = (cmpresult > 0);
1798
0
      break;
1799
0
    default:
1800
      /* EQ and NE cases aren't allowed here */
1801
0
      elog(ERROR, "unexpected strategy number %d", subkey->sk_strategy);
1802
0
      satisfied = false;  /* keep compiler quiet */
1803
0
      break;
1804
0
  }
1805
1806
0
  return satisfied;
1807
0
}
1808
1809
/*
1810
 * _bt_tuple_before_array_skeys() -- too early to advance required arrays?
1811
 *
1812
 * We always compare the tuple using the current array keys (which we assume
1813
 * are already set in so->keyData[]).  readpagetup indicates if tuple is the
1814
 * scan's current _bt_readpage-wise tuple.
1815
 *
1816
 * readpagetup callers must only call here when _bt_check_compare already set
1817
 * continuescan=false.  We help these callers deal with _bt_check_compare's
1818
 * inability to distinguish between the < and > cases (it uses equality
1819
 * operator scan keys, whereas we use 3-way ORDER procs).  These callers pass
1820
 * a _bt_check_compare-set sktrig value that indicates which scan key
1821
 * triggered the call (!readpagetup callers just pass us sktrig=0 instead).
1822
 * This information allows us to avoid wastefully checking earlier scan keys
1823
 * that were already deemed to have been satisfied inside _bt_check_compare.
1824
 *
1825
 * Returns false when caller's tuple is >= the current required equality scan
1826
 * keys (or <=, in the case of backwards scans).  This happens to readpagetup
1827
 * callers when the scan has reached the point of needing its array keys
1828
 * advanced; caller will need to advance required and non-required arrays at
1829
 * scan key offsets >= sktrig, plus scan keys < sktrig iff sktrig rolls over.
1830
 * (When we return false to readpagetup callers, tuple can only be == current
1831
 * required equality scan keys when caller's sktrig indicates that the arrays
1832
 * need to be advanced due to an unsatisfied required inequality key trigger.)
1833
 *
1834
 * Returns true when caller passes a tuple that is < the current set of
1835
 * equality keys for the most significant non-equal required scan key/column
1836
 * (or > the keys, during backwards scans).  This happens to readpagetup
1837
 * callers when tuple is still before the start of matches for the scan's
1838
 * required equality strategy scan keys.  (sktrig can't have indicated that an
1839
 * inequality strategy scan key wasn't satisfied in _bt_check_compare when we
1840
 * return true.  In fact, we automatically return false when passed such an
1841
 * inequality sktrig by readpagetup callers -- _bt_check_compare's initial
1842
 * continuescan=false doesn't really need to be confirmed here by us.)
1843
 *
1844
 * !readpagetup callers optionally pass us *scanBehind, which tracks whether
1845
 * any missing truncated attributes might have affected array advancement
1846
 * (compared to what would happen if it was shown the first non-pivot tuple on
1847
 * the page to the right of caller's finaltup/high key tuple instead).  It's
1848
 * only possible that we'll set *scanBehind to true when caller passes us a
1849
 * pivot tuple (with truncated -inf attributes) that we return false for.
1850
 */
1851
static bool
1852
_bt_tuple_before_array_skeys(IndexScanDesc scan, ScanDirection dir,
1853
               IndexTuple tuple, TupleDesc tupdesc, int tupnatts,
1854
               bool readpagetup, int sktrig, bool *scanBehind)
1855
0
{
1856
0
  BTScanOpaque so = (BTScanOpaque) scan->opaque;
1857
1858
0
  Assert(so->numArrayKeys);
1859
0
  Assert(so->numberOfKeys);
1860
0
  Assert(sktrig == 0 || readpagetup);
1861
0
  Assert(!readpagetup || scanBehind == NULL);
1862
1863
0
  if (scanBehind)
1864
0
    *scanBehind = false;
1865
1866
0
  for (int ikey = sktrig; ikey < so->numberOfKeys; ikey++)
1867
0
  {
1868
0
    ScanKey   cur = so->keyData + ikey;
1869
0
    Datum   tupdatum;
1870
0
    bool    tupnull;
1871
0
    int32   result;
1872
1873
    /* readpagetup calls require one ORDER proc comparison (at most) */
1874
0
    Assert(!readpagetup || ikey == sktrig);
1875
1876
    /*
1877
     * Once we reach a non-required scan key, we're completely done.
1878
     *
1879
     * Note: we deliberately don't consider the scan direction here.
1880
     * _bt_advance_array_keys caller requires that we track *scanBehind
1881
     * without concern for scan direction.
1882
     */
1883
0
    if ((cur->sk_flags & (SK_BT_REQFWD | SK_BT_REQBKWD)) == 0)
1884
0
    {
1885
0
      Assert(!readpagetup);
1886
0
      Assert(ikey > sktrig || ikey == 0);
1887
0
      return false;
1888
0
    }
1889
1890
0
    if (cur->sk_attno > tupnatts)
1891
0
    {
1892
0
      Assert(!readpagetup);
1893
1894
      /*
1895
       * When we reach a high key's truncated attribute, assume that the
1896
       * tuple attribute's value is >= the scan's equality constraint
1897
       * scan keys (but set *scanBehind to let interested callers know
1898
       * that a truncated attribute might have affected our answer).
1899
       */
1900
0
      if (scanBehind)
1901
0
        *scanBehind = true;
1902
1903
0
      return false;
1904
0
    }
1905
1906
    /*
1907
     * Deal with inequality strategy scan keys that _bt_check_compare set
1908
     * continuescan=false for
1909
     */
1910
0
    if (cur->sk_strategy != BTEqualStrategyNumber)
1911
0
    {
1912
      /*
1913
       * When _bt_check_compare indicated that a required inequality
1914
       * scan key wasn't satisfied, there's no need to verify anything;
1915
       * caller always calls _bt_advance_array_keys with this sktrig.
1916
       */
1917
0
      if (readpagetup)
1918
0
        return false;
1919
1920
      /*
1921
       * Otherwise we can't give up, since we must check all required
1922
       * scan keys (required in either direction) in order to correctly
1923
       * track *scanBehind for caller
1924
       */
1925
0
      continue;
1926
0
    }
1927
1928
0
    tupdatum = index_getattr(tuple, cur->sk_attno, tupdesc, &tupnull);
1929
1930
0
    if (likely(!(cur->sk_flags & (SK_BT_MINVAL | SK_BT_MAXVAL))))
1931
0
    {
1932
      /* Scankey has a valid/comparable sk_argument value */
1933
0
      result = _bt_compare_array_skey(&so->orderProcs[ikey],
1934
0
                      tupdatum, tupnull,
1935
0
                      cur->sk_argument, cur);
1936
1937
0
      if (result == 0)
1938
0
      {
1939
        /*
1940
         * Interpret result in a way that takes NEXT/PRIOR into
1941
         * account
1942
         */
1943
0
        if (cur->sk_flags & SK_BT_NEXT)
1944
0
          result = -1;
1945
0
        else if (cur->sk_flags & SK_BT_PRIOR)
1946
0
          result = 1;
1947
1948
0
        Assert(result == 0 || (cur->sk_flags & SK_BT_SKIP));
1949
0
      }
1950
0
    }
1951
0
    else
1952
0
    {
1953
0
      BTArrayKeyInfo *array = NULL;
1954
1955
      /*
1956
       * Current array element/array = scan key value is a sentinel
1957
       * value that represents the lowest (or highest) possible value
1958
       * that's still within the range of the array.
1959
       *
1960
       * Like _bt_first, we only see MINVAL keys during forwards scans
1961
       * (and similarly only see MAXVAL keys during backwards scans).
1962
       * Even if the scan's direction changes, we'll stop at some higher
1963
       * order key before we can ever reach any MAXVAL (or MINVAL) keys.
1964
       * (However, unlike _bt_first we _can_ get to keys marked either
1965
       * NEXT or PRIOR, regardless of the scan's current direction.)
1966
       */
1967
0
      Assert(ScanDirectionIsForward(dir) ?
1968
0
           !(cur->sk_flags & SK_BT_MAXVAL) :
1969
0
           !(cur->sk_flags & SK_BT_MINVAL));
1970
1971
      /*
1972
       * There are no valid sk_argument values in MINVAL/MAXVAL keys.
1973
       * Check if tupdatum is within the range of skip array instead.
1974
       */
1975
0
      for (int arrayidx = 0; arrayidx < so->numArrayKeys; arrayidx++)
1976
0
      {
1977
0
        array = &so->arrayKeys[arrayidx];
1978
0
        if (array->scan_key == ikey)
1979
0
          break;
1980
0
      }
1981
1982
0
      _bt_binsrch_skiparray_skey(false, dir, tupdatum, tupnull,
1983
0
                     array, cur, &result);
1984
1985
0
      if (result == 0)
1986
0
      {
1987
        /*
1988
         * tupdatum satisfies both low_compare and high_compare, so
1989
         * it's time to advance the array keys.
1990
         *
1991
         * Note: It's possible that the skip array will "advance" from
1992
         * its MINVAL (or MAXVAL) representation to an alternative,
1993
         * logically equivalent representation of the same value: a
1994
         * representation where the = key gets a valid datum in its
1995
         * sk_argument.  This is only possible when low_compare uses
1996
         * the >= strategy (or high_compare uses the <= strategy).
1997
         */
1998
0
        return false;
1999
0
      }
2000
0
    }
2001
2002
    /*
2003
     * Does this comparison indicate that caller must _not_ advance the
2004
     * scan's arrays just yet?
2005
     */
2006
0
    if ((ScanDirectionIsForward(dir) && result < 0) ||
2007
0
      (ScanDirectionIsBackward(dir) && result > 0))
2008
0
      return true;
2009
2010
    /*
2011
     * Does this comparison indicate that caller should now advance the
2012
     * scan's arrays?  (Must be if we get here during a readpagetup call.)
2013
     */
2014
0
    if (readpagetup || result != 0)
2015
0
    {
2016
0
      Assert(result != 0);
2017
0
      return false;
2018
0
    }
2019
2020
    /*
2021
     * Inconclusive -- need to check later scan keys, too.
2022
     *
2023
     * This must be a finaltup precheck, or a call made from an assertion.
2024
     */
2025
0
    Assert(result == 0);
2026
0
  }
2027
2028
0
  Assert(!readpagetup);
2029
2030
0
  return false;
2031
0
}
2032
2033
/*
2034
 * Determine if a scan with array keys should skip over uninteresting tuples.
2035
 *
2036
 * This is a subroutine for _bt_checkkeys, called when _bt_readpage's linear
2037
 * search process has scanned an excessive number of tuples whose key space is
2038
 * "between arrays".  (The linear search process is started after _bt_readpage
2039
 * finishes reading an initial group of matching tuples.  It locates the start
2040
 * of the first group of tuples matching the next set of required array keys.)
2041
 *
2042
 * When look ahead is successful, we set pstate.skip which
2043
 * instructs _bt_readpage to skip ahead to that tuple next (could be past the
2044
 * end of the scan's leaf page).  Pages where the optimization is effective
2045
 * will generally still need to skip several times.  Each call here performs
2046
 * only a single "look ahead" comparison of a later tuple, whose distance from
2047
 * the current tuple is determined by heuristics.
2048
 */
2049
static void
2050
_bt_checkkeys_look_ahead(IndexScanDesc scan, BTReadPageState *pstate,
2051
             int tupnatts, TupleDesc tupdesc)
2052
0
{
2053
0
  ScanDirection dir = pstate->dir;
2054
0
  OffsetNumber aheadoffnum;
2055
0
  IndexTuple  ahead;
2056
2057
0
  Assert(!pstate->forcenonrequired);
2058
2059
  /* Avoid looking ahead when comparing the page high key */
2060
0
  if (pstate->offnum < pstate->minoff)
2061
0
    return;
2062
2063
  /*
2064
   * Don't look ahead when there aren't enough tuples remaining on the page
2065
   * (in the current scan direction) for it to be worth our while
2066
   */
2067
0
  if (ScanDirectionIsForward(dir) &&
2068
0
    pstate->offnum >= pstate->maxoff - LOOK_AHEAD_DEFAULT_DISTANCE)
2069
0
    return;
2070
0
  else if (ScanDirectionIsBackward(dir) &&
2071
0
       pstate->offnum <= pstate->minoff + LOOK_AHEAD_DEFAULT_DISTANCE)
2072
0
    return;
2073
2074
  /*
2075
   * The look ahead distance starts small, and ramps up as each call here
2076
   * allows _bt_readpage to skip over more tuples
2077
   */
2078
0
  if (!pstate->targetdistance)
2079
0
    pstate->targetdistance = LOOK_AHEAD_DEFAULT_DISTANCE;
2080
0
  else if (pstate->targetdistance < MaxIndexTuplesPerPage / 2)
2081
0
    pstate->targetdistance *= 2;
2082
2083
  /* Don't read past the end (or before the start) of the page, though */
2084
0
  if (ScanDirectionIsForward(dir))
2085
0
    aheadoffnum = Min((int) pstate->maxoff,
2086
0
              (int) pstate->offnum + pstate->targetdistance);
2087
0
  else
2088
0
    aheadoffnum = Max((int) pstate->minoff,
2089
0
              (int) pstate->offnum - pstate->targetdistance);
2090
2091
0
  ahead = (IndexTuple) PageGetItem(pstate->page,
2092
0
                   PageGetItemId(pstate->page, aheadoffnum));
2093
0
  if (_bt_tuple_before_array_skeys(scan, dir, ahead, tupdesc, tupnatts,
2094
0
                   false, 0, NULL))
2095
0
  {
2096
    /*
2097
     * Success -- instruct _bt_readpage to skip ahead to very next tuple
2098
     * after the one we determined was still before the current array keys
2099
     */
2100
0
    if (ScanDirectionIsForward(dir))
2101
0
      pstate->skip = aheadoffnum + 1;
2102
0
    else
2103
0
      pstate->skip = aheadoffnum - 1;
2104
0
  }
2105
0
  else
2106
0
  {
2107
    /*
2108
     * Failure -- "ahead" tuple is too far ahead (we were too aggressive).
2109
     *
2110
     * Reset the number of rechecks, and aggressively reduce the target
2111
     * distance (we're much more aggressive here than we were when the
2112
     * distance was initially ramped up).
2113
     */
2114
0
    pstate->rechecks = 0;
2115
0
    pstate->targetdistance = Max(pstate->targetdistance / 8, 1);
2116
0
  }
2117
0
}
2118
2119
/*
2120
 * _bt_advance_array_keys() -- Advance array elements using a tuple
2121
 *
2122
 * The scan always gets a new qual as a consequence of calling here (except
2123
 * when we determine that the top-level scan has run out of matching tuples).
2124
 * All later _bt_check_compare calls also use the same new qual that was first
2125
 * used here (at least until the next call here advances the keys once again).
2126
 * It's convenient to structure _bt_check_compare rechecks of caller's tuple
2127
 * (using the new qual) as one the steps of advancing the scan's array keys,
2128
 * so this function works as a wrapper around _bt_check_compare.
2129
 *
2130
 * Like _bt_check_compare, we'll set pstate.continuescan on behalf of the
2131
 * caller, and return a boolean indicating if caller's tuple satisfies the
2132
 * scan's new qual.  But unlike _bt_check_compare, we set so->needPrimScan
2133
 * when we set continuescan=false, indicating if a new primitive index scan
2134
 * has been scheduled (otherwise, the top-level scan has run out of tuples in
2135
 * the current scan direction).
2136
 *
2137
 * Caller must use _bt_tuple_before_array_skeys to determine if the current
2138
 * place in the scan is >= the current array keys _before_ calling here.
2139
 * We're responsible for ensuring that caller's tuple is <= the newly advanced
2140
 * required array keys once we return.  We try to find an exact match, but
2141
 * failing that we'll advance the array keys to whatever set of array elements
2142
 * comes next in the key space for the current scan direction.  Required array
2143
 * keys "ratchet forwards" (or backwards).  They can only advance as the scan
2144
 * itself advances through the index/key space.
2145
 *
2146
 * (The rules are the same for backwards scans, except that the operators are
2147
 * flipped: just replace the precondition's >= operator with a <=, and the
2148
 * postcondition's <= operator with a >=.  In other words, just swap the
2149
 * precondition with the postcondition.)
2150
 *
2151
 * We also deal with "advancing" non-required arrays here (or arrays that are
2152
 * treated as non-required for the duration of a _bt_readpage call).  Callers
2153
 * whose sktrig scan key is non-required specify sktrig_required=false.  These
2154
 * calls are the only exception to the general rule about always advancing the
2155
 * required array keys (the scan may not even have a required array).  These
2156
 * callers should just pass a NULL pstate (since there is never any question
2157
 * of stopping the scan).  No call to _bt_tuple_before_array_skeys is required
2158
 * ahead of these calls (it's already clear that any required scan keys must
2159
 * be satisfied by caller's tuple).
2160
 *
2161
 * Note that we deal with non-array required equality strategy scan keys as
2162
 * degenerate single element arrays here.  Obviously, they can never really
2163
 * advance in the way that real arrays can, but they must still affect how we
2164
 * advance real array scan keys (exactly like true array equality scan keys).
2165
 * We have to keep around a 3-way ORDER proc for these (using the "=" operator
2166
 * won't do), since in general whether the tuple is < or > _any_ unsatisfied
2167
 * required equality key influences how the scan's real arrays must advance.
2168
 *
2169
 * Note also that we may sometimes need to advance the array keys when the
2170
 * existing required array keys (and other required equality keys) are already
2171
 * an exact match for every corresponding value from caller's tuple.  We must
2172
 * do this for inequalities that _bt_check_compare set continuescan=false for.
2173
 * They'll advance the array keys here, just like any other scan key that
2174
 * _bt_check_compare stops on.  (This can even happen _after_ we advance the
2175
 * array keys, in which case we'll advance the array keys a second time.  That
2176
 * way _bt_checkkeys caller always has its required arrays advance to the
2177
 * maximum possible extent that its tuple will allow.)
2178
 */
2179
static bool
2180
_bt_advance_array_keys(IndexScanDesc scan, BTReadPageState *pstate,
2181
             IndexTuple tuple, int tupnatts, TupleDesc tupdesc,
2182
             int sktrig, bool sktrig_required)
2183
0
{
2184
0
  BTScanOpaque so = (BTScanOpaque) scan->opaque;
2185
0
  Relation  rel = scan->indexRelation;
2186
0
  ScanDirection dir = pstate ? pstate->dir : ForwardScanDirection;
2187
0
  int     arrayidx = 0;
2188
0
  bool    beyond_end_advance = false,
2189
0
        skip_array_advanced = false,
2190
0
        has_required_opposite_direction_only = false,
2191
0
        all_required_satisfied = true,
2192
0
        all_satisfied = true;
2193
2194
0
  Assert(!so->needPrimScan && !so->scanBehind && !so->oppositeDirCheck);
2195
0
  Assert(_bt_verify_keys_with_arraykeys(scan));
2196
2197
0
  if (sktrig_required)
2198
0
  {
2199
    /*
2200
     * Precondition array state assertion
2201
     */
2202
0
    Assert(!_bt_tuple_before_array_skeys(scan, dir, tuple, tupdesc,
2203
0
                       tupnatts, false, 0, NULL));
2204
2205
    /*
2206
     * Once we return we'll have a new set of required array keys, so
2207
     * reset state used by "look ahead" optimization
2208
     */
2209
0
    pstate->rechecks = 0;
2210
0
    pstate->targetdistance = 0;
2211
0
  }
2212
0
  else if (sktrig < so->numberOfKeys - 1 &&
2213
0
       !(so->keyData[so->numberOfKeys - 1].sk_flags & SK_SEARCHARRAY))
2214
0
  {
2215
0
    int     least_sign_ikey = so->numberOfKeys - 1;
2216
0
    bool    continuescan;
2217
2218
    /*
2219
     * Optimization: perform a precheck of the least significant key
2220
     * during !sktrig_required calls when it isn't already our sktrig
2221
     * (provided the precheck key is not itself an array).
2222
     *
2223
     * When the precheck works out we'll avoid an expensive binary search
2224
     * of sktrig's array (plus any other arrays before least_sign_ikey).
2225
     */
2226
0
    Assert(so->keyData[sktrig].sk_flags & SK_SEARCHARRAY);
2227
0
    if (!_bt_check_compare(scan, dir, tuple, tupnatts, tupdesc, false,
2228
0
                 false, &continuescan,
2229
0
                 &least_sign_ikey))
2230
0
      return false;
2231
0
  }
2232
2233
0
  for (int ikey = 0; ikey < so->numberOfKeys; ikey++)
2234
0
  {
2235
0
    ScanKey   cur = so->keyData + ikey;
2236
0
    BTArrayKeyInfo *array = NULL;
2237
0
    Datum   tupdatum;
2238
0
    bool    required = false,
2239
0
          tupnull;
2240
0
    int32   result;
2241
0
    int     set_elem = 0;
2242
2243
0
    if (cur->sk_flags & SK_SEARCHARRAY)
2244
0
    {
2245
      /* Manage array state */
2246
0
      array = &so->arrayKeys[arrayidx++];
2247
2248
0
      Assert(array->scan_key == ikey);
2249
0
      Assert(cur->sk_strategy == BTEqualStrategyNumber);
2250
0
    }
2251
0
    else if (cur->sk_strategy != BTEqualStrategyNumber)
2252
0
    {
2253
      /*
2254
       * Are any inequalities required in the opposite direction only
2255
       * present here?
2256
       */
2257
0
      if (((ScanDirectionIsForward(dir) &&
2258
0
          (cur->sk_flags & (SK_BT_REQBKWD))) ||
2259
0
         (ScanDirectionIsBackward(dir) &&
2260
0
          (cur->sk_flags & (SK_BT_REQFWD)))))
2261
0
        has_required_opposite_direction_only = true;
2262
0
    }
2263
2264
    /* Optimization: skip over known-satisfied scan keys */
2265
0
    if (ikey < sktrig)
2266
0
      continue;
2267
2268
0
    if (cur->sk_flags & (SK_BT_REQFWD | SK_BT_REQBKWD))
2269
0
    {
2270
0
      required = true;
2271
2272
0
      if (cur->sk_attno > tupnatts)
2273
0
      {
2274
        /* Set this just like _bt_tuple_before_array_skeys */
2275
0
        Assert(sktrig < ikey);
2276
0
        so->scanBehind = true;
2277
0
      }
2278
0
    }
2279
2280
    /*
2281
     * Handle a required non-array scan key that the initial call to
2282
     * _bt_check_compare indicated triggered array advancement, if any.
2283
     *
2284
     * The non-array scan key's strategy will be <, <=, or = during a
2285
     * forwards scan (or any one of =, >=, or > during a backwards scan).
2286
     * It follows that the corresponding tuple attribute's value must now
2287
     * be either > or >= the scan key value (for backwards scans it must
2288
     * be either < or <= that value).
2289
     *
2290
     * If this is a required equality strategy scan key, this is just an
2291
     * optimization; _bt_tuple_before_array_skeys already confirmed that
2292
     * this scan key places us ahead of caller's tuple.  There's no need
2293
     * to repeat that work now.  (The same underlying principle also gets
2294
     * applied by the cur_elem_trig optimization used to speed up searches
2295
     * for the next array element.)
2296
     *
2297
     * If this is a required inequality strategy scan key, we _must_ rely
2298
     * on _bt_check_compare like this; we aren't capable of directly
2299
     * evaluating required inequality strategy scan keys here, on our own.
2300
     */
2301
0
    if (ikey == sktrig && !array)
2302
0
    {
2303
0
      Assert(sktrig_required && required && all_required_satisfied);
2304
2305
      /* Use "beyond end" advancement.  See below for an explanation. */
2306
0
      beyond_end_advance = true;
2307
0
      all_satisfied = all_required_satisfied = false;
2308
2309
0
      continue;
2310
0
    }
2311
2312
    /*
2313
     * Nothing more for us to do with an inequality strategy scan key that
2314
     * wasn't the one that _bt_check_compare stopped on, though.
2315
     *
2316
     * Note: if our later call to _bt_check_compare (to recheck caller's
2317
     * tuple) sets continuescan=false due to finding this same inequality
2318
     * unsatisfied (possible when it's required in the scan direction),
2319
     * we'll deal with it via a recursive "second pass" call.
2320
     */
2321
0
    else if (cur->sk_strategy != BTEqualStrategyNumber)
2322
0
      continue;
2323
2324
    /*
2325
     * Nothing for us to do with an equality strategy scan key that isn't
2326
     * marked required, either -- unless it's a non-required array
2327
     */
2328
0
    else if (!required && !array)
2329
0
      continue;
2330
2331
    /*
2332
     * Here we perform steps for all array scan keys after a required
2333
     * array scan key whose binary search triggered "beyond end of array
2334
     * element" array advancement due to encountering a tuple attribute
2335
     * value > the closest matching array key (or < for backwards scans).
2336
     */
2337
0
    if (beyond_end_advance)
2338
0
    {
2339
0
      if (array)
2340
0
        _bt_array_set_low_or_high(rel, cur, array,
2341
0
                      ScanDirectionIsBackward(dir));
2342
2343
0
      continue;
2344
0
    }
2345
2346
    /*
2347
     * Here we perform steps for all array scan keys after a required
2348
     * array scan key whose tuple attribute was < the closest matching
2349
     * array key when we dealt with it (or > for backwards scans).
2350
     *
2351
     * This earlier required array key already puts us ahead of caller's
2352
     * tuple in the key space (for the current scan direction).  We must
2353
     * make sure that subsequent lower-order array keys do not put us too
2354
     * far ahead (ahead of tuples that have yet to be seen by our caller).
2355
     * For example, when a tuple "(a, b) = (42, 5)" advances the array
2356
     * keys on "a" from 40 to 45, we must also set "b" to whatever the
2357
     * first array element for "b" is.  It would be wrong to allow "b" to
2358
     * be set based on the tuple value.
2359
     *
2360
     * Perform the same steps with truncated high key attributes.  You can
2361
     * think of this as a "binary search" for the element closest to the
2362
     * value -inf.  Again, the arrays must never get ahead of the scan.
2363
     */
2364
0
    if (!all_required_satisfied || cur->sk_attno > tupnatts)
2365
0
    {
2366
0
      if (array)
2367
0
        _bt_array_set_low_or_high(rel, cur, array,
2368
0
                      ScanDirectionIsForward(dir));
2369
2370
0
      continue;
2371
0
    }
2372
2373
    /*
2374
     * Search in scankey's array for the corresponding tuple attribute
2375
     * value from caller's tuple
2376
     */
2377
0
    tupdatum = index_getattr(tuple, cur->sk_attno, tupdesc, &tupnull);
2378
2379
0
    if (array)
2380
0
    {
2381
0
      bool    cur_elem_trig = (sktrig_required && ikey == sktrig);
2382
2383
      /*
2384
       * "Binary search" by checking if tupdatum/tupnull are within the
2385
       * range of the skip array
2386
       */
2387
0
      if (array->num_elems == -1)
2388
0
        _bt_binsrch_skiparray_skey(cur_elem_trig, dir,
2389
0
                       tupdatum, tupnull, array, cur,
2390
0
                       &result);
2391
2392
      /*
2393
       * Binary search for the closest match from the SAOP array
2394
       */
2395
0
      else
2396
0
        set_elem = _bt_binsrch_array_skey(&so->orderProcs[ikey],
2397
0
                          cur_elem_trig, dir,
2398
0
                          tupdatum, tupnull, array, cur,
2399
0
                          &result);
2400
0
    }
2401
0
    else
2402
0
    {
2403
0
      Assert(required);
2404
2405
      /*
2406
       * This is a required non-array equality strategy scan key, which
2407
       * we'll treat as a degenerate single element array.
2408
       *
2409
       * This scan key's imaginary "array" can't really advance, but it
2410
       * can still roll over like any other array.  (Actually, this is
2411
       * no different to real single value arrays, which never advance
2412
       * without rolling over -- they can never truly advance, either.)
2413
       */
2414
0
      result = _bt_compare_array_skey(&so->orderProcs[ikey],
2415
0
                      tupdatum, tupnull,
2416
0
                      cur->sk_argument, cur);
2417
0
    }
2418
2419
    /*
2420
     * Consider "beyond end of array element" array advancement.
2421
     *
2422
     * When the tuple attribute value is > the closest matching array key
2423
     * (or < in the backwards scan case), we need to ratchet this array
2424
     * forward (backward) by one increment, so that caller's tuple ends up
2425
     * being < final array value instead (or > final array value instead).
2426
     * This process has to work for all of the arrays, not just this one:
2427
     * it must "carry" to higher-order arrays when the set_elem that we
2428
     * just found happens to be the final one for the scan's direction.
2429
     * Incrementing (decrementing) set_elem itself isn't good enough.
2430
     *
2431
     * Our approach is to provisionally use set_elem as if it was an exact
2432
     * match now, then set each later/less significant array to whatever
2433
     * its final element is.  Once outside the loop we'll then "increment
2434
     * this array's set_elem" by calling _bt_advance_array_keys_increment.
2435
     * That way the process rolls over to higher order arrays as needed.
2436
     *
2437
     * Under this scheme any required arrays only ever ratchet forwards
2438
     * (or backwards), and always do so to the maximum possible extent
2439
     * that we can know will be safe without seeing the scan's next tuple.
2440
     * We don't need any special handling for required scan keys that lack
2441
     * a real array to advance, nor for redundant scan keys that couldn't
2442
     * be eliminated by _bt_preprocess_keys.  It won't matter if some of
2443
     * our "true" array scan keys (or even all of them) are non-required.
2444
     */
2445
0
    if (sktrig_required && required &&
2446
0
      ((ScanDirectionIsForward(dir) && result > 0) ||
2447
0
       (ScanDirectionIsBackward(dir) && result < 0)))
2448
0
      beyond_end_advance = true;
2449
2450
0
    Assert(all_required_satisfied && all_satisfied);
2451
0
    if (result != 0)
2452
0
    {
2453
      /*
2454
       * Track whether caller's tuple satisfies our new post-advancement
2455
       * qual, for required scan keys, as well as for the entire set of
2456
       * interesting scan keys (all required scan keys plus non-required
2457
       * array scan keys are considered interesting.)
2458
       */
2459
0
      all_satisfied = false;
2460
0
      if (sktrig_required && required)
2461
0
        all_required_satisfied = false;
2462
0
      else
2463
0
      {
2464
        /*
2465
         * There's no need to advance the arrays using the best
2466
         * available match for a non-required array.  Give up now.
2467
         * (Though note that sktrig_required calls still have to do
2468
         * all the usual post-advancement steps, including the recheck
2469
         * call to _bt_check_compare.)
2470
         */
2471
0
        break;
2472
0
      }
2473
0
    }
2474
2475
    /* Advance array keys, even when we don't have an exact match */
2476
0
    if (array)
2477
0
    {
2478
0
      if (array->num_elems == -1)
2479
0
      {
2480
        /* Skip array's new element is tupdatum (or MINVAL/MAXVAL) */
2481
0
        _bt_skiparray_set_element(rel, cur, array, result,
2482
0
                      tupdatum, tupnull);
2483
0
        skip_array_advanced = true;
2484
0
      }
2485
0
      else if (array->cur_elem != set_elem)
2486
0
      {
2487
        /* SAOP array's new element is set_elem datum */
2488
0
        array->cur_elem = set_elem;
2489
0
        cur->sk_argument = array->elem_values[set_elem];
2490
0
      }
2491
0
    }
2492
0
  }
2493
2494
  /*
2495
   * Advance the array keys incrementally whenever "beyond end of array
2496
   * element" array advancement happens, so that advancement will carry to
2497
   * higher-order arrays (might exhaust all the scan's arrays instead, which
2498
   * ends the top-level scan).
2499
   */
2500
0
  if (beyond_end_advance &&
2501
0
    !_bt_advance_array_keys_increment(scan, dir, &skip_array_advanced))
2502
0
    goto end_toplevel_scan;
2503
2504
0
  Assert(_bt_verify_keys_with_arraykeys(scan));
2505
2506
  /*
2507
   * Maintain a page-level count of the number of times the scan's array
2508
   * keys advanced in a way that affected at least one skip array
2509
   */
2510
0
  if (sktrig_required && skip_array_advanced)
2511
0
    pstate->nskipadvances++;
2512
2513
  /*
2514
   * Does tuple now satisfy our new qual?  Recheck with _bt_check_compare.
2515
   *
2516
   * Calls triggered by an unsatisfied required scan key, whose tuple now
2517
   * satisfies all required scan keys, but not all nonrequired array keys,
2518
   * will still require a recheck call to _bt_check_compare.  They'll still
2519
   * need its "second pass" handling of required inequality scan keys.
2520
   * (Might have missed a still-unsatisfied required inequality scan key
2521
   * that caller didn't detect as the sktrig scan key during its initial
2522
   * _bt_check_compare call that used the old/original qual.)
2523
   *
2524
   * Calls triggered by an unsatisfied nonrequired array scan key never need
2525
   * "second pass" handling of required inequalities (nor any other handling
2526
   * of any required scan key).  All that matters is whether caller's tuple
2527
   * satisfies the new qual, so it's safe to just skip the _bt_check_compare
2528
   * recheck when we've already determined that it can only return 'false'.
2529
   *
2530
   * Note: In practice most scan keys are marked required by preprocessing,
2531
   * if necessary by generating a preceding skip array.  We nevertheless
2532
   * often handle array keys marked required as if they were nonrequired.
2533
   * This behavior is requested by our _bt_check_compare caller, though only
2534
   * when it is passed "forcenonrequired=true" by _bt_checkkeys.
2535
   */
2536
0
  if ((sktrig_required && all_required_satisfied) ||
2537
0
    (!sktrig_required && all_satisfied))
2538
0
  {
2539
0
    int     nsktrig = sktrig + 1;
2540
0
    bool    continuescan;
2541
2542
0
    Assert(all_required_satisfied);
2543
2544
    /* Recheck _bt_check_compare on behalf of caller */
2545
0
    if (_bt_check_compare(scan, dir, tuple, tupnatts, tupdesc, false,
2546
0
                !sktrig_required, &continuescan,
2547
0
                &nsktrig) &&
2548
0
      !so->scanBehind)
2549
0
    {
2550
      /* This tuple satisfies the new qual */
2551
0
      Assert(all_satisfied && continuescan);
2552
2553
0
      if (pstate)
2554
0
        pstate->continuescan = true;
2555
2556
0
      return true;
2557
0
    }
2558
2559
    /*
2560
     * Consider "second pass" handling of required inequalities.
2561
     *
2562
     * It's possible that our _bt_check_compare call indicated that the
2563
     * scan should end due to some unsatisfied inequality that wasn't
2564
     * initially recognized as such by us.  Handle this by calling
2565
     * ourselves recursively, this time indicating that the trigger is the
2566
     * inequality that we missed first time around (and using a set of
2567
     * required array/equality keys that are now exact matches for tuple).
2568
     *
2569
     * We make a strong, general guarantee that every _bt_checkkeys call
2570
     * here will advance the array keys to the maximum possible extent
2571
     * that we can know to be safe based on caller's tuple alone.  If we
2572
     * didn't perform this step, then that guarantee wouldn't quite hold.
2573
     */
2574
0
    if (unlikely(!continuescan))
2575
0
    {
2576
0
      bool    satisfied PG_USED_FOR_ASSERTS_ONLY;
2577
2578
0
      Assert(sktrig_required);
2579
0
      Assert(so->keyData[nsktrig].sk_strategy != BTEqualStrategyNumber);
2580
2581
      /*
2582
       * The tuple must use "beyond end" advancement during the
2583
       * recursive call, so we cannot possibly end up back here when
2584
       * recursing.  We'll consume a small, fixed amount of stack space.
2585
       */
2586
0
      Assert(!beyond_end_advance);
2587
2588
      /* Advance the array keys a second time using same tuple */
2589
0
      satisfied = _bt_advance_array_keys(scan, pstate, tuple, tupnatts,
2590
0
                         tupdesc, nsktrig, true);
2591
2592
      /* This tuple doesn't satisfy the inequality */
2593
0
      Assert(!satisfied);
2594
0
      return false;
2595
0
    }
2596
2597
    /*
2598
     * Some non-required scan key (from new qual) still not satisfied.
2599
     *
2600
     * All scan keys required in the current scan direction must still be
2601
     * satisfied, though, so we can trust all_required_satisfied below.
2602
     */
2603
0
  }
2604
2605
  /*
2606
   * When we were called just to deal with "advancing" non-required arrays,
2607
   * this is as far as we can go (cannot stop the scan for these callers)
2608
   */
2609
0
  if (!sktrig_required)
2610
0
  {
2611
    /* Caller's tuple doesn't match any qual */
2612
0
    return false;
2613
0
  }
2614
2615
  /*
2616
   * Postcondition array state assertion (for still-unsatisfied tuples).
2617
   *
2618
   * By here we have established that the scan's required arrays (scan must
2619
   * have at least one required array) advanced, without becoming exhausted.
2620
   *
2621
   * Caller's tuple is now < the newly advanced array keys (or > when this
2622
   * is a backwards scan), except in the case where we only got this far due
2623
   * to an unsatisfied non-required scan key.  Verify that with an assert.
2624
   *
2625
   * Note: we don't just quit at this point when all required scan keys were
2626
   * found to be satisfied because we need to consider edge-cases involving
2627
   * scan keys required in the opposite direction only; those aren't tracked
2628
   * by all_required_satisfied.
2629
   */
2630
0
  Assert(_bt_tuple_before_array_skeys(scan, dir, tuple, tupdesc, tupnatts,
2631
0
                    false, 0, NULL) ==
2632
0
       !all_required_satisfied);
2633
2634
  /*
2635
   * We generally permit primitive index scans to continue onto the next
2636
   * sibling page when the page's finaltup satisfies all required scan keys
2637
   * at the point where we're between pages.
2638
   *
2639
   * If caller's tuple is also the page's finaltup, and we see that required
2640
   * scan keys still aren't satisfied, start a new primitive index scan.
2641
   */
2642
0
  if (!all_required_satisfied && pstate->finaltup == tuple)
2643
0
    goto new_prim_scan;
2644
2645
  /*
2646
   * Proactively check finaltup (don't wait until finaltup is reached by the
2647
   * scan) when it might well turn out to not be satisfied later on.
2648
   *
2649
   * Note: if so->scanBehind hasn't already been set for finaltup by us,
2650
   * it'll be set during this call to _bt_tuple_before_array_skeys.  Either
2651
   * way, it'll be set correctly (for the whole page) after this point.
2652
   */
2653
0
  if (!all_required_satisfied && pstate->finaltup &&
2654
0
    _bt_tuple_before_array_skeys(scan, dir, pstate->finaltup, tupdesc,
2655
0
                   BTreeTupleGetNAtts(pstate->finaltup, rel),
2656
0
                   false, 0, &so->scanBehind))
2657
0
    goto new_prim_scan;
2658
2659
  /*
2660
   * When we encounter a truncated finaltup high key attribute, we're
2661
   * optimistic about the chances of its corresponding required scan key
2662
   * being satisfied when we go on to recheck it against tuples from this
2663
   * page's right sibling leaf page.  We consider truncated attributes to be
2664
   * satisfied by required scan keys, which allows the primitive index scan
2665
   * to continue to the next leaf page.  We must set so->scanBehind to true
2666
   * to remember that the last page's finaltup had "satisfied" required scan
2667
   * keys for one or more truncated attribute values (scan keys required in
2668
   * _either_ scan direction).
2669
   *
2670
   * There is a chance that _bt_readpage (which checks so->scanBehind) will
2671
   * find that even the sibling leaf page's finaltup is < the new array
2672
   * keys.  When that happens, our optimistic policy will have incurred a
2673
   * single extra leaf page access that could have been avoided.
2674
   *
2675
   * A pessimistic policy would give backward scans a gratuitous advantage
2676
   * over forward scans.  We'd punish forward scans for applying more
2677
   * accurate information from the high key, rather than just using the
2678
   * final non-pivot tuple as finaltup, in the style of backward scans.
2679
   * Being pessimistic would also give some scans with non-required arrays a
2680
   * perverse advantage over similar scans that use required arrays instead.
2681
   *
2682
   * This is similar to our scan-level heuristics, below.  They also set
2683
   * scanBehind to speculatively continue the primscan onto the next page.
2684
   */
2685
0
  if (so->scanBehind)
2686
0
  {
2687
    /* Truncated high key -- _bt_scanbehind_checkkeys recheck scheduled */
2688
0
  }
2689
2690
  /*
2691
   * Handle inequalities marked required in the opposite scan direction.
2692
   * They can also signal that we should start a new primitive index scan.
2693
   *
2694
   * It's possible that the scan is now positioned where "matching" tuples
2695
   * begin, and that caller's tuple satisfies all scan keys required in the
2696
   * current scan direction.  But if caller's tuple still doesn't satisfy
2697
   * other scan keys that are required in the opposite scan direction only
2698
   * (e.g., a required >= strategy scan key when scan direction is forward),
2699
   * it's still possible that there are many leaf pages before the page that
2700
   * _bt_first could skip straight to.  Groveling through all those pages
2701
   * will always give correct answers, but it can be very inefficient.  We
2702
   * must avoid needlessly scanning extra pages.
2703
   *
2704
   * Separately, it's possible that _bt_check_compare set continuescan=false
2705
   * for a scan key that's required in the opposite direction only.  This is
2706
   * a special case, that happens only when _bt_check_compare sees that the
2707
   * inequality encountered a NULL value.  This signals the end of non-NULL
2708
   * values in the current scan direction, which is reason enough to end the
2709
   * (primitive) scan.  If this happens at the start of a large group of
2710
   * NULL values, then we shouldn't expect to be called again until after
2711
   * the scan has already read indefinitely-many leaf pages full of tuples
2712
   * with NULL suffix values.  (_bt_first is expected to skip over the group
2713
   * of NULLs by applying a similar "deduce NOT NULL" rule of its own, which
2714
   * involves consing up an explicit SK_SEARCHNOTNULL key.)
2715
   *
2716
   * Apply a test against finaltup to detect and recover from the problem:
2717
   * if even finaltup doesn't satisfy such an inequality, we just skip by
2718
   * starting a new primitive index scan.  When we skip, we know for sure
2719
   * that all of the tuples on the current page following caller's tuple are
2720
   * also before the _bt_first-wise start of tuples for our new qual.  That
2721
   * at least suggests many more skippable pages beyond the current page.
2722
   * (when so->scanBehind and so->oppositeDirCheck are set, this'll happen
2723
   * when we test the next page's finaltup/high key instead.)
2724
   */
2725
0
  else if (has_required_opposite_direction_only && pstate->finaltup &&
2726
0
       unlikely(!_bt_oppodir_checkkeys(scan, dir, pstate->finaltup)))
2727
0
    goto new_prim_scan;
2728
2729
0
continue_scan:
2730
2731
  /*
2732
   * Stick with the ongoing primitive index scan for now.
2733
   *
2734
   * It's possible that later tuples will also turn out to have values that
2735
   * are still < the now-current array keys (or > the current array keys).
2736
   * Our caller will handle this by performing what amounts to a linear
2737
   * search of the page, implemented by calling _bt_check_compare and then
2738
   * _bt_tuple_before_array_skeys for each tuple.
2739
   *
2740
   * This approach has various advantages over a binary search of the page.
2741
   * Repeated binary searches of the page (one binary search for every array
2742
   * advancement) won't outperform a continuous linear search.  While there
2743
   * are workloads that a naive linear search won't handle well, our caller
2744
   * has a "look ahead" fallback mechanism to deal with that problem.
2745
   */
2746
0
  pstate->continuescan = true; /* Override _bt_check_compare */
2747
0
  so->needPrimScan = false;  /* _bt_readpage has more tuples to check */
2748
2749
0
  if (so->scanBehind)
2750
0
  {
2751
    /*
2752
     * Remember if recheck needs to call _bt_oppodir_checkkeys for next
2753
     * page's finaltup (see above comments about "Handle inequalities
2754
     * marked required in the opposite scan direction" for why).
2755
     */
2756
0
    so->oppositeDirCheck = has_required_opposite_direction_only;
2757
2758
    /*
2759
     * skip by setting "look ahead" mechanism's offnum for forwards scans
2760
     * (backwards scans check scanBehind flag directly instead)
2761
     */
2762
0
    if (ScanDirectionIsForward(dir))
2763
0
      pstate->skip = pstate->maxoff + 1;
2764
0
  }
2765
2766
  /* Caller's tuple doesn't match the new qual */
2767
0
  return false;
2768
2769
0
new_prim_scan:
2770
2771
0
  Assert(pstate->finaltup); /* not on rightmost/leftmost page */
2772
2773
  /*
2774
   * Looks like another primitive index scan is required.  But consider
2775
   * continuing the current primscan based on scan-level heuristics.
2776
   *
2777
   * Continue the ongoing primitive scan (and schedule a recheck for when
2778
   * the scan arrives on the next sibling leaf page) when it has already
2779
   * read at least one leaf page before the one we're reading now.  This
2780
   * makes primscan scheduling more efficient when scanning subsets of an
2781
   * index with many distinct attribute values matching many array elements.
2782
   * It encourages fewer, larger primitive scans where that makes sense.
2783
   * This will in turn encourage _bt_readpage to apply the pstate.startikey
2784
   * optimization more often.
2785
   *
2786
   * Also continue the ongoing primitive index scan when it is still on the
2787
   * first page if there have been more than NSKIPADVANCES_THRESHOLD calls
2788
   * here that each advanced at least one of the scan's skip arrays
2789
   * (deliberately ignore advancements that only affected SAOP arrays here).
2790
   * A page that cycles through this many skip array elements is quite
2791
   * likely to neighbor similar pages, that we'll also need to read.
2792
   *
2793
   * Note: These heuristics aren't as aggressive as you might think.  We're
2794
   * conservative about allowing a primitive scan to step from the first
2795
   * leaf page it reads to the page's sibling page (we only allow it on
2796
   * first pages whose finaltup strongly suggests that it'll work out, as
2797
   * well as first pages that have a large number of skip array advances).
2798
   * Clearing this first page finaltup hurdle is a strong signal in itself.
2799
   *
2800
   * Note: The NSKIPADVANCES_THRESHOLD heuristic exists only to avoid
2801
   * pathological cases.  Specifically, cases where a skip scan should just
2802
   * behave like a traditional full index scan, but ends up "skipping" again
2803
   * and again, descending to the prior leaf page's direct sibling leaf page
2804
   * each time.  This misbehavior would otherwise be possible during scans
2805
   * that never quite manage to "clear the first page finaltup hurdle".
2806
   */
2807
0
  if (!pstate->firstpage || pstate->nskipadvances > NSKIPADVANCES_THRESHOLD)
2808
0
  {
2809
    /* Schedule a recheck once on the next (or previous) page */
2810
0
    so->scanBehind = true;
2811
2812
    /* Continue the current primitive scan after all */
2813
0
    goto continue_scan;
2814
0
  }
2815
2816
  /*
2817
   * End this primitive index scan, but schedule another.
2818
   *
2819
   * Note: We make a soft assumption that the current scan direction will
2820
   * also be used within _bt_next, when it is asked to step off this page.
2821
   * It is up to _bt_next to cancel this scheduled primitive index scan
2822
   * whenever it steps to a page in the direction opposite currPos.dir.
2823
   */
2824
0
  pstate->continuescan = false;  /* Tell _bt_readpage we're done... */
2825
0
  so->needPrimScan = true; /* ...but call _bt_first again */
2826
2827
0
  if (scan->parallel_scan)
2828
0
    _bt_parallel_primscan_schedule(scan, so->currPos.currPage);
2829
2830
  /* Caller's tuple doesn't match the new qual */
2831
0
  return false;
2832
2833
0
end_toplevel_scan:
2834
2835
  /*
2836
   * End the current primitive index scan, but don't schedule another.
2837
   *
2838
   * This ends the entire top-level scan in the current scan direction.
2839
   *
2840
   * Note: The scan's arrays (including any non-required arrays) are now in
2841
   * their final positions for the current scan direction.  If the scan
2842
   * direction happens to change, then the arrays will already be in their
2843
   * first positions for what will then be the current scan direction.
2844
   */
2845
0
  pstate->continuescan = false;  /* Tell _bt_readpage we're done... */
2846
0
  so->needPrimScan = false;  /* ...and don't call _bt_first again */
2847
2848
  /* Caller's tuple doesn't match any qual */
2849
0
  return false;
2850
0
}
2851
2852
/*
2853
 * _bt_advance_array_keys_increment() -- Advance to next set of array elements
2854
 *
2855
 * Advances the array keys by a single increment in the current scan
2856
 * direction.  When there are multiple array keys this can roll over from the
2857
 * lowest order array to higher order arrays.
2858
 *
2859
 * Returns true if there is another set of values to consider, false if not.
2860
 * On true result, the scankeys are initialized with the next set of values.
2861
 * On false result, the scankeys stay the same, and the array keys are not
2862
 * advanced (every array remains at its final element for scan direction).
2863
 */
2864
static bool
2865
_bt_advance_array_keys_increment(IndexScanDesc scan, ScanDirection dir,
2866
                 bool *skip_array_set)
2867
0
{
2868
0
  Relation  rel = scan->indexRelation;
2869
0
  BTScanOpaque so = (BTScanOpaque) scan->opaque;
2870
2871
  /*
2872
   * We must advance the last array key most quickly, since it will
2873
   * correspond to the lowest-order index column among the available
2874
   * qualifications
2875
   */
2876
0
  for (int i = so->numArrayKeys - 1; i >= 0; i--)
2877
0
  {
2878
0
    BTArrayKeyInfo *array = &so->arrayKeys[i];
2879
0
    ScanKey   skey = &so->keyData[array->scan_key];
2880
2881
0
    if (array->num_elems == -1)
2882
0
      *skip_array_set = true;
2883
2884
0
    if (ScanDirectionIsForward(dir))
2885
0
    {
2886
0
      if (_bt_array_increment(rel, skey, array))
2887
0
        return true;
2888
0
    }
2889
0
    else
2890
0
    {
2891
0
      if (_bt_array_decrement(rel, skey, array))
2892
0
        return true;
2893
0
    }
2894
2895
    /*
2896
     * Couldn't increment (or decrement) array.  Handle array roll over.
2897
     *
2898
     * Start over at the array's lowest sorting value (or its highest
2899
     * value, for backward scans)...
2900
     */
2901
0
    _bt_array_set_low_or_high(rel, skey, array,
2902
0
                  ScanDirectionIsForward(dir));
2903
2904
    /* ...then increment (or decrement) next most significant array */
2905
0
  }
2906
2907
  /*
2908
   * The array keys are now exhausted.
2909
   *
2910
   * Restore the array keys to the state they were in immediately before we
2911
   * were called.  This ensures that the arrays only ever ratchet in the
2912
   * current scan direction.
2913
   *
2914
   * Without this, scans could overlook matching tuples when the scan
2915
   * direction gets reversed just before btgettuple runs out of items to
2916
   * return, but just after _bt_readpage prepares all the items from the
2917
   * scan's final page in so->currPos.  When we're on the final page it is
2918
   * typical for so->currPos to get invalidated once btgettuple finally
2919
   * returns false, which'll effectively invalidate the scan's array keys.
2920
   * That hasn't happened yet, though -- and in general it may never happen.
2921
   */
2922
0
  _bt_start_array_keys(scan, -dir);
2923
2924
0
  return false;
2925
0
}
2926
2927
/*
2928
 * _bt_array_increment() -- increment array scan key's sk_argument
2929
 *
2930
 * Return value indicates whether caller's array was successfully incremented.
2931
 * Cannot increment an array whose current element is already the final one.
2932
 */
2933
static bool
2934
_bt_array_increment(Relation rel, ScanKey skey, BTArrayKeyInfo *array)
2935
0
{
2936
0
  bool    oflow = false;
2937
0
  Datum   inc_sk_argument;
2938
2939
0
  Assert(skey->sk_flags & SK_SEARCHARRAY);
2940
0
  Assert(!(skey->sk_flags & (SK_BT_MINVAL | SK_BT_NEXT | SK_BT_PRIOR)));
2941
2942
  /* SAOP array? */
2943
0
  if (array->num_elems != -1)
2944
0
  {
2945
0
    Assert(!(skey->sk_flags & (SK_BT_SKIP | SK_BT_MINVAL | SK_BT_MAXVAL)));
2946
0
    if (array->cur_elem < array->num_elems - 1)
2947
0
    {
2948
      /*
2949
       * Just increment current element, and assign its datum to skey
2950
       * (only skip arrays need us to free existing sk_argument memory)
2951
       */
2952
0
      array->cur_elem++;
2953
0
      skey->sk_argument = array->elem_values[array->cur_elem];
2954
2955
      /* Successfully incremented array */
2956
0
      return true;
2957
0
    }
2958
2959
    /* Cannot increment past final array element */
2960
0
    return false;
2961
0
  }
2962
2963
  /* Nope, this is a skip array */
2964
0
  Assert(skey->sk_flags & SK_BT_SKIP);
2965
2966
  /*
2967
   * The sentinel value that represents the maximum value within the range
2968
   * of a skip array (often just +inf) is never incrementable
2969
   */
2970
0
  if (skey->sk_flags & SK_BT_MAXVAL)
2971
0
    return false;
2972
2973
  /*
2974
   * When the current array element is NULL, and the highest sorting value
2975
   * in the index is also NULL, we cannot increment past the final element
2976
   */
2977
0
  if ((skey->sk_flags & SK_ISNULL) && !(skey->sk_flags & SK_BT_NULLS_FIRST))
2978
0
    return false;
2979
2980
  /*
2981
   * Opclasses without skip support "increment" the scan key's current
2982
   * element by setting the NEXT flag.  The true next value is determined by
2983
   * repositioning to the first index tuple > existing sk_argument/current
2984
   * array element.  Note that this works in the usual way when the scan key
2985
   * is already marked ISNULL (i.e. when the current element is NULL).
2986
   */
2987
0
  if (!array->sksup)
2988
0
  {
2989
    /* Successfully "incremented" array */
2990
0
    skey->sk_flags |= SK_BT_NEXT;
2991
0
    return true;
2992
0
  }
2993
2994
  /*
2995
   * Opclasses with skip support directly increment sk_argument
2996
   */
2997
0
  if (skey->sk_flags & SK_ISNULL)
2998
0
  {
2999
0
    Assert(skey->sk_flags & SK_BT_NULLS_FIRST);
3000
3001
    /*
3002
     * Existing sk_argument/array element is NULL (for an IS NULL qual).
3003
     *
3004
     * "Increment" from NULL to the low_elem value provided by opclass
3005
     * skip support routine.
3006
     */
3007
0
    skey->sk_flags &= ~(SK_SEARCHNULL | SK_ISNULL);
3008
0
    skey->sk_argument = datumCopy(array->sksup->low_elem,
3009
0
                    array->attbyval, array->attlen);
3010
0
    return true;
3011
0
  }
3012
3013
  /*
3014
   * Ask opclass support routine to provide incremented copy of existing
3015
   * non-NULL sk_argument
3016
   */
3017
0
  inc_sk_argument = array->sksup->increment(rel, skey->sk_argument, &oflow);
3018
0
  if (unlikely(oflow))
3019
0
  {
3020
    /* inc_sk_argument has undefined value (so no pfree) */
3021
0
    if (array->null_elem && !(skey->sk_flags & SK_BT_NULLS_FIRST))
3022
0
    {
3023
0
      _bt_skiparray_set_isnull(rel, skey, array);
3024
3025
      /* Successfully "incremented" array to NULL */
3026
0
      return true;
3027
0
    }
3028
3029
    /* Cannot increment past final array element */
3030
0
    return false;
3031
0
  }
3032
3033
  /*
3034
   * Successfully incremented sk_argument to a non-NULL value.  Make sure
3035
   * that the incremented value is still within the range of the array.
3036
   */
3037
0
  if (array->high_compare &&
3038
0
    !DatumGetBool(FunctionCall2Coll(&array->high_compare->sk_func,
3039
0
                    array->high_compare->sk_collation,
3040
0
                    inc_sk_argument,
3041
0
                    array->high_compare->sk_argument)))
3042
0
  {
3043
    /* Keep existing sk_argument after all */
3044
0
    if (!array->attbyval)
3045
0
      pfree(DatumGetPointer(inc_sk_argument));
3046
3047
    /* Cannot increment past final array element */
3048
0
    return false;
3049
0
  }
3050
3051
  /* Accept value returned by opclass increment callback */
3052
0
  if (!array->attbyval && skey->sk_argument)
3053
0
    pfree(DatumGetPointer(skey->sk_argument));
3054
0
  skey->sk_argument = inc_sk_argument;
3055
3056
  /* Successfully incremented array */
3057
0
  return true;
3058
0
}
3059
3060
/*
3061
 * _bt_array_decrement() -- decrement array scan key's sk_argument
3062
 *
3063
 * Return value indicates whether caller's array was successfully decremented.
3064
 * Cannot decrement an array whose current element is already the first one.
3065
 */
3066
static bool
3067
_bt_array_decrement(Relation rel, ScanKey skey, BTArrayKeyInfo *array)
3068
0
{
3069
0
  bool    uflow = false;
3070
0
  Datum   dec_sk_argument;
3071
3072
0
  Assert(skey->sk_flags & SK_SEARCHARRAY);
3073
0
  Assert(!(skey->sk_flags & (SK_BT_MAXVAL | SK_BT_NEXT | SK_BT_PRIOR)));
3074
3075
  /* SAOP array? */
3076
0
  if (array->num_elems != -1)
3077
0
  {
3078
0
    Assert(!(skey->sk_flags & (SK_BT_SKIP | SK_BT_MINVAL | SK_BT_MAXVAL)));
3079
0
    if (array->cur_elem > 0)
3080
0
    {
3081
      /*
3082
       * Just decrement current element, and assign its datum to skey
3083
       * (only skip arrays need us to free existing sk_argument memory)
3084
       */
3085
0
      array->cur_elem--;
3086
0
      skey->sk_argument = array->elem_values[array->cur_elem];
3087
3088
      /* Successfully decremented array */
3089
0
      return true;
3090
0
    }
3091
3092
    /* Cannot decrement to before first array element */
3093
0
    return false;
3094
0
  }
3095
3096
  /* Nope, this is a skip array */
3097
0
  Assert(skey->sk_flags & SK_BT_SKIP);
3098
3099
  /*
3100
   * The sentinel value that represents the minimum value within the range
3101
   * of a skip array (often just -inf) is never decrementable
3102
   */
3103
0
  if (skey->sk_flags & SK_BT_MINVAL)
3104
0
    return false;
3105
3106
  /*
3107
   * When the current array element is NULL, and the lowest sorting value in
3108
   * the index is also NULL, we cannot decrement before first array element
3109
   */
3110
0
  if ((skey->sk_flags & SK_ISNULL) && (skey->sk_flags & SK_BT_NULLS_FIRST))
3111
0
    return false;
3112
3113
  /*
3114
   * Opclasses without skip support "decrement" the scan key's current
3115
   * element by setting the PRIOR flag.  The true prior value is determined
3116
   * by repositioning to the last index tuple < existing sk_argument/current
3117
   * array element.  Note that this works in the usual way when the scan key
3118
   * is already marked ISNULL (i.e. when the current element is NULL).
3119
   */
3120
0
  if (!array->sksup)
3121
0
  {
3122
    /* Successfully "decremented" array */
3123
0
    skey->sk_flags |= SK_BT_PRIOR;
3124
0
    return true;
3125
0
  }
3126
3127
  /*
3128
   * Opclasses with skip support directly decrement sk_argument
3129
   */
3130
0
  if (skey->sk_flags & SK_ISNULL)
3131
0
  {
3132
0
    Assert(!(skey->sk_flags & SK_BT_NULLS_FIRST));
3133
3134
    /*
3135
     * Existing sk_argument/array element is NULL (for an IS NULL qual).
3136
     *
3137
     * "Decrement" from NULL to the high_elem value provided by opclass
3138
     * skip support routine.
3139
     */
3140
0
    skey->sk_flags &= ~(SK_SEARCHNULL | SK_ISNULL);
3141
0
    skey->sk_argument = datumCopy(array->sksup->high_elem,
3142
0
                    array->attbyval, array->attlen);
3143
0
    return true;
3144
0
  }
3145
3146
  /*
3147
   * Ask opclass support routine to provide decremented copy of existing
3148
   * non-NULL sk_argument
3149
   */
3150
0
  dec_sk_argument = array->sksup->decrement(rel, skey->sk_argument, &uflow);
3151
0
  if (unlikely(uflow))
3152
0
  {
3153
    /* dec_sk_argument has undefined value (so no pfree) */
3154
0
    if (array->null_elem && (skey->sk_flags & SK_BT_NULLS_FIRST))
3155
0
    {
3156
0
      _bt_skiparray_set_isnull(rel, skey, array);
3157
3158
      /* Successfully "decremented" array to NULL */
3159
0
      return true;
3160
0
    }
3161
3162
    /* Cannot decrement to before first array element */
3163
0
    return false;
3164
0
  }
3165
3166
  /*
3167
   * Successfully decremented sk_argument to a non-NULL value.  Make sure
3168
   * that the decremented value is still within the range of the array.
3169
   */
3170
0
  if (array->low_compare &&
3171
0
    !DatumGetBool(FunctionCall2Coll(&array->low_compare->sk_func,
3172
0
                    array->low_compare->sk_collation,
3173
0
                    dec_sk_argument,
3174
0
                    array->low_compare->sk_argument)))
3175
0
  {
3176
    /* Keep existing sk_argument after all */
3177
0
    if (!array->attbyval)
3178
0
      pfree(DatumGetPointer(dec_sk_argument));
3179
3180
    /* Cannot decrement to before first array element */
3181
0
    return false;
3182
0
  }
3183
3184
  /* Accept value returned by opclass decrement callback */
3185
0
  if (!array->attbyval && skey->sk_argument)
3186
0
    pfree(DatumGetPointer(skey->sk_argument));
3187
0
  skey->sk_argument = dec_sk_argument;
3188
3189
  /* Successfully decremented array */
3190
0
  return true;
3191
0
}
3192
3193
/*
3194
 * _bt_array_set_low_or_high() -- Set array scan key to lowest/highest element
3195
 *
3196
 * Caller also passes associated scan key, which will have its argument set to
3197
 * the lowest/highest array value in passing.
3198
 */
3199
static void
3200
_bt_array_set_low_or_high(Relation rel, ScanKey skey, BTArrayKeyInfo *array,
3201
              bool low_not_high)
3202
0
{
3203
0
  Assert(skey->sk_flags & SK_SEARCHARRAY);
3204
3205
0
  if (array->num_elems != -1)
3206
0
  {
3207
    /* set low or high element for SAOP array */
3208
0
    int     set_elem = 0;
3209
3210
0
    Assert(!(skey->sk_flags & SK_BT_SKIP));
3211
3212
0
    if (!low_not_high)
3213
0
      set_elem = array->num_elems - 1;
3214
3215
    /*
3216
     * Just copy over array datum (only skip arrays require freeing and
3217
     * allocating memory for sk_argument)
3218
     */
3219
0
    array->cur_elem = set_elem;
3220
0
    skey->sk_argument = array->elem_values[set_elem];
3221
3222
0
    return;
3223
0
  }
3224
3225
  /* set low or high element for skip array */
3226
0
  Assert(skey->sk_flags & SK_BT_SKIP);
3227
0
  Assert(array->num_elems == -1);
3228
3229
  /* Free memory previously allocated for sk_argument if needed */
3230
0
  if (!array->attbyval && skey->sk_argument)
3231
0
    pfree(DatumGetPointer(skey->sk_argument));
3232
3233
  /* Reset flags */
3234
0
  skey->sk_argument = (Datum) 0;
3235
0
  skey->sk_flags &= ~(SK_SEARCHNULL | SK_ISNULL |
3236
0
            SK_BT_MINVAL | SK_BT_MAXVAL |
3237
0
            SK_BT_NEXT | SK_BT_PRIOR);
3238
3239
0
  if (array->null_elem &&
3240
0
    (low_not_high == ((skey->sk_flags & SK_BT_NULLS_FIRST) != 0)))
3241
0
  {
3242
    /* Requested element (either lowest or highest) has the value NULL */
3243
0
    skey->sk_flags |= (SK_SEARCHNULL | SK_ISNULL);
3244
0
  }
3245
0
  else if (low_not_high)
3246
0
  {
3247
    /* Setting array to lowest element (according to low_compare) */
3248
0
    skey->sk_flags |= SK_BT_MINVAL;
3249
0
  }
3250
0
  else
3251
0
  {
3252
    /* Setting array to highest element (according to high_compare) */
3253
0
    skey->sk_flags |= SK_BT_MAXVAL;
3254
0
  }
3255
0
}
3256
3257
/*
3258
 * _bt_skiparray_set_element() -- Set skip array scan key's sk_argument
3259
 *
3260
 * Caller passes set_elem_result returned by _bt_binsrch_skiparray_skey for
3261
 * caller's tupdatum/tupnull.
3262
 *
3263
 * We copy tupdatum/tupnull into skey's sk_argument iff set_elem_result == 0.
3264
 * Otherwise, we set skey to either the lowest or highest value that's within
3265
 * the range of caller's skip array (whichever is the best available match to
3266
 * tupdatum/tupnull that is still within the range of the skip array according
3267
 * to _bt_binsrch_skiparray_skey/set_elem_result).
3268
 */
3269
static void
3270
_bt_skiparray_set_element(Relation rel, ScanKey skey, BTArrayKeyInfo *array,
3271
              int32 set_elem_result, Datum tupdatum, bool tupnull)
3272
0
{
3273
0
  Assert(skey->sk_flags & SK_BT_SKIP);
3274
0
  Assert(skey->sk_flags & SK_SEARCHARRAY);
3275
3276
0
  if (set_elem_result)
3277
0
  {
3278
    /* tupdatum/tupnull is out of the range of the skip array */
3279
0
    Assert(!array->null_elem);
3280
3281
0
    _bt_array_set_low_or_high(rel, skey, array, set_elem_result < 0);
3282
0
    return;
3283
0
  }
3284
3285
  /* Advance skip array to tupdatum (or tupnull) value */
3286
0
  if (unlikely(tupnull))
3287
0
  {
3288
0
    _bt_skiparray_set_isnull(rel, skey, array);
3289
0
    return;
3290
0
  }
3291
3292
  /* Free memory previously allocated for sk_argument if needed */
3293
0
  if (!array->attbyval && skey->sk_argument)
3294
0
    pfree(DatumGetPointer(skey->sk_argument));
3295
3296
  /* tupdatum becomes new sk_argument/new current element */
3297
0
  skey->sk_flags &= ~(SK_SEARCHNULL | SK_ISNULL |
3298
0
            SK_BT_MINVAL | SK_BT_MAXVAL |
3299
0
            SK_BT_NEXT | SK_BT_PRIOR);
3300
0
  skey->sk_argument = datumCopy(tupdatum, array->attbyval, array->attlen);
3301
0
}
3302
3303
/*
3304
 * _bt_skiparray_set_isnull() -- set skip array scan key to NULL
3305
 */
3306
static void
3307
_bt_skiparray_set_isnull(Relation rel, ScanKey skey, BTArrayKeyInfo *array)
3308
0
{
3309
0
  Assert(skey->sk_flags & SK_BT_SKIP);
3310
0
  Assert(skey->sk_flags & SK_SEARCHARRAY);
3311
0
  Assert(array->null_elem && !array->low_compare && !array->high_compare);
3312
3313
  /* Free memory previously allocated for sk_argument if needed */
3314
0
  if (!array->attbyval && skey->sk_argument)
3315
0
    pfree(DatumGetPointer(skey->sk_argument));
3316
3317
  /* NULL becomes new sk_argument/new current element */
3318
0
  skey->sk_argument = (Datum) 0;
3319
0
  skey->sk_flags &= ~(SK_BT_MINVAL | SK_BT_MAXVAL |
3320
0
            SK_BT_NEXT | SK_BT_PRIOR);
3321
0
  skey->sk_flags |= (SK_SEARCHNULL | SK_ISNULL);
3322
0
}
3323
3324
/*
3325
 * _bt_compare_array_skey() -- apply array comparison function
3326
 *
3327
 * Compares caller's tuple attribute value to a scan key/array element.
3328
 * Helper function used during binary searches of SK_SEARCHARRAY arrays.
3329
 *
3330
 *    This routine returns:
3331
 *      <0 if tupdatum < arrdatum;
3332
 *       0 if tupdatum == arrdatum;
3333
 *      >0 if tupdatum > arrdatum.
3334
 *
3335
 * This is essentially the same interface as _bt_compare: both functions
3336
 * compare the value that they're searching for to a binary search pivot.
3337
 * However, unlike _bt_compare, this function's "tuple argument" comes first,
3338
 * while its "array/scankey argument" comes second.
3339
 */
3340
static inline int32
3341
_bt_compare_array_skey(FmgrInfo *orderproc,
3342
             Datum tupdatum, bool tupnull,
3343
             Datum arrdatum, ScanKey cur)
3344
0
{
3345
0
  int32   result = 0;
3346
3347
0
  Assert(cur->sk_strategy == BTEqualStrategyNumber);
3348
0
  Assert(!(cur->sk_flags & (SK_BT_MINVAL | SK_BT_MAXVAL)));
3349
3350
0
  if (tupnull)       /* NULL tupdatum */
3351
0
  {
3352
0
    if (cur->sk_flags & SK_ISNULL)
3353
0
      result = 0;     /* NULL "=" NULL */
3354
0
    else if (cur->sk_flags & SK_BT_NULLS_FIRST)
3355
0
      result = -1;   /* NULL "<" NOT_NULL */
3356
0
    else
3357
0
      result = 1;     /* NULL ">" NOT_NULL */
3358
0
  }
3359
0
  else if (cur->sk_flags & SK_ISNULL) /* NOT_NULL tupdatum, NULL arrdatum */
3360
0
  {
3361
0
    if (cur->sk_flags & SK_BT_NULLS_FIRST)
3362
0
      result = 1;     /* NOT_NULL ">" NULL */
3363
0
    else
3364
0
      result = -1;   /* NOT_NULL "<" NULL */
3365
0
  }
3366
0
  else
3367
0
  {
3368
    /*
3369
     * Like _bt_compare, we need to be careful of cross-type comparisons,
3370
     * so the left value has to be the value that came from an index tuple
3371
     */
3372
0
    result = DatumGetInt32(FunctionCall2Coll(orderproc, cur->sk_collation,
3373
0
                         tupdatum, arrdatum));
3374
3375
    /*
3376
     * We flip the sign by following the obvious rule: flip whenever the
3377
     * column is a DESC column.
3378
     *
3379
     * _bt_compare does it the wrong way around (flip when *ASC*) in order
3380
     * to compensate for passing its orderproc arguments backwards.  We
3381
     * don't need to play these games because we find it natural to pass
3382
     * tupdatum as the left value (and arrdatum as the right value).
3383
     */
3384
0
    if (cur->sk_flags & SK_BT_DESC)
3385
0
      INVERT_COMPARE_RESULT(result);
3386
0
  }
3387
3388
0
  return result;
3389
0
}
3390
3391
/*
3392
 * _bt_binsrch_array_skey() -- Binary search for next matching array key
3393
 *
3394
 * Returns an index to the first array element >= caller's tupdatum argument.
3395
 * This convention is more natural for forwards scan callers, but that can't
3396
 * really matter to backwards scan callers.  Both callers require handling for
3397
 * the case where the match we return is < tupdatum, and symmetric handling
3398
 * for the case where our best match is > tupdatum.
3399
 *
3400
 * Also sets *set_elem_result to the result _bt_compare_array_skey returned
3401
 * when we used it to compare the matching array element to tupdatum/tupnull.
3402
 *
3403
 * cur_elem_trig indicates if array advancement was triggered by this array's
3404
 * scan key, and that the array is for a required scan key.  We can apply this
3405
 * information to find the next matching array element in the current scan
3406
 * direction using far fewer comparisons (fewer on average, compared to naive
3407
 * binary search).  This scheme takes advantage of an important property of
3408
 * required arrays: required arrays always advance in lockstep with the index
3409
 * scan's progress through the index's key space.
3410
 */
3411
int
3412
_bt_binsrch_array_skey(FmgrInfo *orderproc,
3413
             bool cur_elem_trig, ScanDirection dir,
3414
             Datum tupdatum, bool tupnull,
3415
             BTArrayKeyInfo *array, ScanKey cur,
3416
             int32 *set_elem_result)
3417
0
{
3418
0
  int     low_elem = 0,
3419
0
        mid_elem = -1,
3420
0
        high_elem = array->num_elems - 1,
3421
0
        result = 0;
3422
0
  Datum   arrdatum;
3423
3424
0
  Assert(cur->sk_flags & SK_SEARCHARRAY);
3425
0
  Assert(!(cur->sk_flags & SK_BT_SKIP));
3426
0
  Assert(!(cur->sk_flags & SK_ISNULL)); /* SAOP arrays never have NULLs */
3427
0
  Assert(cur->sk_strategy == BTEqualStrategyNumber);
3428
3429
0
  if (cur_elem_trig)
3430
0
  {
3431
0
    Assert(!ScanDirectionIsNoMovement(dir));
3432
0
    Assert(cur->sk_flags & SK_BT_REQFWD);
3433
3434
    /*
3435
     * When the scan key that triggered array advancement is a required
3436
     * array scan key, it is now certain that the current array element
3437
     * (plus all prior elements relative to the current scan direction)
3438
     * cannot possibly be at or ahead of the corresponding tuple value.
3439
     * (_bt_checkkeys must have called _bt_tuple_before_array_skeys, which
3440
     * makes sure this is true as a condition of advancing the arrays.)
3441
     *
3442
     * This makes it safe to exclude array elements up to and including
3443
     * the former-current array element from our search.
3444
     *
3445
     * Separately, when array advancement was triggered by a required scan
3446
     * key, the array element immediately after the former-current element
3447
     * is often either an exact tupdatum match, or a "close by" near-match
3448
     * (a near-match tupdatum is one whose key space falls _between_ the
3449
     * former-current and new-current array elements).  We'll detect both
3450
     * cases via an optimistic comparison of the new search lower bound
3451
     * (or new search upper bound in the case of backwards scans).
3452
     */
3453
0
    if (ScanDirectionIsForward(dir))
3454
0
    {
3455
0
      low_elem = array->cur_elem + 1; /* old cur_elem exhausted */
3456
3457
      /* Compare prospective new cur_elem (also the new lower bound) */
3458
0
      if (high_elem >= low_elem)
3459
0
      {
3460
0
        arrdatum = array->elem_values[low_elem];
3461
0
        result = _bt_compare_array_skey(orderproc, tupdatum, tupnull,
3462
0
                        arrdatum, cur);
3463
3464
0
        if (result <= 0)
3465
0
        {
3466
          /* Optimistic comparison optimization worked out */
3467
0
          *set_elem_result = result;
3468
0
          return low_elem;
3469
0
        }
3470
0
        mid_elem = low_elem;
3471
0
        low_elem++;   /* this cur_elem exhausted, too */
3472
0
      }
3473
3474
0
      if (high_elem < low_elem)
3475
0
      {
3476
        /* Caller needs to perform "beyond end" array advancement */
3477
0
        *set_elem_result = 1;
3478
0
        return high_elem;
3479
0
      }
3480
0
    }
3481
0
    else
3482
0
    {
3483
0
      high_elem = array->cur_elem - 1;  /* old cur_elem exhausted */
3484
3485
      /* Compare prospective new cur_elem (also the new upper bound) */
3486
0
      if (high_elem >= low_elem)
3487
0
      {
3488
0
        arrdatum = array->elem_values[high_elem];
3489
0
        result = _bt_compare_array_skey(orderproc, tupdatum, tupnull,
3490
0
                        arrdatum, cur);
3491
3492
0
        if (result >= 0)
3493
0
        {
3494
          /* Optimistic comparison optimization worked out */
3495
0
          *set_elem_result = result;
3496
0
          return high_elem;
3497
0
        }
3498
0
        mid_elem = high_elem;
3499
0
        high_elem--;  /* this cur_elem exhausted, too */
3500
0
      }
3501
3502
0
      if (high_elem < low_elem)
3503
0
      {
3504
        /* Caller needs to perform "beyond end" array advancement */
3505
0
        *set_elem_result = -1;
3506
0
        return low_elem;
3507
0
      }
3508
0
    }
3509
0
  }
3510
3511
0
  while (high_elem > low_elem)
3512
0
  {
3513
0
    mid_elem = low_elem + ((high_elem - low_elem) / 2);
3514
0
    arrdatum = array->elem_values[mid_elem];
3515
3516
0
    result = _bt_compare_array_skey(orderproc, tupdatum, tupnull,
3517
0
                    arrdatum, cur);
3518
3519
0
    if (result == 0)
3520
0
    {
3521
      /*
3522
       * It's safe to quit as soon as we see an equal array element.
3523
       * This often saves an extra comparison or two...
3524
       */
3525
0
      low_elem = mid_elem;
3526
0
      break;
3527
0
    }
3528
3529
0
    if (result > 0)
3530
0
      low_elem = mid_elem + 1;
3531
0
    else
3532
0
      high_elem = mid_elem;
3533
0
  }
3534
3535
  /*
3536
   * ...but our caller also cares about how its searched-for tuple datum
3537
   * compares to the low_elem datum.  Must always set *set_elem_result with
3538
   * the result of that comparison specifically.
3539
   */
3540
0
  if (low_elem != mid_elem)
3541
0
    result = _bt_compare_array_skey(orderproc, tupdatum, tupnull,
3542
0
                    array->elem_values[low_elem], cur);
3543
3544
0
  *set_elem_result = result;
3545
3546
0
  return low_elem;
3547
0
}
3548
3549
/*
3550
 * _bt_binsrch_skiparray_skey() -- "Binary search" within a skip array
3551
 *
3552
 * Does not return an index into the array, since skip arrays don't really
3553
 * contain elements (they generate their array elements procedurally instead).
3554
 * Our interface matches that of _bt_binsrch_array_skey in every other way.
3555
 *
3556
 * Sets *set_elem_result just like _bt_binsrch_array_skey would with a true
3557
 * array.  The value 0 indicates that tupdatum/tupnull is within the range of
3558
 * the skip array.  We return -1 when tupdatum/tupnull is lower that any value
3559
 * within the range of the array, and 1 when it is higher than every value.
3560
 * Caller should pass *set_elem_result to _bt_skiparray_set_element to advance
3561
 * the array.
3562
 *
3563
 * cur_elem_trig indicates if array advancement was triggered by this array's
3564
 * scan key.  We use this to optimize-away comparisons that are known by our
3565
 * caller to be unnecessary from context, just like _bt_binsrch_array_skey.
3566
 */
3567
static void
3568
_bt_binsrch_skiparray_skey(bool cur_elem_trig, ScanDirection dir,
3569
               Datum tupdatum, bool tupnull,
3570
               BTArrayKeyInfo *array, ScanKey cur,
3571
               int32 *set_elem_result)
3572
0
{
3573
0
  Assert(cur->sk_flags & SK_BT_SKIP);
3574
0
  Assert(cur->sk_flags & SK_SEARCHARRAY);
3575
0
  Assert(cur->sk_flags & SK_BT_REQFWD);
3576
0
  Assert(array->num_elems == -1);
3577
0
  Assert(!ScanDirectionIsNoMovement(dir));
3578
3579
0
  if (array->null_elem)
3580
0
  {
3581
0
    Assert(!array->low_compare && !array->high_compare);
3582
3583
0
    *set_elem_result = 0;
3584
0
    return;
3585
0
  }
3586
3587
0
  if (tupnull)       /* NULL tupdatum */
3588
0
  {
3589
0
    if (cur->sk_flags & SK_BT_NULLS_FIRST)
3590
0
      *set_elem_result = -1; /* NULL "<" NOT_NULL */
3591
0
    else
3592
0
      *set_elem_result = 1; /* NULL ">" NOT_NULL */
3593
0
    return;
3594
0
  }
3595
3596
  /*
3597
   * Array inequalities determine whether tupdatum is within the range of
3598
   * caller's skip array
3599
   */
3600
0
  *set_elem_result = 0;
3601
0
  if (ScanDirectionIsForward(dir))
3602
0
  {
3603
    /*
3604
     * Evaluate low_compare first (unless cur_elem_trig tells us that it
3605
     * cannot possibly fail to be satisfied), then evaluate high_compare
3606
     */
3607
0
    if (!cur_elem_trig && array->low_compare &&
3608
0
      !DatumGetBool(FunctionCall2Coll(&array->low_compare->sk_func,
3609
0
                      array->low_compare->sk_collation,
3610
0
                      tupdatum,
3611
0
                      array->low_compare->sk_argument)))
3612
0
      *set_elem_result = -1;
3613
0
    else if (array->high_compare &&
3614
0
         !DatumGetBool(FunctionCall2Coll(&array->high_compare->sk_func,
3615
0
                         array->high_compare->sk_collation,
3616
0
                         tupdatum,
3617
0
                         array->high_compare->sk_argument)))
3618
0
      *set_elem_result = 1;
3619
0
  }
3620
0
  else
3621
0
  {
3622
    /*
3623
     * Evaluate high_compare first (unless cur_elem_trig tells us that it
3624
     * cannot possibly fail to be satisfied), then evaluate low_compare
3625
     */
3626
0
    if (!cur_elem_trig && array->high_compare &&
3627
0
      !DatumGetBool(FunctionCall2Coll(&array->high_compare->sk_func,
3628
0
                      array->high_compare->sk_collation,
3629
0
                      tupdatum,
3630
0
                      array->high_compare->sk_argument)))
3631
0
      *set_elem_result = 1;
3632
0
    else if (array->low_compare &&
3633
0
         !DatumGetBool(FunctionCall2Coll(&array->low_compare->sk_func,
3634
0
                         array->low_compare->sk_collation,
3635
0
                         tupdatum,
3636
0
                         array->low_compare->sk_argument)))
3637
0
      *set_elem_result = -1;
3638
0
  }
3639
3640
  /*
3641
   * Assert that any keys that were assumed to be satisfied already (due to
3642
   * caller passing cur_elem_trig=true) really are satisfied as expected
3643
   */
3644
#ifdef USE_ASSERT_CHECKING
3645
  if (cur_elem_trig)
3646
  {
3647
    if (ScanDirectionIsForward(dir) && array->low_compare)
3648
      Assert(DatumGetBool(FunctionCall2Coll(&array->low_compare->sk_func,
3649
                          array->low_compare->sk_collation,
3650
                          tupdatum,
3651
                          array->low_compare->sk_argument)));
3652
3653
    if (ScanDirectionIsBackward(dir) && array->high_compare)
3654
      Assert(DatumGetBool(FunctionCall2Coll(&array->high_compare->sk_func,
3655
                          array->high_compare->sk_collation,
3656
                          tupdatum,
3657
                          array->high_compare->sk_argument)));
3658
  }
3659
#endif
3660
0
}
3661
3662
#ifdef USE_ASSERT_CHECKING
3663
/*
3664
 * Verify that the scan's "so->keyData[]" scan keys are in agreement with
3665
 * its array key state
3666
 */
3667
static bool
3668
_bt_verify_keys_with_arraykeys(IndexScanDesc scan)
3669
{
3670
  BTScanOpaque so = (BTScanOpaque) scan->opaque;
3671
  int     last_sk_attno = InvalidAttrNumber,
3672
        arrayidx = 0;
3673
  bool    nonrequiredseen = false;
3674
3675
  if (!so->qual_ok)
3676
    return false;
3677
3678
  for (int ikey = 0; ikey < so->numberOfKeys; ikey++)
3679
  {
3680
    ScanKey   cur = so->keyData + ikey;
3681
    BTArrayKeyInfo *array;
3682
3683
    if (!(cur->sk_flags & SK_SEARCHARRAY))
3684
      continue;
3685
3686
    if (cur->sk_strategy != BTEqualStrategyNumber)
3687
      return false;
3688
3689
    array = &so->arrayKeys[arrayidx++];
3690
    if (array->scan_key != ikey)
3691
      return false;
3692
3693
    if (array->num_elems == 0 || array->num_elems < -1)
3694
      return false;
3695
3696
    if (array->num_elems != -1 &&
3697
      cur->sk_argument != array->elem_values[array->cur_elem])
3698
      return false;
3699
    if (cur->sk_flags & (SK_BT_REQFWD | SK_BT_REQBKWD))
3700
    {
3701
      if (last_sk_attno > cur->sk_attno)
3702
        return false;
3703
      if (nonrequiredseen)
3704
        return false;
3705
    }
3706
    else
3707
      nonrequiredseen = true;
3708
3709
    last_sk_attno = cur->sk_attno;
3710
  }
3711
3712
  if (arrayidx != so->numArrayKeys)
3713
    return false;
3714
3715
  return true;
3716
}
3717
#endif