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/nbtsearch.c
Line
Count
Source
1
/*-------------------------------------------------------------------------
2
 *
3
 * nbtsearch.c
4
 *    Search code for postgres btrees.
5
 *
6
 *
7
 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
8
 * Portions Copyright (c) 1994, Regents of the University of California
9
 *
10
 * IDENTIFICATION
11
 *    src/backend/access/nbtree/nbtsearch.c
12
 *
13
 *-------------------------------------------------------------------------
14
 */
15
16
#include "postgres.h"
17
18
#include "access/nbtree.h"
19
#include "access/relscan.h"
20
#include "access/xact.h"
21
#include "catalog/catalog.h"
22
#include "executor/instrument_node.h"
23
#include "miscadmin.h"
24
#include "pgstat.h"
25
#include "storage/predicate.h"
26
#include "utils/injection_point.h"
27
#include "utils/lsyscache.h"
28
#include "utils/rel.h"
29
30
31
static inline void _bt_drop_lock_and_maybe_pin(Relation rel, BTScanOpaque so);
32
static Buffer _bt_moveright(Relation rel, Relation heaprel, BTScanInsert key,
33
              Buffer buf, bool forupdate, BTStack stack,
34
              int access);
35
static OffsetNumber _bt_binsrch(Relation rel, BTScanInsert key, Buffer buf);
36
static int  _bt_binsrch_posting(BTScanInsert key, Page page,
37
                OffsetNumber offnum);
38
static inline void _bt_returnitem(IndexScanDesc scan, BTScanOpaque so);
39
static bool _bt_steppage(IndexScanDesc scan, ScanDirection dir);
40
static bool _bt_readfirstpage(IndexScanDesc scan, OffsetNumber offnum,
41
                ScanDirection dir);
42
static bool _bt_readnextpage(IndexScanDesc scan, BlockNumber blkno,
43
               BlockNumber lastcurrblkno, ScanDirection dir,
44
               bool seized);
45
static Buffer _bt_lock_and_validate_left(Relation rel, BlockNumber *blkno,
46
                     BlockNumber lastcurrblkno);
47
static bool _bt_endpoint(IndexScanDesc scan, ScanDirection dir);
48
49
50
/*
51
 *  _bt_drop_lock_and_maybe_pin()
52
 *
53
 * Unlock so->currPos.buf.  If scan is so->dropPin, drop the pin, too.
54
 * Dropping the pin prevents VACUUM from blocking on acquiring a cleanup lock.
55
 */
56
static inline void
57
_bt_drop_lock_and_maybe_pin(Relation rel, BTScanOpaque so)
58
0
{
59
0
  if (!so->dropPin)
60
0
  {
61
    /* Just drop the lock (not the pin) */
62
0
    _bt_unlockbuf(rel, so->currPos.buf);
63
0
    return;
64
0
  }
65
66
  /*
67
   * Drop both the lock and the pin.
68
   *
69
   * Have to set so->currPos.lsn so that _bt_killitems has a way to detect
70
   * when concurrent heap TID recycling by VACUUM might have taken place.
71
   */
72
0
  so->currPos.lsn = BufferGetLSNAtomic(so->currPos.buf);
73
0
  _bt_relbuf(rel, so->currPos.buf);
74
0
  so->currPos.buf = InvalidBuffer;
75
0
}
76
77
/*
78
 *  _bt_search() -- Search the tree for a particular scankey,
79
 *    or more precisely for the first leaf page it could be on.
80
 *
81
 * The passed scankey is an insertion-type scankey (see nbtree/README),
82
 * but it can omit the rightmost column(s) of the index.
83
 *
84
 * If returnstack is true, return value is a stack of parent-page pointers
85
 * (i.e. there is no entry for the leaf level/page).  If returnstack is false,
86
 * we just return NULL.  This scheme allows callers that don't need a descent
87
 * stack to avoid palloc churn.
88
 *
89
 * When we return, *bufP is set to the address of the leaf-page buffer, which
90
 * is locked and pinned.  No locks are held on the parent pages, however!
91
 *
92
 * The returned buffer is locked according to access parameter.  Additionally,
93
 * access = BT_WRITE will allow an empty root page to be created and returned.
94
 * When access = BT_READ, an empty index will result in *bufP being set to
95
 * InvalidBuffer.  Also, in BT_WRITE mode, any incomplete splits encountered
96
 * during the search will be finished.
97
 *
98
 * heaprel must be provided by callers that pass access = BT_WRITE, since we
99
 * might need to allocate a new root page for caller -- see _bt_allocbuf.
100
 */
101
BTStack
102
_bt_search(Relation rel, Relation heaprel, BTScanInsert key, Buffer *bufP,
103
       int access, bool returnstack)
104
0
{
105
0
  BTStack   stack_in = NULL;
106
0
  int     page_access = BT_READ;
107
108
  /* heaprel must be set whenever _bt_allocbuf is reachable */
109
0
  Assert(access == BT_READ || access == BT_WRITE);
110
0
  Assert(access == BT_READ || heaprel != NULL);
111
112
  /* Get the root page to start with */
113
0
  *bufP = _bt_getroot(rel, heaprel, access);
114
115
  /* If index is empty and access = BT_READ, no root page is created. */
116
0
  if (!BufferIsValid(*bufP))
117
0
    return (BTStack) NULL;
118
119
  /* Loop iterates once per level descended in the tree */
120
0
  for (;;)
121
0
  {
122
0
    Page    page;
123
0
    BTPageOpaque opaque;
124
0
    OffsetNumber offnum;
125
0
    ItemId    itemid;
126
0
    IndexTuple  itup;
127
0
    BlockNumber child;
128
0
    BTStack   new_stack;
129
130
    /*
131
     * Race -- the page we just grabbed may have split since we read its
132
     * downlink in its parent page (or the metapage).  If it has, we may
133
     * need to move right to its new sibling.  Do that.
134
     *
135
     * In write-mode, allow _bt_moveright to finish any incomplete splits
136
     * along the way.  Strictly speaking, we'd only need to finish an
137
     * incomplete split on the leaf page we're about to insert to, not on
138
     * any of the upper levels (internal pages with incomplete splits are
139
     * also taken care of in _bt_getstackbuf).  But this is a good
140
     * opportunity to finish splits of internal pages too.
141
     */
142
0
    *bufP = _bt_moveright(rel, heaprel, key, *bufP, (access == BT_WRITE),
143
0
                stack_in, page_access);
144
145
    /* if this is a leaf page, we're done */
146
0
    page = BufferGetPage(*bufP);
147
0
    opaque = BTPageGetOpaque(page);
148
0
    if (P_ISLEAF(opaque))
149
0
      break;
150
151
    /*
152
     * Find the appropriate pivot tuple on this page.  Its downlink points
153
     * to the child page that we're about to descend to.
154
     */
155
0
    offnum = _bt_binsrch(rel, key, *bufP);
156
0
    itemid = PageGetItemId(page, offnum);
157
0
    itup = (IndexTuple) PageGetItem(page, itemid);
158
0
    Assert(BTreeTupleIsPivot(itup) || !key->heapkeyspace);
159
0
    child = BTreeTupleGetDownLink(itup);
160
161
    /*
162
     * We need to save the location of the pivot tuple we chose in a new
163
     * stack entry for this page/level.  If caller ends up splitting a
164
     * page one level down, it usually ends up inserting a new pivot
165
     * tuple/downlink immediately after the location recorded here.
166
     */
167
0
    if (returnstack)
168
0
    {
169
0
      new_stack = (BTStack) palloc_object(BTStackData);
170
0
      new_stack->bts_blkno = BufferGetBlockNumber(*bufP);
171
0
      new_stack->bts_offset = offnum;
172
0
      new_stack->bts_parent = stack_in;
173
0
      stack_in = new_stack;
174
0
    }
175
176
    /*
177
     * Page level 1 is lowest non-leaf page level prior to leaves.  So, if
178
     * we're on the level 1 and asked to lock leaf page in write mode,
179
     * then lock next page in write mode, because it must be a leaf.
180
     */
181
0
    if (opaque->btpo_level == 1 && access == BT_WRITE)
182
0
      page_access = BT_WRITE;
183
184
    /* drop the read lock on the page, then acquire one on its child */
185
0
    *bufP = _bt_relandgetbuf(rel, *bufP, child, page_access);
186
187
    /* okay, all set to move down a level */
188
0
  }
189
190
  /*
191
   * If we're asked to lock leaf in write mode, but didn't manage to, then
192
   * relock.  This should only happen when the root page is a leaf page (and
193
   * the only page in the index other than the metapage).
194
   */
195
0
  if (access == BT_WRITE && page_access == BT_READ)
196
0
  {
197
    /* trade in our read lock for a write lock */
198
0
    _bt_unlockbuf(rel, *bufP);
199
0
    _bt_lockbuf(rel, *bufP, BT_WRITE);
200
201
    /*
202
     * Race -- the leaf page may have split after we dropped the read lock
203
     * but before we acquired a write lock.  If it has, we may need to
204
     * move right to its new sibling.  Do that.
205
     */
206
0
    *bufP = _bt_moveright(rel, heaprel, key, *bufP, true, stack_in, BT_WRITE);
207
0
  }
208
209
0
  return stack_in;
210
0
}
211
212
/*
213
 *  _bt_moveright() -- move right in the btree if necessary.
214
 *
215
 * When we follow a pointer to reach a page, it is possible that
216
 * the page has changed in the meanwhile.  If this happens, we're
217
 * guaranteed that the page has "split right" -- that is, that any
218
 * data that appeared on the page originally is either on the page
219
 * or strictly to the right of it.
220
 *
221
 * This routine decides whether or not we need to move right in the
222
 * tree by examining the high key entry on the page.  If that entry is
223
 * strictly less than the scankey, or <= the scankey in the
224
 * key.nextkey=true case, then we followed the wrong link and we need
225
 * to move right.
226
 *
227
 * The passed insertion-type scankey can omit the rightmost column(s) of the
228
 * index. (see nbtree/README)
229
 *
230
 * When key.nextkey is false (the usual case), we are looking for the first
231
 * item >= key.  When key.nextkey is true, we are looking for the first item
232
 * strictly greater than key.
233
 *
234
 * If forupdate is true, we will attempt to finish any incomplete splits
235
 * that we encounter.  This is required when locking a target page for an
236
 * insertion, because we don't allow inserting on a page before the split is
237
 * completed.  'heaprel' and 'stack' are only used if forupdate is true.
238
 *
239
 * On entry, we have the buffer pinned and a lock of the type specified by
240
 * 'access'.  If we move right, we release the buffer and lock and acquire
241
 * the same on the right sibling.  Return value is the buffer we stop at.
242
 */
243
static Buffer
244
_bt_moveright(Relation rel,
245
        Relation heaprel,
246
        BTScanInsert key,
247
        Buffer buf,
248
        bool forupdate,
249
        BTStack stack,
250
        int access)
251
0
{
252
0
  Page    page;
253
0
  BTPageOpaque opaque;
254
0
  int32   cmpval;
255
256
0
  Assert(!forupdate || heaprel != NULL);
257
258
  /*
259
   * When nextkey = false (normal case): if the scan key that brought us to
260
   * this page is > the high key stored on the page, then the page has split
261
   * and we need to move right.  (pg_upgrade'd !heapkeyspace indexes could
262
   * have some duplicates to the right as well as the left, but that's
263
   * something that's only ever dealt with on the leaf level, after
264
   * _bt_search has found an initial leaf page.)
265
   *
266
   * When nextkey = true: move right if the scan key is >= page's high key.
267
   * (Note that key.scantid cannot be set in this case.)
268
   *
269
   * The page could even have split more than once, so scan as far as
270
   * needed.
271
   *
272
   * We also have to move right if we followed a link that brought us to a
273
   * dead page.
274
   */
275
0
  cmpval = key->nextkey ? 0 : 1;
276
277
0
  for (;;)
278
0
  {
279
0
    page = BufferGetPage(buf);
280
0
    opaque = BTPageGetOpaque(page);
281
282
0
    if (P_RIGHTMOST(opaque))
283
0
      break;
284
285
    /*
286
     * Finish any incomplete splits we encounter along the way.
287
     */
288
0
    if (forupdate && P_INCOMPLETE_SPLIT(opaque))
289
0
    {
290
0
      BlockNumber blkno = BufferGetBlockNumber(buf);
291
292
      /* upgrade our lock if necessary */
293
0
      if (access == BT_READ)
294
0
      {
295
0
        _bt_unlockbuf(rel, buf);
296
0
        _bt_lockbuf(rel, buf, BT_WRITE);
297
0
      }
298
299
0
      if (P_INCOMPLETE_SPLIT(opaque))
300
0
        _bt_finish_split(rel, heaprel, buf, stack);
301
0
      else
302
0
        _bt_relbuf(rel, buf);
303
304
      /* re-acquire the lock in the right mode, and re-check */
305
0
      buf = _bt_getbuf(rel, blkno, access);
306
0
      continue;
307
0
    }
308
309
0
    if (P_IGNORE(opaque) || _bt_compare(rel, key, page, P_HIKEY) >= cmpval)
310
0
    {
311
      /* step right one page */
312
0
      buf = _bt_relandgetbuf(rel, buf, opaque->btpo_next, access);
313
0
      continue;
314
0
    }
315
0
    else
316
0
      break;
317
0
  }
318
319
0
  if (P_IGNORE(opaque))
320
0
    elog(ERROR, "fell off the end of index \"%s\"",
321
0
       RelationGetRelationName(rel));
322
323
0
  return buf;
324
0
}
325
326
/*
327
 *  _bt_binsrch() -- Do a binary search for a key on a particular page.
328
 *
329
 * On an internal (non-leaf) page, _bt_binsrch() returns the OffsetNumber
330
 * of the last key < given scankey, or last key <= given scankey if nextkey
331
 * is true.  (Since _bt_compare treats the first data key of such a page as
332
 * minus infinity, there will be at least one key < scankey, so the result
333
 * always points at one of the keys on the page.)
334
 *
335
 * On a leaf page, _bt_binsrch() returns the final result of the initial
336
 * positioning process that started with _bt_first's call to _bt_search.
337
 * We're returning a non-pivot tuple offset, so things are a little different.
338
 * It is possible that we'll return an offset that's either past the last
339
 * non-pivot slot, or (in the case of a backward scan) before the first slot.
340
 *
341
 * This procedure is not responsible for walking right, it just examines
342
 * the given page.  _bt_binsrch() has no lock or refcount side effects
343
 * on the buffer.
344
 */
345
static OffsetNumber
346
_bt_binsrch(Relation rel,
347
      BTScanInsert key,
348
      Buffer buf)
349
0
{
350
0
  Page    page;
351
0
  BTPageOpaque opaque;
352
0
  OffsetNumber low,
353
0
        high;
354
0
  int32   result,
355
0
        cmpval;
356
357
0
  page = BufferGetPage(buf);
358
0
  opaque = BTPageGetOpaque(page);
359
360
  /* Requesting nextkey semantics while using scantid seems nonsensical */
361
0
  Assert(!key->nextkey || key->scantid == NULL);
362
  /* scantid-set callers must use _bt_binsrch_insert() on leaf pages */
363
0
  Assert(!P_ISLEAF(opaque) || key->scantid == NULL);
364
365
0
  low = P_FIRSTDATAKEY(opaque);
366
0
  high = PageGetMaxOffsetNumber(page);
367
368
  /*
369
   * If there are no keys on the page, return the first available slot. Note
370
   * this covers two cases: the page is really empty (no keys), or it
371
   * contains only a high key.  The latter case is possible after vacuuming.
372
   * This can never happen on an internal page, however, since they are
373
   * never empty (an internal page must have at least one child).
374
   */
375
0
  if (unlikely(high < low))
376
0
    return low;
377
378
  /*
379
   * Binary search to find the first key on the page >= scan key, or first
380
   * key > scankey when nextkey is true.
381
   *
382
   * For nextkey=false (cmpval=1), the loop invariant is: all slots before
383
   * 'low' are < scan key, all slots at or after 'high' are >= scan key.
384
   *
385
   * For nextkey=true (cmpval=0), the loop invariant is: all slots before
386
   * 'low' are <= scan key, all slots at or after 'high' are > scan key.
387
   *
388
   * We can fall out when high == low.
389
   */
390
0
  high++;           /* establish the loop invariant for high */
391
392
0
  cmpval = key->nextkey ? 0 : 1; /* select comparison value */
393
394
0
  while (high > low)
395
0
  {
396
0
    OffsetNumber mid = low + ((high - low) / 2);
397
398
    /* We have low <= mid < high, so mid points at a real slot */
399
400
0
    result = _bt_compare(rel, key, page, mid);
401
402
0
    if (result >= cmpval)
403
0
      low = mid + 1;
404
0
    else
405
0
      high = mid;
406
0
  }
407
408
  /*
409
   * At this point we have high == low.
410
   *
411
   * On a leaf page we always return the first non-pivot tuple >= scan key
412
   * (resp. > scan key) for forward scan callers.  For backward scans, it's
413
   * always the _last_ non-pivot tuple < scan key (resp. <= scan key).
414
   */
415
0
  if (P_ISLEAF(opaque))
416
0
  {
417
    /*
418
     * In the backward scan case we're supposed to locate the last
419
     * matching tuple on the leaf level -- not the first matching tuple
420
     * (the last tuple will be the first one returned by the scan).
421
     *
422
     * At this point we've located the first non-pivot tuple immediately
423
     * after the last matching tuple (which might just be maxoff + 1).
424
     * Compensate by stepping back.
425
     */
426
0
    if (key->backward)
427
0
      return OffsetNumberPrev(low);
428
429
0
    return low;
430
0
  }
431
432
  /*
433
   * On a non-leaf page, return the last key < scan key (resp. <= scan key).
434
   * There must be one if _bt_compare() is playing by the rules.
435
   *
436
   * _bt_compare() will seldom see any exactly-matching pivot tuples, since
437
   * a truncated -inf heap TID is usually enough to prevent it altogether.
438
   * Even omitted scan key entries are treated as > truncated attributes.
439
   *
440
   * However, during backward scans _bt_compare() interprets omitted scan
441
   * key attributes as == corresponding truncated -inf attributes instead.
442
   * This works just like < would work here.  Under this scheme, < strategy
443
   * backward scans will always directly descend to the correct leaf page.
444
   * In particular, they will never incur an "extra" leaf page access with a
445
   * scan key that happens to contain the same prefix of values as some
446
   * pivot tuple's untruncated prefix.  VACUUM relies on this guarantee when
447
   * it uses a leaf page high key to "re-find" a page undergoing deletion.
448
   */
449
0
  Assert(low > P_FIRSTDATAKEY(opaque));
450
451
0
  return OffsetNumberPrev(low);
452
0
}
453
454
/*
455
 *
456
 *  _bt_binsrch_insert() -- Cacheable, incremental leaf page binary search.
457
 *
458
 * Like _bt_binsrch(), but with support for caching the binary search
459
 * bounds.  Only used during insertion, and only on the leaf page that it
460
 * looks like caller will insert tuple on.  Exclusive-locked and pinned
461
 * leaf page is contained within insertstate.
462
 *
463
 * Caches the bounds fields in insertstate so that a subsequent call can
464
 * reuse the low and strict high bounds of original binary search.  Callers
465
 * that use these fields directly must be prepared for the case where low
466
 * and/or stricthigh are not on the same page (one or both exceed maxoff
467
 * for the page).  The case where there are no items on the page (high <
468
 * low) makes bounds invalid.
469
 *
470
 * Caller is responsible for invalidating bounds when it modifies the page
471
 * before calling here a second time, and for dealing with posting list
472
 * tuple matches (callers can use insertstate's postingoff field to
473
 * determine which existing heap TID will need to be replaced by a posting
474
 * list split).
475
 */
476
OffsetNumber
477
_bt_binsrch_insert(Relation rel, BTInsertState insertstate)
478
0
{
479
0
  BTScanInsert key = insertstate->itup_key;
480
0
  Page    page;
481
0
  BTPageOpaque opaque;
482
0
  OffsetNumber low,
483
0
        high,
484
0
        stricthigh;
485
0
  int32   result,
486
0
        cmpval;
487
488
0
  page = BufferGetPage(insertstate->buf);
489
0
  opaque = BTPageGetOpaque(page);
490
491
0
  Assert(P_ISLEAF(opaque));
492
0
  Assert(!key->nextkey);
493
0
  Assert(insertstate->postingoff == 0);
494
495
0
  if (!insertstate->bounds_valid)
496
0
  {
497
    /* Start new binary search */
498
0
    low = P_FIRSTDATAKEY(opaque);
499
0
    high = PageGetMaxOffsetNumber(page);
500
0
  }
501
0
  else
502
0
  {
503
    /* Restore result of previous binary search against same page */
504
0
    low = insertstate->low;
505
0
    high = insertstate->stricthigh;
506
0
  }
507
508
  /* If there are no keys on the page, return the first available slot */
509
0
  if (unlikely(high < low))
510
0
  {
511
    /* Caller can't reuse bounds */
512
0
    insertstate->low = InvalidOffsetNumber;
513
0
    insertstate->stricthigh = InvalidOffsetNumber;
514
0
    insertstate->bounds_valid = false;
515
0
    return low;
516
0
  }
517
518
  /*
519
   * Binary search to find the first key on the page >= scan key. (nextkey
520
   * is always false when inserting).
521
   *
522
   * The loop invariant is: all slots before 'low' are < scan key, all slots
523
   * at or after 'high' are >= scan key.  'stricthigh' is > scan key, and is
524
   * maintained to save additional search effort for caller.
525
   *
526
   * We can fall out when high == low.
527
   */
528
0
  if (!insertstate->bounds_valid)
529
0
    high++;         /* establish the loop invariant for high */
530
0
  stricthigh = high;      /* high initially strictly higher */
531
532
0
  cmpval = 1;         /* !nextkey comparison value */
533
534
0
  while (high > low)
535
0
  {
536
0
    OffsetNumber mid = low + ((high - low) / 2);
537
538
    /* We have low <= mid < high, so mid points at a real slot */
539
540
0
    result = _bt_compare(rel, key, page, mid);
541
542
0
    if (result >= cmpval)
543
0
      low = mid + 1;
544
0
    else
545
0
    {
546
0
      high = mid;
547
0
      if (result != 0)
548
0
        stricthigh = high;
549
0
    }
550
551
    /*
552
     * If tuple at offset located by binary search is a posting list whose
553
     * TID range overlaps with caller's scantid, perform posting list
554
     * binary search to set postingoff for caller.  Caller must split the
555
     * posting list when postingoff is set.  This should happen
556
     * infrequently.
557
     */
558
0
    if (unlikely(result == 0 && key->scantid != NULL))
559
0
    {
560
      /*
561
       * postingoff should never be set more than once per leaf page
562
       * binary search.  That would mean that there are duplicate table
563
       * TIDs in the index, which is never okay.  Check for that here.
564
       */
565
0
      if (insertstate->postingoff != 0)
566
0
        ereport(ERROR,
567
0
            (errcode(ERRCODE_INDEX_CORRUPTED),
568
0
             errmsg_internal("table tid from new index tuple (%u,%u) cannot find insert offset between offsets %u and %u of block %u in index \"%s\"",
569
0
                     ItemPointerGetBlockNumber(key->scantid),
570
0
                     ItemPointerGetOffsetNumber(key->scantid),
571
0
                     low, stricthigh,
572
0
                     BufferGetBlockNumber(insertstate->buf),
573
0
                     RelationGetRelationName(rel))));
574
575
0
      insertstate->postingoff = _bt_binsrch_posting(key, page, mid);
576
0
    }
577
0
  }
578
579
  /*
580
   * On a leaf page, a binary search always returns the first key >= scan
581
   * key (at least in !nextkey case), which could be the last slot + 1. This
582
   * is also the lower bound of cached search.
583
   *
584
   * stricthigh may also be the last slot + 1, which prevents caller from
585
   * using bounds directly, but is still useful to us if we're called a
586
   * second time with cached bounds (cached low will be < stricthigh when
587
   * that happens).
588
   */
589
0
  insertstate->low = low;
590
0
  insertstate->stricthigh = stricthigh;
591
0
  insertstate->bounds_valid = true;
592
593
0
  return low;
594
0
}
595
596
/*----------
597
 *  _bt_binsrch_posting() -- posting list binary search.
598
 *
599
 * Helper routine for _bt_binsrch_insert().
600
 *
601
 * Returns offset into posting list where caller's scantid belongs.
602
 *----------
603
 */
604
static int
605
_bt_binsrch_posting(BTScanInsert key, Page page, OffsetNumber offnum)
606
0
{
607
0
  IndexTuple  itup;
608
0
  ItemId    itemid;
609
0
  int     low,
610
0
        high,
611
0
        mid,
612
0
        res;
613
614
  /*
615
   * If this isn't a posting tuple, then the index must be corrupt (if it is
616
   * an ordinary non-pivot tuple then there must be an existing tuple with a
617
   * heap TID that equals inserter's new heap TID/scantid).  Defensively
618
   * check that tuple is a posting list tuple whose posting list range
619
   * includes caller's scantid.
620
   *
621
   * (This is also needed because contrib/amcheck's rootdescend option needs
622
   * to be able to relocate a non-pivot tuple using _bt_binsrch_insert().)
623
   */
624
0
  itemid = PageGetItemId(page, offnum);
625
0
  itup = (IndexTuple) PageGetItem(page, itemid);
626
0
  if (!BTreeTupleIsPosting(itup))
627
0
    return 0;
628
629
0
  Assert(key->heapkeyspace && key->allequalimage);
630
631
  /*
632
   * In the event that posting list tuple has LP_DEAD bit set, indicate this
633
   * to _bt_binsrch_insert() caller by returning -1, a sentinel value.  A
634
   * second call to _bt_binsrch_insert() can take place when its caller has
635
   * removed the dead item.
636
   */
637
0
  if (ItemIdIsDead(itemid))
638
0
    return -1;
639
640
  /* "high" is past end of posting list for loop invariant */
641
0
  low = 0;
642
0
  high = BTreeTupleGetNPosting(itup);
643
0
  Assert(high >= 2);
644
645
0
  while (high > low)
646
0
  {
647
0
    mid = low + ((high - low) / 2);
648
0
    res = ItemPointerCompare(key->scantid,
649
0
                 BTreeTupleGetPostingN(itup, mid));
650
651
0
    if (res > 0)
652
0
      low = mid + 1;
653
0
    else if (res < 0)
654
0
      high = mid;
655
0
    else
656
0
      return mid;
657
0
  }
658
659
  /* Exact match not found */
660
0
  return low;
661
0
}
662
663
/*----------
664
 *  _bt_compare() -- Compare insertion-type scankey to tuple on a page.
665
 *
666
 *  page/offnum: location of btree item to be compared to.
667
 *
668
 *    This routine returns:
669
 *      <0 if scankey < tuple at offnum;
670
 *       0 if scankey == tuple at offnum;
671
 *      >0 if scankey > tuple at offnum.
672
 *
673
 * NULLs in the keys are treated as sortable values.  Therefore
674
 * "equality" does not necessarily mean that the item should be returned
675
 * to the caller as a matching key.  Similarly, an insertion scankey
676
 * with its scantid set is treated as equal to a posting tuple whose TID
677
 * range overlaps with their scantid.  There generally won't be a
678
 * matching TID in the posting tuple, which caller must handle
679
 * themselves (e.g., by splitting the posting list tuple).
680
 *
681
 * CRUCIAL NOTE: on a non-leaf page, the first data key is assumed to be
682
 * "minus infinity": this routine will always claim it is less than the
683
 * scankey.  The actual key value stored is explicitly truncated to 0
684
 * attributes (explicitly minus infinity) with version 3+ indexes, but
685
 * that isn't relied upon.  This allows us to implement the Lehman and
686
 * Yao convention that the first down-link pointer is before the first
687
 * key.  See backend/access/nbtree/README for details.
688
 *----------
689
 */
690
int32
691
_bt_compare(Relation rel,
692
      BTScanInsert key,
693
      Page page,
694
      OffsetNumber offnum)
695
0
{
696
0
  TupleDesc itupdesc = RelationGetDescr(rel);
697
0
  BTPageOpaque opaque = BTPageGetOpaque(page);
698
0
  IndexTuple  itup;
699
0
  ItemPointer heapTid;
700
0
  ScanKey   scankey;
701
0
  int     ncmpkey;
702
0
  int     ntupatts;
703
0
  int32   result;
704
705
0
  Assert(_bt_check_natts(rel, key->heapkeyspace, page, offnum));
706
0
  Assert(key->keysz <= IndexRelationGetNumberOfKeyAttributes(rel));
707
0
  Assert(key->heapkeyspace || key->scantid == NULL);
708
709
  /*
710
   * Force result ">" if target item is first data item on an internal page
711
   * --- see NOTE above.
712
   */
713
0
  if (!P_ISLEAF(opaque) && offnum == P_FIRSTDATAKEY(opaque))
714
0
    return 1;
715
716
0
  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offnum));
717
0
  ntupatts = BTreeTupleGetNAtts(itup, rel);
718
719
  /*
720
   * The scan key is set up with the attribute number associated with each
721
   * term in the key.  It is important that, if the index is multi-key, the
722
   * scan contain the first k key attributes, and that they be in order.  If
723
   * you think about how multi-key ordering works, you'll understand why
724
   * this is.
725
   *
726
   * We don't test for violation of this condition here, however.  The
727
   * initial setup for the index scan had better have gotten it right (see
728
   * _bt_first).
729
   */
730
731
0
  ncmpkey = Min(ntupatts, key->keysz);
732
0
  Assert(key->heapkeyspace || ncmpkey == key->keysz);
733
0
  Assert(!BTreeTupleIsPosting(itup) || key->allequalimage);
734
0
  scankey = key->scankeys;
735
0
  for (int i = 1; i <= ncmpkey; i++)
736
0
  {
737
0
    Datum   datum;
738
0
    bool    isNull;
739
740
0
    datum = index_getattr(itup, scankey->sk_attno, itupdesc, &isNull);
741
742
0
    if (scankey->sk_flags & SK_ISNULL) /* key is NULL */
743
0
    {
744
0
      if (isNull)
745
0
        result = 0;   /* NULL "=" NULL */
746
0
      else if (scankey->sk_flags & SK_BT_NULLS_FIRST)
747
0
        result = -1; /* NULL "<" NOT_NULL */
748
0
      else
749
0
        result = 1;   /* NULL ">" NOT_NULL */
750
0
    }
751
0
    else if (isNull)   /* key is NOT_NULL and item is NULL */
752
0
    {
753
0
      if (scankey->sk_flags & SK_BT_NULLS_FIRST)
754
0
        result = 1;   /* NOT_NULL ">" NULL */
755
0
      else
756
0
        result = -1; /* NOT_NULL "<" NULL */
757
0
    }
758
0
    else
759
0
    {
760
      /*
761
       * The sk_func needs to be passed the index value as left arg and
762
       * the sk_argument as right arg (they might be of different
763
       * types).  Since it is convenient for callers to think of
764
       * _bt_compare as comparing the scankey to the index item, we have
765
       * to flip the sign of the comparison result.  (Unless it's a DESC
766
       * column, in which case we *don't* flip the sign.)
767
       */
768
0
      result = DatumGetInt32(FunctionCall2Coll(&scankey->sk_func,
769
0
                           scankey->sk_collation,
770
0
                           datum,
771
0
                           scankey->sk_argument));
772
773
0
      if (!(scankey->sk_flags & SK_BT_DESC))
774
0
        INVERT_COMPARE_RESULT(result);
775
0
    }
776
777
    /* if the keys are unequal, return the difference */
778
0
    if (result != 0)
779
0
      return result;
780
781
0
    scankey++;
782
0
  }
783
784
  /*
785
   * All non-truncated attributes (other than heap TID) were found to be
786
   * equal.  Treat truncated attributes as minus infinity when scankey has a
787
   * key attribute value that would otherwise be compared directly.
788
   *
789
   * Note: it doesn't matter if ntupatts includes non-key attributes;
790
   * scankey won't, so explicitly excluding non-key attributes isn't
791
   * necessary.
792
   */
793
0
  if (key->keysz > ntupatts)
794
0
    return 1;
795
796
  /*
797
   * Use the heap TID attribute and scantid to try to break the tie.  The
798
   * rules are the same as any other key attribute -- only the
799
   * representation differs.
800
   */
801
0
  heapTid = BTreeTupleGetHeapTID(itup);
802
0
  if (key->scantid == NULL)
803
0
  {
804
    /*
805
     * Forward scans have a scankey that is considered greater than a
806
     * truncated pivot tuple if and when the scankey has equal values for
807
     * attributes up to and including the least significant untruncated
808
     * attribute in tuple.  Even attributes that were omitted from the
809
     * scan key are considered greater than -inf truncated attributes.
810
     * (See _bt_binsrch for an explanation of our backward scan behavior.)
811
     *
812
     * For example, if an index has the minimum two attributes (single
813
     * user key attribute, plus heap TID attribute), and a page's high key
814
     * is ('foo', -inf), and scankey is ('foo', <omitted>), the search
815
     * will not descend to the page to the left.  The search will descend
816
     * right instead.  The truncated attribute in pivot tuple means that
817
     * all non-pivot tuples on the page to the left are strictly < 'foo',
818
     * so it isn't necessary to descend left.  In other words, search
819
     * doesn't have to descend left because it isn't interested in a match
820
     * that has a heap TID value of -inf.
821
     *
822
     * Note: the heap TID part of the test ensures that scankey is being
823
     * compared to a pivot tuple with one or more truncated -inf key
824
     * attributes.  The heap TID attribute is the last key attribute in
825
     * every index, of course, but other than that it isn't special.
826
     */
827
0
    if (!key->backward && key->keysz == ntupatts && heapTid == NULL &&
828
0
      key->heapkeyspace)
829
0
      return 1;
830
831
    /* All provided scankey arguments found to be equal */
832
0
    return 0;
833
0
  }
834
835
  /*
836
   * Treat truncated heap TID as minus infinity, since scankey has a key
837
   * attribute value (scantid) that would otherwise be compared directly
838
   */
839
0
  Assert(key->keysz == IndexRelationGetNumberOfKeyAttributes(rel));
840
0
  if (heapTid == NULL)
841
0
    return 1;
842
843
  /*
844
   * Scankey must be treated as equal to a posting list tuple if its scantid
845
   * value falls within the range of the posting list.  In all other cases
846
   * there can only be a single heap TID value, which is compared directly
847
   * with scantid.
848
   */
849
0
  Assert(ntupatts >= IndexRelationGetNumberOfKeyAttributes(rel));
850
0
  result = ItemPointerCompare(key->scantid, heapTid);
851
0
  if (result <= 0 || !BTreeTupleIsPosting(itup))
852
0
    return result;
853
0
  else
854
0
  {
855
0
    result = ItemPointerCompare(key->scantid,
856
0
                  BTreeTupleGetMaxHeapTID(itup));
857
0
    if (result > 0)
858
0
      return 1;
859
0
  }
860
861
0
  return 0;
862
0
}
863
864
/*
865
 *  _bt_first() -- Find the first item in a scan.
866
 *
867
 *    We need to be clever about the direction of scan, the search
868
 *    conditions, and the tree ordering.  We find the first item (or,
869
 *    if backwards scan, the last item) in the tree that satisfies the
870
 *    qualifications in the scan key.  On success exit, data about the
871
 *    matching tuple(s) on the page has been loaded into so->currPos.  We'll
872
 *    drop all locks and hold onto a pin on page's buffer, except during
873
 *    so->dropPin scans, when we drop both the lock and the pin.
874
 *    _bt_returnitem sets the next item to return to scan on success exit.
875
 *
876
 * If there are no matching items in the index, we return false, with no
877
 * pins or locks held.  so->currPos will remain invalid.
878
 *
879
 * Note that scan->keyData[], and the so->keyData[] scankey built from it,
880
 * are both search-type scankeys (see nbtree/README for more about this).
881
 * Within this routine, we build a temporary insertion-type scankey to use
882
 * in locating the scan start position.
883
 */
884
bool
885
_bt_first(IndexScanDesc scan, ScanDirection dir)
886
0
{
887
0
  Relation  rel = scan->indexRelation;
888
0
  BTScanOpaque so = (BTScanOpaque) scan->opaque;
889
0
  OffsetNumber offnum;
890
0
  BTScanInsertData inskey;
891
0
  ScanKey   startKeys[INDEX_MAX_KEYS];
892
0
  ScanKeyData notnullkey;
893
0
  int     keysz = 0;
894
0
  StrategyNumber strat_total = InvalidStrategy;
895
0
  BlockNumber blkno = InvalidBlockNumber,
896
0
        lastcurrblkno;
897
898
0
  Assert(!BTScanPosIsValid(so->currPos));
899
900
  /*
901
   * Examine the scan keys and eliminate any redundant keys; also mark the
902
   * keys that must be matched to continue the scan.
903
   */
904
0
  _bt_preprocess_keys(scan);
905
906
  /*
907
   * Quit now if _bt_preprocess_keys() discovered that the scan keys can
908
   * never be satisfied (eg, x == 1 AND x > 2).
909
   */
910
0
  if (!so->qual_ok)
911
0
  {
912
0
    Assert(!so->needPrimScan);
913
0
    _bt_parallel_done(scan);
914
0
    return false;
915
0
  }
916
917
  /*
918
   * If this is a parallel scan, we must seize the scan.  _bt_readfirstpage
919
   * will likely release the parallel scan later on.
920
   */
921
0
  if (scan->parallel_scan != NULL &&
922
0
    !_bt_parallel_seize(scan, &blkno, &lastcurrblkno, true))
923
0
    return false;
924
925
  /*
926
   * Initialize the scan's arrays (if any) for the current scan direction
927
   * (except when they were already set to later values as part of
928
   * scheduling the primitive index scan that is now underway)
929
   */
930
0
  if (so->numArrayKeys && !so->needPrimScan)
931
0
    _bt_start_array_keys(scan, dir);
932
933
0
  if (blkno != InvalidBlockNumber)
934
0
  {
935
    /*
936
     * We anticipated calling _bt_search, but another worker bet us to it.
937
     * _bt_readnextpage releases the scan for us (not _bt_readfirstpage).
938
     */
939
0
    Assert(scan->parallel_scan != NULL);
940
0
    Assert(!so->needPrimScan);
941
0
    Assert(blkno != P_NONE);
942
943
0
    if (!_bt_readnextpage(scan, blkno, lastcurrblkno, dir, true))
944
0
      return false;
945
946
0
    _bt_returnitem(scan, so);
947
0
    return true;
948
0
  }
949
950
  /*
951
   * Count an indexscan for stats, now that we know that we'll call
952
   * _bt_search/_bt_endpoint below
953
   */
954
0
  pgstat_count_index_scan(rel);
955
0
  if (scan->instrument)
956
0
    scan->instrument->nsearches++;
957
958
  /*----------
959
   * Examine the scan keys to discover where we need to start the scan.
960
   * The selected scan keys (at most one per index column) are remembered by
961
   * storing their addresses into the local startKeys[] array.  The final
962
   * startKeys[] entry's strategy is set in strat_total. (Actually, there
963
   * are a couple of cases where we force a less/more restrictive strategy.)
964
   *
965
   * We must use the key that was marked required (in the direction opposite
966
   * our own scan's) during preprocessing.  Each index attribute can only
967
   * have one such required key.  In general, the keys that we use to find
968
   * an initial position when scanning forwards are the same keys that end
969
   * the scan on the leaf level when scanning backwards (and vice-versa).
970
   *
971
   * When the scan keys include cross-type operators, _bt_preprocess_keys
972
   * may not be able to eliminate redundant keys; in such cases it will
973
   * arbitrarily pick a usable key for each attribute (and scan direction),
974
   * ensuring that there is no more than one key required in each direction.
975
   * We stop considering further keys once we reach the first nonrequired
976
   * key (which must come after all required keys), so this can't affect us.
977
   *
978
   * The required keys that we use as starting boundaries have to be =, >,
979
   * or >= keys for a forward scan or =, <, <= keys for a backwards scan.
980
   * We can use keys for multiple attributes so long as the prior attributes
981
   * had only =, >= (resp. =, <=) keys.  These rules are very similar to the
982
   * rules that preprocessing used to determine which keys to mark required.
983
   * We cannot always use every required key as a positioning key, though.
984
   * Skip arrays necessitate independently applying our own rules here.
985
   * Skip arrays are always generally considered = array keys, but we'll
986
   * nevertheless treat them as inequalities at certain points of the scan.
987
   * When that happens, it _might_ have implications for the number of
988
   * required keys that we can safely use for initial positioning purposes.
989
   *
990
   * For example, a forward scan with a skip array on its leading attribute
991
   * (with no low_compare/high_compare) will have at least two required scan
992
   * keys, but we won't use any of them as boundary keys during the scan's
993
   * initial call here.  Our positioning key during the first call here can
994
   * be thought of as representing "> -infinity".  Similarly, if such a skip
995
   * array's low_compare is "a > 'foo'", then we position using "a > 'foo'"
996
   * during the scan's initial call here; a lower-order key such as "b = 42"
997
   * can't be used until the "a" array advances beyond MINVAL/low_compare.
998
   *
999
   * On the other hand, if such a skip array's low_compare was "a >= 'foo'",
1000
   * then we _can_ use "a >= 'foo' AND b = 42" during the initial call here.
1001
   * A subsequent call here might have us use "a = 'fop' AND b = 42".  Note
1002
   * that we treat = and >= as equivalent when scanning forwards (just as we
1003
   * treat = and <= as equivalent when scanning backwards).  We effectively
1004
   * do the same thing (though with a distinct "a" element/value) each time.
1005
   *
1006
   * All keys (with the exception of SK_SEARCHNULL keys and SK_BT_SKIP
1007
   * array keys whose array is "null_elem=true") imply a NOT NULL qualifier.
1008
   * If the index stores nulls at the end of the index we'll be starting
1009
   * from, and we have no boundary key for the column (which means the key
1010
   * we deduced NOT NULL from is an inequality key that constrains the other
1011
   * end of the index), then we cons up an explicit SK_SEARCHNOTNULL key to
1012
   * use as a boundary key.  If we didn't do this, we might find ourselves
1013
   * traversing a lot of null entries at the start of the scan.
1014
   *
1015
   * In this loop, row-comparison keys are treated the same as keys on their
1016
   * first (leftmost) columns.  We'll add all lower-order columns of the row
1017
   * comparison that were marked required during preprocessing below.
1018
   *
1019
   * _bt_advance_array_keys needs to know exactly how we'll reposition the
1020
   * scan (should it opt to schedule another primitive index scan).  It is
1021
   * critical that primscans only be scheduled when they'll definitely make
1022
   * some useful progress.  _bt_advance_array_keys does this by calling
1023
   * _bt_checkkeys routines that report whether a tuple is past the end of
1024
   * matches for the scan's keys (given the scan's current array elements).
1025
   * If the page's final tuple is "after the end of matches" for a scan that
1026
   * uses the *opposite* scan direction, then it must follow that it's also
1027
   * "before the start of matches" for the actual current scan direction.
1028
   * It is therefore essential that all of our initial positioning rules are
1029
   * symmetric with _bt_checkkeys's corresponding continuescan=false rule.
1030
   * If you update anything here, _bt_checkkeys/_bt_advance_array_keys might
1031
   * need to be kept in sync.
1032
   *----------
1033
   */
1034
0
  if (so->numberOfKeys > 0)
1035
0
  {
1036
0
    AttrNumber  curattr;
1037
0
    ScanKey   bkey;
1038
0
    ScanKey   impliesNN;
1039
0
    ScanKey   cur;
1040
1041
    /*
1042
     * bkey will be set to the key that preprocessing left behind as the
1043
     * boundary key for this attribute, in this scan direction (if any)
1044
     */
1045
0
    cur = so->keyData;
1046
0
    curattr = 1;
1047
0
    bkey = NULL;
1048
    /* Also remember any scankey that implies a NOT NULL constraint */
1049
0
    impliesNN = NULL;
1050
1051
    /*
1052
     * Loop iterates from 0 to numberOfKeys inclusive; we use the last
1053
     * pass to handle after-last-key processing.  Actual exit from the
1054
     * loop is at one of the "break" statements below.
1055
     */
1056
0
    for (int i = 0;; cur++, i++)
1057
0
    {
1058
0
      if (i >= so->numberOfKeys || cur->sk_attno != curattr)
1059
0
      {
1060
        /* Done looking for the curattr boundary key */
1061
0
        Assert(bkey == NULL ||
1062
0
             (bkey->sk_attno == curattr &&
1063
0
            (bkey->sk_flags & (SK_BT_REQFWD | SK_BT_REQBKWD))));
1064
0
        Assert(impliesNN == NULL ||
1065
0
             (impliesNN->sk_attno == curattr &&
1066
0
            (impliesNN->sk_flags & (SK_BT_REQFWD | SK_BT_REQBKWD))));
1067
1068
        /*
1069
         * If this is a scan key for a skip array whose current
1070
         * element is MINVAL, choose low_compare (when scanning
1071
         * backwards it'll be MAXVAL, and we'll choose high_compare).
1072
         *
1073
         * Note: if the array's low_compare key makes 'bkey' NULL,
1074
         * then we behave as if the array's first element is -inf,
1075
         * except when !array->null_elem implies a usable NOT NULL
1076
         * constraint.
1077
         */
1078
0
        if (bkey != NULL &&
1079
0
          (bkey->sk_flags & (SK_BT_MINVAL | SK_BT_MAXVAL)))
1080
0
        {
1081
0
          int     ikey = bkey - so->keyData;
1082
0
          ScanKey   skipequalitykey = bkey;
1083
0
          BTArrayKeyInfo *array = NULL;
1084
1085
0
          for (int arridx = 0; arridx < so->numArrayKeys; arridx++)
1086
0
          {
1087
0
            array = &so->arrayKeys[arridx];
1088
0
            if (array->scan_key == ikey)
1089
0
              break;
1090
0
          }
1091
1092
0
          if (ScanDirectionIsForward(dir))
1093
0
          {
1094
0
            Assert(!(skipequalitykey->sk_flags & SK_BT_MAXVAL));
1095
0
            bkey = array->low_compare;
1096
0
          }
1097
0
          else
1098
0
          {
1099
0
            Assert(!(skipequalitykey->sk_flags & SK_BT_MINVAL));
1100
0
            bkey = array->high_compare;
1101
0
          }
1102
1103
0
          Assert(bkey == NULL ||
1104
0
               bkey->sk_attno == skipequalitykey->sk_attno);
1105
1106
0
          if (!array->null_elem)
1107
0
            impliesNN = skipequalitykey;
1108
0
          else
1109
0
            Assert(bkey == NULL && impliesNN == NULL);
1110
0
        }
1111
1112
        /*
1113
         * If we didn't find a usable boundary key, see if we can
1114
         * deduce a NOT NULL key
1115
         */
1116
0
        if (bkey == NULL && impliesNN != NULL &&
1117
0
          ((impliesNN->sk_flags & SK_BT_NULLS_FIRST) ?
1118
0
           ScanDirectionIsForward(dir) :
1119
0
           ScanDirectionIsBackward(dir)))
1120
0
        {
1121
          /* Final startKeys[] entry will be deduced NOT NULL key */
1122
0
          bkey = &notnullkey;
1123
0
          ScanKeyEntryInitialize(bkey,
1124
0
                       (SK_SEARCHNOTNULL | SK_ISNULL |
1125
0
                      (impliesNN->sk_flags &
1126
0
                       (SK_BT_DESC | SK_BT_NULLS_FIRST))),
1127
0
                       curattr,
1128
0
                       ScanDirectionIsForward(dir) ?
1129
0
                       BTGreaterStrategyNumber : BTLessStrategyNumber,
1130
0
                       InvalidOid,
1131
0
                       InvalidOid,
1132
0
                       InvalidOid,
1133
0
                       (Datum) 0);
1134
0
        }
1135
1136
        /*
1137
         * If preprocessing didn't leave a usable boundary key, quit;
1138
         * else save the boundary key pointer in startKeys[]
1139
         */
1140
0
        if (bkey == NULL)
1141
0
          break;
1142
0
        startKeys[keysz++] = bkey;
1143
1144
        /*
1145
         * We can only consider adding more boundary keys when the one
1146
         * that we just chose to add uses either the = or >= strategy
1147
         * (during backwards scans we can only do so when the key that
1148
         * we just added to startKeys[] uses the = or <= strategy)
1149
         */
1150
0
        strat_total = bkey->sk_strategy;
1151
0
        if (strat_total == BTGreaterStrategyNumber ||
1152
0
          strat_total == BTLessStrategyNumber)
1153
0
          break;
1154
1155
        /*
1156
         * If the key that we just added to startKeys[] is a skip
1157
         * array = key whose current element is marked NEXT or PRIOR,
1158
         * make strat_total > or < (and stop adding boundary keys).
1159
         * This can only happen with opclasses that lack skip support.
1160
         */
1161
0
        if (bkey->sk_flags & (SK_BT_NEXT | SK_BT_PRIOR))
1162
0
        {
1163
0
          Assert(bkey->sk_flags & SK_BT_SKIP);
1164
0
          Assert(strat_total == BTEqualStrategyNumber);
1165
1166
0
          if (ScanDirectionIsForward(dir))
1167
0
          {
1168
0
            Assert(!(bkey->sk_flags & SK_BT_PRIOR));
1169
0
            strat_total = BTGreaterStrategyNumber;
1170
0
          }
1171
0
          else
1172
0
          {
1173
0
            Assert(!(bkey->sk_flags & SK_BT_NEXT));
1174
0
            strat_total = BTLessStrategyNumber;
1175
0
          }
1176
1177
          /*
1178
           * We're done.  We'll never find an exact = match for a
1179
           * NEXT or PRIOR sentinel sk_argument value.  There's no
1180
           * sense in trying to add more keys to startKeys[].
1181
           */
1182
0
          break;
1183
0
        }
1184
1185
        /*
1186
         * Done if that was the last scan key output by preprocessing.
1187
         * Also done if we've now examined all keys marked required.
1188
         */
1189
0
        if (i >= so->numberOfKeys ||
1190
0
          !(cur->sk_flags & (SK_BT_REQFWD | SK_BT_REQBKWD)))
1191
0
          break;
1192
1193
        /*
1194
         * Reset for next attr.
1195
         */
1196
0
        Assert(cur->sk_attno == curattr + 1);
1197
0
        curattr = cur->sk_attno;
1198
0
        bkey = NULL;
1199
0
        impliesNN = NULL;
1200
0
      }
1201
1202
      /*
1203
       * If we've located the starting boundary key for curattr, we have
1204
       * no interest in curattr's other required key
1205
       */
1206
0
      if (bkey != NULL)
1207
0
        continue;
1208
1209
      /*
1210
       * Is this key the starting boundary key for curattr?
1211
       *
1212
       * If not, does it imply a NOT NULL constraint?  (Because
1213
       * SK_SEARCHNULL keys are always assigned BTEqualStrategyNumber,
1214
       * *any* inequality key works for that; we need not test.)
1215
       */
1216
0
      switch (cur->sk_strategy)
1217
0
      {
1218
0
        case BTLessStrategyNumber:
1219
0
        case BTLessEqualStrategyNumber:
1220
0
          if (ScanDirectionIsBackward(dir))
1221
0
            bkey = cur;
1222
0
          else if (impliesNN == NULL)
1223
0
            impliesNN = cur;
1224
0
          break;
1225
0
        case BTEqualStrategyNumber:
1226
0
          bkey = cur;
1227
0
          break;
1228
0
        case BTGreaterEqualStrategyNumber:
1229
0
        case BTGreaterStrategyNumber:
1230
0
          if (ScanDirectionIsForward(dir))
1231
0
            bkey = cur;
1232
0
          else if (impliesNN == NULL)
1233
0
            impliesNN = cur;
1234
0
          break;
1235
0
      }
1236
0
    }
1237
0
  }
1238
1239
  /*
1240
   * If we found no usable boundary keys, we have to start from one end of
1241
   * the tree.  Walk down that edge to the first or last key, and scan from
1242
   * there.
1243
   *
1244
   * Note: calls _bt_readfirstpage for us, which releases the parallel scan.
1245
   */
1246
0
  if (keysz == 0)
1247
0
    return _bt_endpoint(scan, dir);
1248
1249
  /*
1250
   * We want to start the scan somewhere within the index.  Set up an
1251
   * insertion scankey we can use to search for the boundary point we
1252
   * identified above.  The insertion scankey is built using the keys
1253
   * identified by startKeys[].  (Remaining insertion scankey fields are
1254
   * initialized after initial-positioning scan keys are finalized.)
1255
   */
1256
0
  Assert(keysz <= INDEX_MAX_KEYS);
1257
0
  for (int i = 0; i < keysz; i++)
1258
0
  {
1259
0
    ScanKey   bkey = startKeys[i];
1260
1261
0
    Assert(bkey->sk_attno == i + 1);
1262
1263
0
    if (bkey->sk_flags & SK_ROW_HEADER)
1264
0
    {
1265
      /*
1266
       * Row comparison header: look to the first row member instead
1267
       */
1268
0
      ScanKey   subkey = (ScanKey) DatumGetPointer(bkey->sk_argument);
1269
0
      bool    loosen_strat = false,
1270
0
            tighten_strat = false;
1271
1272
      /*
1273
       * Cannot be a NULL in the first row member: _bt_preprocess_keys
1274
       * would've marked the qual as unsatisfiable, preventing us from
1275
       * ever getting this far
1276
       */
1277
0
      Assert(subkey->sk_flags & SK_ROW_MEMBER);
1278
0
      Assert(subkey->sk_attno == bkey->sk_attno);
1279
0
      Assert(!(subkey->sk_flags & SK_ISNULL));
1280
1281
      /*
1282
       * This is either a > or >= key (during backwards scans it is
1283
       * either < or <=) that was marked required during preprocessing.
1284
       * Later so->keyData[] keys can't have been marked required, so
1285
       * our row compare header key must be the final startKeys[] entry.
1286
       */
1287
0
      Assert(subkey->sk_flags & (SK_BT_REQFWD | SK_BT_REQBKWD));
1288
0
      Assert(subkey->sk_strategy == bkey->sk_strategy);
1289
0
      Assert(subkey->sk_strategy == strat_total);
1290
0
      Assert(i == keysz - 1);
1291
1292
      /*
1293
       * The member scankeys are already in insertion format (ie, they
1294
       * have sk_func = 3-way-comparison function)
1295
       */
1296
0
      memcpy(inskey.scankeys + i, subkey, sizeof(ScanKeyData));
1297
1298
      /*
1299
       * Now look to later row compare members.
1300
       *
1301
       * If there's an "index attribute gap" between two row compare
1302
       * members, the second member won't have been marked required, and
1303
       * so can't be used as a starting boundary key here.  The part of
1304
       * the row comparison that we do still use has to be treated as a
1305
       * ">=" or "<=" condition.  For example, a qual "(a, c) > (1, 42)"
1306
       * with an omitted intervening index attribute "b" will use an
1307
       * insertion scan key "a >= 1".  Even the first "a = 1" tuple on
1308
       * the leaf level might satisfy the row compare qual.
1309
       *
1310
       * We're able to use a _more_ restrictive strategy when we reach a
1311
       * NULL row compare member, since they're always unsatisfiable.
1312
       * For example, a qual "(a, b, c) >= (1, NULL, 77)" will use an
1313
       * insertion scan key "a > 1".  All tuples where "a = 1" cannot
1314
       * possibly satisfy the row compare qual, so this is safe.
1315
       */
1316
0
      Assert(!(subkey->sk_flags & SK_ROW_END));
1317
0
      for (;;)
1318
0
      {
1319
0
        subkey++;
1320
0
        Assert(subkey->sk_flags & SK_ROW_MEMBER);
1321
1322
0
        if (subkey->sk_flags & SK_ISNULL)
1323
0
        {
1324
          /*
1325
           * NULL member key, can only use earlier keys.
1326
           *
1327
           * We deliberately avoid checking if this key is marked
1328
           * required.  All earlier keys are required, and this key
1329
           * is unsatisfiable either way, so we can't miss anything.
1330
           */
1331
0
          tighten_strat = true;
1332
0
          break;
1333
0
        }
1334
1335
0
        if (!(subkey->sk_flags & (SK_BT_REQFWD | SK_BT_REQBKWD)))
1336
0
        {
1337
          /* nonrequired member key, can only use earlier keys */
1338
0
          loosen_strat = true;
1339
0
          break;
1340
0
        }
1341
1342
0
        Assert(subkey->sk_attno == keysz + 1);
1343
0
        Assert(subkey->sk_strategy == bkey->sk_strategy);
1344
0
        Assert(keysz < INDEX_MAX_KEYS);
1345
1346
0
        memcpy(inskey.scankeys + keysz, subkey, sizeof(ScanKeyData));
1347
0
        keysz++;
1348
1349
0
        if (subkey->sk_flags & SK_ROW_END)
1350
0
          break;
1351
0
      }
1352
0
      Assert(!(loosen_strat && tighten_strat));
1353
0
      if (loosen_strat)
1354
0
      {
1355
        /* Use less restrictive strategy (and fewer member keys) */
1356
0
        switch (strat_total)
1357
0
        {
1358
0
          case BTLessStrategyNumber:
1359
0
            strat_total = BTLessEqualStrategyNumber;
1360
0
            break;
1361
0
          case BTGreaterStrategyNumber:
1362
0
            strat_total = BTGreaterEqualStrategyNumber;
1363
0
            break;
1364
0
        }
1365
0
      }
1366
0
      if (tighten_strat)
1367
0
      {
1368
        /* Use more restrictive strategy (and fewer member keys) */
1369
0
        switch (strat_total)
1370
0
        {
1371
0
          case BTLessEqualStrategyNumber:
1372
0
            strat_total = BTLessStrategyNumber;
1373
0
            break;
1374
0
          case BTGreaterEqualStrategyNumber:
1375
0
            strat_total = BTGreaterStrategyNumber;
1376
0
            break;
1377
0
        }
1378
0
      }
1379
1380
      /* Done (row compare header key is always last startKeys[] key) */
1381
0
      break;
1382
0
    }
1383
1384
    /*
1385
     * Ordinary comparison key/search-style key.
1386
     *
1387
     * Transform the search-style scan key to an insertion scan key by
1388
     * replacing the sk_func with the appropriate btree 3-way-comparison
1389
     * function.
1390
     *
1391
     * If scankey operator is not a cross-type comparison, we can use the
1392
     * cached comparison function; otherwise gotta look it up in the
1393
     * catalogs.  (That can't lead to infinite recursion, since no
1394
     * indexscan initiated by syscache lookup will use cross-data-type
1395
     * operators.)
1396
     *
1397
     * We support the convention that sk_subtype == InvalidOid means the
1398
     * opclass input type; this hack simplifies life for ScanKeyInit().
1399
     */
1400
0
    if (bkey->sk_subtype == rel->rd_opcintype[i] ||
1401
0
      bkey->sk_subtype == InvalidOid)
1402
0
    {
1403
0
      FmgrInfo   *procinfo;
1404
1405
0
      procinfo = index_getprocinfo(rel, bkey->sk_attno, BTORDER_PROC);
1406
0
      ScanKeyEntryInitializeWithInfo(inskey.scankeys + i,
1407
0
                       bkey->sk_flags,
1408
0
                       bkey->sk_attno,
1409
0
                       InvalidStrategy,
1410
0
                       bkey->sk_subtype,
1411
0
                       bkey->sk_collation,
1412
0
                       procinfo,
1413
0
                       bkey->sk_argument);
1414
0
    }
1415
0
    else
1416
0
    {
1417
0
      RegProcedure cmp_proc;
1418
1419
0
      cmp_proc = get_opfamily_proc(rel->rd_opfamily[i],
1420
0
                     rel->rd_opcintype[i],
1421
0
                     bkey->sk_subtype, BTORDER_PROC);
1422
0
      if (!RegProcedureIsValid(cmp_proc))
1423
0
        elog(ERROR, "missing support function %d(%u,%u) for attribute %d of index \"%s\"",
1424
0
           BTORDER_PROC, rel->rd_opcintype[i], bkey->sk_subtype,
1425
0
           bkey->sk_attno, RelationGetRelationName(rel));
1426
0
      ScanKeyEntryInitialize(inskey.scankeys + i,
1427
0
                   bkey->sk_flags,
1428
0
                   bkey->sk_attno,
1429
0
                   InvalidStrategy,
1430
0
                   bkey->sk_subtype,
1431
0
                   bkey->sk_collation,
1432
0
                   cmp_proc,
1433
0
                   bkey->sk_argument);
1434
0
    }
1435
0
  }
1436
1437
  /*----------
1438
   * Examine the selected initial-positioning strategy to determine exactly
1439
   * where we need to start the scan, and set flag variables to control the
1440
   * initial descent by _bt_search (and our _bt_binsrch call for the leaf
1441
   * page _bt_search returns).
1442
   *----------
1443
   */
1444
0
  _bt_metaversion(rel, &inskey.heapkeyspace, &inskey.allequalimage);
1445
0
  inskey.anynullkeys = false; /* unused */
1446
0
  inskey.scantid = NULL;
1447
0
  inskey.keysz = keysz;
1448
0
  switch (strat_total)
1449
0
  {
1450
0
    case BTLessStrategyNumber:
1451
1452
0
      inskey.nextkey = false;
1453
0
      inskey.backward = true;
1454
0
      break;
1455
1456
0
    case BTLessEqualStrategyNumber:
1457
1458
0
      inskey.nextkey = true;
1459
0
      inskey.backward = true;
1460
0
      break;
1461
1462
0
    case BTEqualStrategyNumber:
1463
1464
      /*
1465
       * If a backward scan was specified, need to start with last equal
1466
       * item not first one.
1467
       */
1468
0
      if (ScanDirectionIsBackward(dir))
1469
0
      {
1470
        /*
1471
         * This is the same as the <= strategy
1472
         */
1473
0
        inskey.nextkey = true;
1474
0
        inskey.backward = true;
1475
0
      }
1476
0
      else
1477
0
      {
1478
        /*
1479
         * This is the same as the >= strategy
1480
         */
1481
0
        inskey.nextkey = false;
1482
0
        inskey.backward = false;
1483
0
      }
1484
0
      break;
1485
1486
0
    case BTGreaterEqualStrategyNumber:
1487
1488
      /*
1489
       * Find first item >= scankey
1490
       */
1491
0
      inskey.nextkey = false;
1492
0
      inskey.backward = false;
1493
0
      break;
1494
1495
0
    case BTGreaterStrategyNumber:
1496
1497
      /*
1498
       * Find first item > scankey
1499
       */
1500
0
      inskey.nextkey = true;
1501
0
      inskey.backward = false;
1502
0
      break;
1503
1504
0
    default:
1505
      /* can't get here, but keep compiler quiet */
1506
0
      elog(ERROR, "unrecognized strat_total: %d", (int) strat_total);
1507
0
      return false;
1508
0
  }
1509
1510
  /*
1511
   * Use the manufactured insertion scan key to descend the tree and
1512
   * position ourselves on the target leaf page.
1513
   */
1514
0
  Assert(ScanDirectionIsBackward(dir) == inskey.backward);
1515
0
  _bt_search(rel, NULL, &inskey, &so->currPos.buf, BT_READ, false);
1516
1517
0
  if (!BufferIsValid(so->currPos.buf))
1518
0
  {
1519
0
    Assert(!so->needPrimScan);
1520
1521
#ifdef USE_INJECTION_POINTS
1522
    if (!IsCatalogRelation(rel))
1523
      INJECTION_POINT("nbtree-first-empty", NULL);
1524
#endif
1525
1526
    /*
1527
     * We only get here if the index is completely empty. Lock relation
1528
     * because nothing finer to lock exists.  Without a buffer lock, it's
1529
     * possible for another transaction to insert data between
1530
     * _bt_search() and PredicateLockRelation().  We have to try again
1531
     * after taking the relation-level predicate lock, to close a narrow
1532
     * window where we wouldn't scan concurrently inserted tuples, but the
1533
     * writer wouldn't see our predicate lock.
1534
     */
1535
0
    if (IsolationIsSerializable())
1536
0
    {
1537
0
      PredicateLockRelation(rel, scan->xs_snapshot);
1538
0
      _bt_search(rel, NULL, &inskey, &so->currPos.buf, BT_READ, false);
1539
0
    }
1540
1541
0
    if (!BufferIsValid(so->currPos.buf))
1542
0
    {
1543
0
      _bt_parallel_done(scan);
1544
0
      return false;
1545
0
    }
1546
0
  }
1547
1548
  /* position to the precise item on the page */
1549
0
  offnum = _bt_binsrch(rel, &inskey, so->currPos.buf);
1550
1551
  /*
1552
   * Now load data from the first page of the scan (usually the page
1553
   * currently in so->currPos.buf).
1554
   *
1555
   * If inskey.nextkey = false and inskey.backward = false, offnum is
1556
   * positioned at the first non-pivot tuple >= inskey.scankeys.
1557
   *
1558
   * If inskey.nextkey = false and inskey.backward = true, offnum is
1559
   * positioned at the last non-pivot tuple < inskey.scankeys.
1560
   *
1561
   * If inskey.nextkey = true and inskey.backward = false, offnum is
1562
   * positioned at the first non-pivot tuple > inskey.scankeys.
1563
   *
1564
   * If inskey.nextkey = true and inskey.backward = true, offnum is
1565
   * positioned at the last non-pivot tuple <= inskey.scankeys.
1566
   *
1567
   * It's possible that _bt_binsrch returned an offnum that is out of bounds
1568
   * for the page.  For example, when inskey is both < the leaf page's high
1569
   * key and > all of its non-pivot tuples, offnum will be "maxoff + 1".
1570
   */
1571
0
  if (!_bt_readfirstpage(scan, offnum, dir))
1572
0
    return false;
1573
1574
0
  _bt_returnitem(scan, so);
1575
0
  return true;
1576
0
}
1577
1578
/*
1579
 *  _bt_next() -- Get the next item in a scan.
1580
 *
1581
 *    On entry, so->currPos describes the current page, which may be pinned
1582
 *    but is not locked, and so->currPos.itemIndex identifies which item was
1583
 *    previously returned.
1584
 *
1585
 *    On success exit, so->currPos is updated as needed, and _bt_returnitem
1586
 *    sets the next item to return to the scan.  so->currPos remains valid.
1587
 *
1588
 *    On failure exit (no more tuples), we invalidate so->currPos.  It'll
1589
 *    still be possible for the scan to return tuples by changing direction,
1590
 *    though we'll need to call _bt_first anew in that other direction.
1591
 */
1592
bool
1593
_bt_next(IndexScanDesc scan, ScanDirection dir)
1594
0
{
1595
0
  BTScanOpaque so = (BTScanOpaque) scan->opaque;
1596
1597
0
  Assert(BTScanPosIsValid(so->currPos));
1598
1599
  /*
1600
   * Advance to next tuple on current page; or if there's no more, try to
1601
   * step to the next page with data.
1602
   */
1603
0
  if (ScanDirectionIsForward(dir))
1604
0
  {
1605
0
    if (++so->currPos.itemIndex > so->currPos.lastItem)
1606
0
    {
1607
0
      if (!_bt_steppage(scan, dir))
1608
0
        return false;
1609
0
    }
1610
0
  }
1611
0
  else
1612
0
  {
1613
0
    if (--so->currPos.itemIndex < so->currPos.firstItem)
1614
0
    {
1615
0
      if (!_bt_steppage(scan, dir))
1616
0
        return false;
1617
0
    }
1618
0
  }
1619
1620
0
  _bt_returnitem(scan, so);
1621
0
  return true;
1622
0
}
1623
1624
/*
1625
 * Return the index item from so->currPos.items[so->currPos.itemIndex] to the
1626
 * index scan by setting the relevant fields in caller's index scan descriptor
1627
 */
1628
static inline void
1629
_bt_returnitem(IndexScanDesc scan, BTScanOpaque so)
1630
0
{
1631
0
  BTScanPosItem *currItem = &so->currPos.items[so->currPos.itemIndex];
1632
1633
  /* Most recent _bt_readpage must have succeeded */
1634
0
  Assert(BTScanPosIsValid(so->currPos));
1635
0
  Assert(so->currPos.itemIndex >= so->currPos.firstItem);
1636
0
  Assert(so->currPos.itemIndex <= so->currPos.lastItem);
1637
1638
  /* Return next item, per amgettuple contract */
1639
0
  scan->xs_heaptid = currItem->heapTid;
1640
0
  if (so->currTuples)
1641
0
    scan->xs_itup = (IndexTuple) (so->currTuples + currItem->tupleOffset);
1642
0
}
1643
1644
/*
1645
 *  _bt_steppage() -- Step to next page containing valid data for scan
1646
 *
1647
 * Wrapper on _bt_readnextpage that performs final steps for the current page.
1648
 *
1649
 * On entry, so->currPos must be valid.  Its buffer will be pinned, though
1650
 * never locked. (Actually, when so->dropPin there won't even be a pin held,
1651
 * though so->currPos.currPage must still be set to a valid block number.)
1652
 */
1653
static bool
1654
_bt_steppage(IndexScanDesc scan, ScanDirection dir)
1655
0
{
1656
0
  BTScanOpaque so = (BTScanOpaque) scan->opaque;
1657
0
  BlockNumber blkno,
1658
0
        lastcurrblkno;
1659
1660
0
  Assert(BTScanPosIsValid(so->currPos));
1661
1662
  /* Before leaving current page, deal with any killed items */
1663
0
  if (so->numKilled > 0)
1664
0
    _bt_killitems(scan);
1665
1666
  /*
1667
   * Before we modify currPos, make a copy of the page data if there was a
1668
   * mark position that needs it.
1669
   */
1670
0
  if (so->markItemIndex >= 0)
1671
0
  {
1672
    /* bump pin on current buffer for assignment to mark buffer */
1673
0
    if (BTScanPosIsPinned(so->currPos))
1674
0
      IncrBufferRefCount(so->currPos.buf);
1675
0
    memcpy(&so->markPos, &so->currPos,
1676
0
         offsetof(BTScanPosData, items[1]) +
1677
0
         so->currPos.lastItem * sizeof(BTScanPosItem));
1678
0
    if (so->markTuples)
1679
0
      memcpy(so->markTuples, so->currTuples,
1680
0
           so->currPos.nextTupleOffset);
1681
0
    so->markPos.itemIndex = so->markItemIndex;
1682
0
    so->markItemIndex = -1;
1683
1684
    /*
1685
     * If we're just about to start the next primitive index scan
1686
     * (possible with a scan that has arrays keys, and needs to skip to
1687
     * continue in the current scan direction), moreLeft/moreRight only
1688
     * indicate the end of the current primitive index scan.  They must
1689
     * never be taken to indicate that the top-level index scan has ended
1690
     * (that would be wrong).
1691
     *
1692
     * We could handle this case by treating the current array keys as
1693
     * markPos state.  But depending on the current array state like this
1694
     * would add complexity.  Instead, we just unset markPos's copy of
1695
     * moreRight or moreLeft (whichever might be affected), while making
1696
     * btrestrpos reset the scan's arrays to their initial scan positions.
1697
     * In effect, btrestrpos leaves advancing the arrays up to the first
1698
     * _bt_readpage call (that takes place after it has restored markPos).
1699
     */
1700
0
    if (so->needPrimScan)
1701
0
    {
1702
0
      if (ScanDirectionIsForward(so->currPos.dir))
1703
0
        so->markPos.moreRight = true;
1704
0
      else
1705
0
        so->markPos.moreLeft = true;
1706
0
    }
1707
1708
    /* mark/restore not supported by parallel scans */
1709
0
    Assert(!scan->parallel_scan);
1710
0
  }
1711
1712
0
  BTScanPosUnpinIfPinned(so->currPos);
1713
1714
  /* Walk to the next page with data */
1715
0
  if (ScanDirectionIsForward(dir))
1716
0
    blkno = so->currPos.nextPage;
1717
0
  else
1718
0
    blkno = so->currPos.prevPage;
1719
0
  lastcurrblkno = so->currPos.currPage;
1720
1721
  /*
1722
   * Cancel primitive index scans that were scheduled when the call to
1723
   * _bt_readpage for currPos happened to use the opposite direction to the
1724
   * one that we're stepping in now.  (It's okay to leave the scan's array
1725
   * keys as-is, since the next _bt_readpage will advance them.)
1726
   */
1727
0
  if (so->currPos.dir != dir)
1728
0
    so->needPrimScan = false;
1729
1730
0
  return _bt_readnextpage(scan, blkno, lastcurrblkno, dir, false);
1731
0
}
1732
1733
/*
1734
 *  _bt_readfirstpage() -- Read first page containing valid data for _bt_first
1735
 *
1736
 * _bt_first caller passes us an offnum returned by _bt_binsrch, which might
1737
 * be an out of bounds offnum such as "maxoff + 1" in certain corner cases.
1738
 * When we're passed an offnum past the end of the page, we might still manage
1739
 * to stop the scan on this page by calling _bt_checkkeys against the high
1740
 * key.  See _bt_readpage for full details.
1741
 *
1742
 * On entry, so->currPos must be pinned and locked (so offnum stays valid).
1743
 * Parallel scan callers must have seized the scan before calling here.
1744
 *
1745
 * On exit, we'll have updated so->currPos and retained locks and pins
1746
 * according to the same rules as those laid out for _bt_readnextpage exit.
1747
 * Like _bt_readnextpage, our return value indicates if there are any matching
1748
 * records in the given direction.
1749
 *
1750
 * We always release the scan for a parallel scan caller, regardless of
1751
 * success or failure; we'll call _bt_parallel_release as soon as possible.
1752
 */
1753
static bool
1754
_bt_readfirstpage(IndexScanDesc scan, OffsetNumber offnum, ScanDirection dir)
1755
0
{
1756
0
  BTScanOpaque so = (BTScanOpaque) scan->opaque;
1757
1758
0
  so->numKilled = 0;      /* just paranoia */
1759
0
  so->markItemIndex = -1;   /* ditto */
1760
1761
  /* Initialize so->currPos for the first page (page in so->currPos.buf) */
1762
0
  if (so->needPrimScan)
1763
0
  {
1764
0
    Assert(so->numArrayKeys);
1765
1766
0
    so->currPos.moreLeft = true;
1767
0
    so->currPos.moreRight = true;
1768
0
    so->needPrimScan = false;
1769
0
  }
1770
0
  else if (ScanDirectionIsForward(dir))
1771
0
  {
1772
0
    so->currPos.moreLeft = false;
1773
0
    so->currPos.moreRight = true;
1774
0
  }
1775
0
  else
1776
0
  {
1777
0
    so->currPos.moreLeft = true;
1778
0
    so->currPos.moreRight = false;
1779
0
  }
1780
1781
  /*
1782
   * Attempt to load matching tuples from the first page.
1783
   *
1784
   * Note that _bt_readpage will finish initializing the so->currPos fields.
1785
   * _bt_readpage also releases parallel scan (even when it returns false).
1786
   */
1787
0
  if (_bt_readpage(scan, dir, offnum, true))
1788
0
  {
1789
0
    Relation  rel = scan->indexRelation;
1790
1791
    /*
1792
     * _bt_readpage succeeded.  Drop the lock (and maybe the pin) on
1793
     * so->currPos.buf in preparation for btgettuple returning tuples.
1794
     */
1795
0
    Assert(BTScanPosIsPinned(so->currPos));
1796
0
    _bt_drop_lock_and_maybe_pin(rel, so);
1797
0
    return true;
1798
0
  }
1799
1800
  /* There's no actually-matching data on the page in so->currPos.buf */
1801
0
  _bt_unlockbuf(scan->indexRelation, so->currPos.buf);
1802
1803
  /* Call _bt_readnextpage using its _bt_steppage wrapper function */
1804
0
  if (!_bt_steppage(scan, dir))
1805
0
    return false;
1806
1807
  /* _bt_readpage for a later page (now in so->currPos) succeeded */
1808
0
  return true;
1809
0
}
1810
1811
/*
1812
 *  _bt_readnextpage() -- Read next page containing valid data for _bt_next
1813
 *
1814
 * Caller's blkno is the next interesting page's link, taken from either the
1815
 * previously-saved right link or left link.  lastcurrblkno is the page that
1816
 * was current at the point where the blkno link was saved, which we use to
1817
 * reason about concurrent page splits/page deletions during backwards scans.
1818
 * In the common case where seized=false, blkno is either so->currPos.nextPage
1819
 * or so->currPos.prevPage, and lastcurrblkno is so->currPos.currPage.
1820
 *
1821
 * On entry, so->currPos shouldn't be locked by caller.  so->currPos.buf must
1822
 * be InvalidBuffer/unpinned as needed by caller (note that lastcurrblkno
1823
 * won't need to be read again in almost all cases).  Parallel scan callers
1824
 * that seized the scan before calling here should pass seized=true; such a
1825
 * caller's blkno and lastcurrblkno arguments come from the seized scan.
1826
 * seized=false callers just pass us the blkno/lastcurrblkno taken from their
1827
 * so->currPos, which (along with so->currPos itself) can be used to end the
1828
 * scan.  A seized=false caller's blkno can never be assumed to be the page
1829
 * that must be read next during a parallel scan, though.  We must figure that
1830
 * part out for ourselves by seizing the scan (the correct page to read might
1831
 * already be beyond the seized=false caller's blkno during a parallel scan,
1832
 * unless blkno/so->currPos.nextPage/so->currPos.prevPage is already P_NONE,
1833
 * or unless so->currPos.moreRight/so->currPos.moreLeft is already unset).
1834
 *
1835
 * On success exit, so->currPos is updated to contain data from the next
1836
 * interesting page, and we return true.  We hold a pin on the buffer on
1837
 * success exit (except during so->dropPin index scans, when we drop the pin
1838
 * eagerly to avoid blocking VACUUM).
1839
 *
1840
 * If there are no more matching records in the given direction, we invalidate
1841
 * so->currPos (while ensuring it retains no locks or pins), and return false.
1842
 *
1843
 * We always release the scan for a parallel scan caller, regardless of
1844
 * success or failure; we'll call _bt_parallel_release as soon as possible.
1845
 */
1846
static bool
1847
_bt_readnextpage(IndexScanDesc scan, BlockNumber blkno,
1848
         BlockNumber lastcurrblkno, ScanDirection dir, bool seized)
1849
0
{
1850
0
  Relation  rel = scan->indexRelation;
1851
0
  BTScanOpaque so = (BTScanOpaque) scan->opaque;
1852
1853
0
  Assert(so->currPos.currPage == lastcurrblkno || seized);
1854
0
  Assert(!(blkno == P_NONE && seized));
1855
0
  Assert(!BTScanPosIsPinned(so->currPos));
1856
1857
  /*
1858
   * Remember that the scan already read lastcurrblkno, a page to the left
1859
   * of blkno (or remember reading a page to the right, for backwards scans)
1860
   */
1861
0
  if (ScanDirectionIsForward(dir))
1862
0
    so->currPos.moreLeft = true;
1863
0
  else
1864
0
    so->currPos.moreRight = true;
1865
1866
0
  for (;;)
1867
0
  {
1868
0
    Page    page;
1869
0
    BTPageOpaque opaque;
1870
1871
0
    if (blkno == P_NONE ||
1872
0
      (ScanDirectionIsForward(dir) ?
1873
0
       !so->currPos.moreRight : !so->currPos.moreLeft))
1874
0
    {
1875
      /*
1876
       * most recent _bt_readpage call (for lastcurrblkno) ended scan,
1877
       * or lastcurrblkno is a half-dead leftmost page (not read by
1878
       * _bt_readpage, so so->currPos doesn't describe it)
1879
       */
1880
0
      Assert(so->currPos.currPage == lastcurrblkno || blkno == P_NONE);
1881
0
      Assert(!seized);
1882
0
      BTScanPosInvalidate(so->currPos);
1883
0
      _bt_parallel_done(scan);  /* iff !so->needPrimScan */
1884
0
      return false;
1885
0
    }
1886
1887
0
    Assert(!so->needPrimScan);
1888
1889
    /* parallel scan must never actually visit so->currPos blkno */
1890
0
    if (!seized && scan->parallel_scan != NULL &&
1891
0
      !_bt_parallel_seize(scan, &blkno, &lastcurrblkno, false))
1892
0
    {
1893
      /* whole scan is now done (or another primitive scan required) */
1894
0
      BTScanPosInvalidate(so->currPos);
1895
0
      return false;
1896
0
    }
1897
1898
0
    if (ScanDirectionIsForward(dir))
1899
0
    {
1900
      /* read blkno, but check for interrupts first */
1901
0
      CHECK_FOR_INTERRUPTS();
1902
0
      so->currPos.buf = _bt_getbuf(rel, blkno, BT_READ);
1903
0
    }
1904
0
    else
1905
0
    {
1906
      /* read blkno, avoiding race (also checks for interrupts) */
1907
0
      so->currPos.buf = _bt_lock_and_validate_left(rel, &blkno,
1908
0
                             lastcurrblkno);
1909
0
      if (so->currPos.buf == InvalidBuffer)
1910
0
      {
1911
        /* must have been a concurrent deletion of leftmost page */
1912
0
        BTScanPosInvalidate(so->currPos);
1913
0
        _bt_parallel_done(scan);
1914
0
        return false;
1915
0
      }
1916
0
    }
1917
1918
0
    page = BufferGetPage(so->currPos.buf);
1919
0
    opaque = BTPageGetOpaque(page);
1920
0
    lastcurrblkno = blkno;
1921
0
    if (likely(!P_IGNORE(opaque)))
1922
0
    {
1923
      /* see if there are any matches on this page */
1924
0
      if (ScanDirectionIsForward(dir))
1925
0
      {
1926
        /* note that this will clear moreRight if we can stop */
1927
0
        if (_bt_readpage(scan, dir, P_FIRSTDATAKEY(opaque), seized))
1928
0
          break;
1929
0
        blkno = so->currPos.nextPage;
1930
0
      }
1931
0
      else
1932
0
      {
1933
        /* note that this will clear moreLeft if we can stop */
1934
0
        if (_bt_readpage(scan, dir, PageGetMaxOffsetNumber(page), seized))
1935
0
          break;
1936
0
        blkno = so->currPos.prevPage;
1937
0
      }
1938
0
    }
1939
0
    else
1940
0
    {
1941
      /* _bt_readpage not called, so do all this for ourselves */
1942
0
      if (ScanDirectionIsForward(dir))
1943
0
        blkno = opaque->btpo_next;
1944
0
      else
1945
0
        blkno = opaque->btpo_prev;
1946
0
      if (scan->parallel_scan != NULL)
1947
0
        _bt_parallel_release(scan, blkno, lastcurrblkno);
1948
0
    }
1949
1950
    /* no matching tuples on this page */
1951
0
    _bt_relbuf(rel, so->currPos.buf);
1952
0
    seized = false;      /* released by _bt_readpage (or by us) */
1953
0
  }
1954
1955
  /*
1956
   * _bt_readpage succeeded.  Drop the lock (and maybe the pin) on
1957
   * so->currPos.buf in preparation for btgettuple returning tuples.
1958
   */
1959
0
  Assert(so->currPos.currPage == blkno);
1960
0
  Assert(BTScanPosIsPinned(so->currPos));
1961
0
  _bt_drop_lock_and_maybe_pin(rel, so);
1962
1963
0
  return true;
1964
0
}
1965
1966
/*
1967
 * _bt_lock_and_validate_left() -- lock caller's left sibling blkno,
1968
 * recovering from concurrent page splits/page deletions when necessary
1969
 *
1970
 * Called during backwards scans, to deal with their unique concurrency rules.
1971
 *
1972
 * blkno points to the block number of the page that we expect to move the
1973
 * scan to.  We'll successfully move the scan there when we find that its
1974
 * right sibling link still points to lastcurrblkno (the page we just read).
1975
 * Otherwise, we have to figure out which page is the correct one for the scan
1976
 * to now read the hard way, reasoning about concurrent splits and deletions.
1977
 * See nbtree/README.
1978
 *
1979
 * On return, we have both a pin and a read lock on the returned page, whose
1980
 * block number will be set in *blkno.  Returns InvalidBuffer if there is no
1981
 * page to the left (no lock or pin is held in that case).
1982
 *
1983
 * It is possible for the returned leaf page to be half-dead; caller must
1984
 * check that condition and step left again when required.
1985
 */
1986
static Buffer
1987
_bt_lock_and_validate_left(Relation rel, BlockNumber *blkno,
1988
               BlockNumber lastcurrblkno)
1989
0
{
1990
0
  BlockNumber origblkno = *blkno; /* detects circular links */
1991
1992
#ifdef USE_INJECTION_POINTS
1993
  if (!IsCatalogRelation(rel))
1994
    INJECTION_POINT("nbtree-walk-left", NULL);
1995
#endif
1996
1997
0
  for (;;)
1998
0
  {
1999
0
    Buffer    buf;
2000
0
    Page    page;
2001
0
    BTPageOpaque opaque;
2002
0
    int     tries;
2003
2004
    /* check for interrupts while we're not holding any buffer lock */
2005
0
    CHECK_FOR_INTERRUPTS();
2006
0
    buf = _bt_getbuf(rel, *blkno, BT_READ);
2007
0
    page = BufferGetPage(buf);
2008
0
    opaque = BTPageGetOpaque(page);
2009
2010
    /*
2011
     * If this isn't the page we want, walk right till we find what we
2012
     * want --- but go no more than four hops (an arbitrary limit). If we
2013
     * don't find the correct page by then, the most likely bet is that
2014
     * lastcurrblkno got deleted and isn't in the sibling chain at all
2015
     * anymore, not that its left sibling got split more than four times.
2016
     *
2017
     * Note that it is correct to test P_ISDELETED not P_IGNORE here,
2018
     * because half-dead pages are still in the sibling chain.
2019
     */
2020
0
    tries = 0;
2021
0
    for (;;)
2022
0
    {
2023
0
      if (likely(!P_ISDELETED(opaque) &&
2024
0
             opaque->btpo_next == lastcurrblkno))
2025
0
      {
2026
        /* Found desired page, return it */
2027
0
        return buf;
2028
0
      }
2029
0
      if (P_RIGHTMOST(opaque) || ++tries > 4)
2030
0
        break;
2031
2032
#ifdef USE_INJECTION_POINTS
2033
      if (!IsCatalogRelation(rel))
2034
        INJECTION_POINT("nbtree-walk-left-step-right", NULL);
2035
#endif
2036
2037
      /* step right */
2038
0
      *blkno = opaque->btpo_next;
2039
0
      buf = _bt_relandgetbuf(rel, buf, *blkno, BT_READ);
2040
0
      page = BufferGetPage(buf);
2041
0
      opaque = BTPageGetOpaque(page);
2042
0
    }
2043
2044
    /*
2045
     * Return to the original page (usually the page most recently read by
2046
     * _bt_readpage, which is passed by caller as lastcurrblkno) to see
2047
     * what's up with its prev sibling link
2048
     */
2049
0
    buf = _bt_relandgetbuf(rel, buf, lastcurrblkno, BT_READ);
2050
0
    page = BufferGetPage(buf);
2051
0
    opaque = BTPageGetOpaque(page);
2052
0
    if (P_ISDELETED(opaque))
2053
0
    {
2054
#ifdef USE_INJECTION_POINTS
2055
      if (!IsCatalogRelation(rel))
2056
        INJECTION_POINT("nbtree-walk-left-deleted", NULL);
2057
#endif
2058
2059
      /*
2060
       * It was deleted.  Move right to first nondeleted page (there
2061
       * must be one); that is the page that has acquired the deleted
2062
       * one's keyspace, so stepping left from it will take us where we
2063
       * want to be.
2064
       */
2065
0
      for (;;)
2066
0
      {
2067
0
        if (P_RIGHTMOST(opaque))
2068
0
          elog(ERROR, "fell off the end of index \"%s\"",
2069
0
             RelationGetRelationName(rel));
2070
0
        lastcurrblkno = opaque->btpo_next;
2071
0
        buf = _bt_relandgetbuf(rel, buf, lastcurrblkno, BT_READ);
2072
0
        page = BufferGetPage(buf);
2073
0
        opaque = BTPageGetOpaque(page);
2074
0
        if (!P_ISDELETED(opaque))
2075
0
          break;
2076
0
      }
2077
0
    }
2078
0
    else
2079
0
    {
2080
      /*
2081
       * Original lastcurrblkno wasn't deleted; the explanation had
2082
       * better be that the page to the left got split or deleted.
2083
       * Without this check, we risk going into an infinite loop.
2084
       */
2085
0
      if (opaque->btpo_prev == origblkno)
2086
0
        elog(ERROR, "could not find left sibling of block %u in index \"%s\"",
2087
0
           lastcurrblkno, RelationGetRelationName(rel));
2088
      /* Okay to try again, since left sibling link changed */
2089
0
    }
2090
2091
    /*
2092
     * Original lastcurrblkno from caller was concurrently deleted (could
2093
     * also have been a great many concurrent left sibling page splits).
2094
     * Found a non-deleted page that should now act as our lastcurrblkno.
2095
     */
2096
0
    if (P_LEFTMOST(opaque))
2097
0
    {
2098
      /* New lastcurrblkno has no left sibling (concurrently deleted) */
2099
0
      _bt_relbuf(rel, buf);
2100
0
      break;
2101
0
    }
2102
2103
    /* Start from scratch with new lastcurrblkno's blkno/prev link */
2104
0
    *blkno = origblkno = opaque->btpo_prev;
2105
0
    _bt_relbuf(rel, buf);
2106
2107
#ifdef USE_INJECTION_POINTS
2108
    if (!IsCatalogRelation(rel))
2109
      INJECTION_POINT("nbtree-walk-left-restart", NULL);
2110
#endif
2111
0
  }
2112
2113
0
  return InvalidBuffer;
2114
0
}
2115
2116
/*
2117
 * _bt_get_endpoint() -- Find the first or last page on a given tree level
2118
 *
2119
 * If the index is empty, we will return InvalidBuffer; any other failure
2120
 * condition causes ereport().  We will not return a dead page.
2121
 *
2122
 * The returned buffer is pinned and read-locked.
2123
 */
2124
Buffer
2125
_bt_get_endpoint(Relation rel, uint32 level, bool rightmost)
2126
0
{
2127
0
  Buffer    buf;
2128
0
  Page    page;
2129
0
  BTPageOpaque opaque;
2130
0
  OffsetNumber offnum;
2131
0
  BlockNumber blkno;
2132
0
  IndexTuple  itup;
2133
2134
  /*
2135
   * If we are looking for a leaf page, okay to descend from fast root;
2136
   * otherwise better descend from true root.  (There is no point in being
2137
   * smarter about intermediate levels.)
2138
   */
2139
0
  if (level == 0)
2140
0
    buf = _bt_getroot(rel, NULL, BT_READ);
2141
0
  else
2142
0
    buf = _bt_gettrueroot(rel);
2143
2144
0
  if (!BufferIsValid(buf))
2145
0
    return InvalidBuffer;
2146
2147
0
  page = BufferGetPage(buf);
2148
0
  opaque = BTPageGetOpaque(page);
2149
2150
0
  for (;;)
2151
0
  {
2152
    /*
2153
     * If we landed on a deleted page, step right to find a live page
2154
     * (there must be one).  Also, if we want the rightmost page, step
2155
     * right if needed to get to it (this could happen if the page split
2156
     * since we obtained a pointer to it).
2157
     */
2158
0
    while (P_IGNORE(opaque) ||
2159
0
         (rightmost && !P_RIGHTMOST(opaque)))
2160
0
    {
2161
0
      blkno = opaque->btpo_next;
2162
0
      if (blkno == P_NONE)
2163
0
        elog(ERROR, "fell off the end of index \"%s\"",
2164
0
           RelationGetRelationName(rel));
2165
0
      buf = _bt_relandgetbuf(rel, buf, blkno, BT_READ);
2166
0
      page = BufferGetPage(buf);
2167
0
      opaque = BTPageGetOpaque(page);
2168
0
    }
2169
2170
    /* Done? */
2171
0
    if (opaque->btpo_level == level)
2172
0
      break;
2173
0
    if (opaque->btpo_level < level)
2174
0
      ereport(ERROR,
2175
0
          (errcode(ERRCODE_INDEX_CORRUPTED),
2176
0
           errmsg_internal("btree level %u not found in index \"%s\"",
2177
0
                   level, RelationGetRelationName(rel))));
2178
2179
    /* Descend to leftmost or rightmost child page */
2180
0
    if (rightmost)
2181
0
      offnum = PageGetMaxOffsetNumber(page);
2182
0
    else
2183
0
      offnum = P_FIRSTDATAKEY(opaque);
2184
2185
0
    if (offnum < 1 || offnum > PageGetMaxOffsetNumber(page))
2186
0
      elog(PANIC, "offnum out of range");
2187
2188
0
    itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offnum));
2189
0
    blkno = BTreeTupleGetDownLink(itup);
2190
2191
0
    buf = _bt_relandgetbuf(rel, buf, blkno, BT_READ);
2192
0
    page = BufferGetPage(buf);
2193
0
    opaque = BTPageGetOpaque(page);
2194
0
  }
2195
2196
0
  return buf;
2197
0
}
2198
2199
/*
2200
 *  _bt_endpoint() -- Find the first or last page in the index, and scan
2201
 * from there to the first key satisfying all the quals.
2202
 *
2203
 * This is used by _bt_first() to set up a scan when we've determined
2204
 * that the scan must start at the beginning or end of the index (for
2205
 * a forward or backward scan respectively).
2206
 *
2207
 * Parallel scan callers must have seized the scan before calling here.
2208
 * Exit conditions are the same as for _bt_first().
2209
 */
2210
static bool
2211
_bt_endpoint(IndexScanDesc scan, ScanDirection dir)
2212
0
{
2213
0
  Relation  rel = scan->indexRelation;
2214
0
  BTScanOpaque so = (BTScanOpaque) scan->opaque;
2215
0
  Page    page;
2216
0
  BTPageOpaque opaque;
2217
0
  OffsetNumber start;
2218
2219
0
  Assert(!BTScanPosIsValid(so->currPos));
2220
0
  Assert(!so->needPrimScan);
2221
2222
  /*
2223
   * Scan down to the leftmost or rightmost leaf page.  This is a simplified
2224
   * version of _bt_search().
2225
   */
2226
0
  so->currPos.buf = _bt_get_endpoint(rel, 0, ScanDirectionIsBackward(dir));
2227
2228
0
  if (!BufferIsValid(so->currPos.buf))
2229
0
  {
2230
#ifdef USE_INJECTION_POINTS
2231
    if (!IsCatalogRelation(rel))
2232
      INJECTION_POINT("nbtree-endpoint-empty", NULL);
2233
#endif
2234
2235
    /*
2236
     * Empty index. Lock the whole relation using the approach explained
2237
     * at the same point in the _bt_first path.
2238
     */
2239
0
    if (IsolationIsSerializable())
2240
0
    {
2241
0
      PredicateLockRelation(rel, scan->xs_snapshot);
2242
0
      so->currPos.buf = _bt_get_endpoint(rel, 0,
2243
0
                         ScanDirectionIsBackward(dir));
2244
0
    }
2245
2246
0
    if (!BufferIsValid(so->currPos.buf))
2247
0
    {
2248
0
      _bt_parallel_done(scan);
2249
0
      return false;
2250
0
    }
2251
0
  }
2252
2253
0
  page = BufferGetPage(so->currPos.buf);
2254
0
  opaque = BTPageGetOpaque(page);
2255
0
  Assert(P_ISLEAF(opaque));
2256
2257
0
  if (ScanDirectionIsForward(dir))
2258
0
  {
2259
    /* There could be dead pages to the left, so not this: */
2260
    /* Assert(P_LEFTMOST(opaque)); */
2261
2262
0
    start = P_FIRSTDATAKEY(opaque);
2263
0
  }
2264
0
  else if (ScanDirectionIsBackward(dir))
2265
0
  {
2266
0
    Assert(P_RIGHTMOST(opaque));
2267
2268
0
    start = PageGetMaxOffsetNumber(page);
2269
0
  }
2270
0
  else
2271
0
  {
2272
0
    elog(ERROR, "invalid scan direction: %d", (int) dir);
2273
0
    start = 0;        /* keep compiler quiet */
2274
0
  }
2275
2276
  /*
2277
   * Now load data from the first page of the scan.
2278
   */
2279
0
  if (!_bt_readfirstpage(scan, start, dir))
2280
0
    return false;
2281
2282
0
  _bt_returnitem(scan, so);
2283
  return true;
2284
0
}