PostgreSQL Source Code git master
Loading...
Searching...
No Matches
nbtsearch.c
Go to the documentation of this file.
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"
23#include "miscadmin.h"
24#include "pgstat.h"
25#include "storage/predicate.h"
27#include "utils/lsyscache.h"
28#include "utils/rel.h"
29
30
32static Buffer _bt_moveright(Relation rel, Relation heaprel, BTScanInsert key,
33 Buffer buf, bool forupdate, BTStack stack,
34 int access);
36static int _bt_binsrch_posting(BTScanInsert key, Page page,
37 OffsetNumber offnum);
38static inline void _bt_returnitem(IndexScanDesc scan, BTScanOpaque so);
39static bool _bt_steppage(IndexScanDesc scan, ScanDirection dir);
40static bool _bt_readfirstpage(IndexScanDesc scan, OffsetNumber offnum,
41 ScanDirection dir);
42static bool _bt_readnextpage(IndexScanDesc scan, BlockNumber blkno,
44 bool seized);
47static 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 */
56static inline void
58{
59 if (!so->dropPin)
60 {
61 /* Just drop the lock (not the pin) */
62 _bt_unlockbuf(rel, so->currPos.buf);
63 return;
64 }
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 so->currPos.lsn = BufferGetLSNAtomic(so->currPos.buf);
73 _bt_relbuf(rel, so->currPos.buf);
74 so->currPos.buf = InvalidBuffer;
75}
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 */
103 int access, bool returnstack)
104{
106 int page_access = BT_READ;
107
108 /* heaprel must be set whenever _bt_allocbuf is reachable */
110 Assert(access == BT_READ || heaprel != NULL);
111
112 /* Get the root page to start with */
113 *bufP = _bt_getroot(rel, heaprel, access);
114
115 /* If index is empty and access = BT_READ, no root page is created. */
116 if (!BufferIsValid(*bufP))
117 return (BTStack) NULL;
118
119 /* Loop iterates once per level descended in the tree */
120 for (;;)
121 {
122 Page page;
123 BTPageOpaque opaque;
124 OffsetNumber offnum;
125 ItemId itemid;
126 IndexTuple itup;
127 BlockNumber child;
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 *bufP = _bt_moveright(rel, heaprel, key, *bufP, (access == BT_WRITE),
144
145 /* if this is a leaf page, we're done */
146 page = BufferGetPage(*bufP);
147 opaque = BTPageGetOpaque(page);
148 if (P_ISLEAF(opaque))
149 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 offnum = _bt_binsrch(rel, key, *bufP);
156 itemid = PageGetItemId(page, offnum);
157 itup = (IndexTuple) PageGetItem(page, itemid);
158 Assert(BTreeTupleIsPivot(itup) || !key->heapkeyspace);
159 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 if (returnstack)
168 {
170 new_stack->bts_blkno = BufferGetBlockNumber(*bufP);
171 new_stack->bts_offset = offnum;
172 new_stack->bts_parent = stack_in;
174 }
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 if (opaque->btpo_level == 1 && access == BT_WRITE)
183
184 /* drop the read lock on the page, then acquire one on its child */
185 *bufP = _bt_relandgetbuf(rel, *bufP, child, page_access);
186
187 /* okay, all set to move down a level */
188 }
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 if (access == BT_WRITE && page_access == BT_READ)
196 {
197 /* trade in our read lock for a write lock */
198 _bt_unlockbuf(rel, *bufP);
199 _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 *bufP = _bt_moveright(rel, heaprel, key, *bufP, true, stack_in, BT_WRITE);
207 }
208
209 return stack_in;
210}
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 */
243static Buffer
245 Relation heaprel,
246 BTScanInsert key,
247 Buffer buf,
248 bool forupdate,
249 BTStack stack,
250 int access)
251{
252 Page page;
253 BTPageOpaque opaque;
255
256 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 cmpval = key->nextkey ? 0 : 1;
276
277 for (;;)
278 {
279 page = BufferGetPage(buf);
280 opaque = BTPageGetOpaque(page);
281
282 if (P_RIGHTMOST(opaque))
283 break;
284
285 /*
286 * Finish any incomplete splits we encounter along the way.
287 */
288 if (forupdate && P_INCOMPLETE_SPLIT(opaque))
289 {
291
292 /* upgrade our lock if necessary */
293 if (access == BT_READ)
294 {
295 _bt_unlockbuf(rel, buf);
296 _bt_lockbuf(rel, buf, BT_WRITE);
297 }
298
299 if (P_INCOMPLETE_SPLIT(opaque))
300 _bt_finish_split(rel, heaprel, buf, stack);
301 else
302 _bt_relbuf(rel, buf);
303
304 /* re-acquire the lock in the right mode, and re-check */
305 buf = _bt_getbuf(rel, blkno, access);
306 continue;
307 }
308
309 if (P_IGNORE(opaque) || _bt_compare(rel, key, page, P_HIKEY) >= cmpval)
310 {
311 /* step right one page */
312 buf = _bt_relandgetbuf(rel, buf, opaque->btpo_next, access);
313 continue;
314 }
315 else
316 break;
317 }
318
319 if (P_IGNORE(opaque))
320 elog(ERROR, "fell off the end of index \"%s\"",
322
323 return buf;
324}
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 */
345static OffsetNumber
347 BTScanInsert key,
348 Buffer buf)
349{
350 Page page;
351 BTPageOpaque opaque;
352 OffsetNumber low,
353 high;
355 cmpval;
356
357 page = BufferGetPage(buf);
358 opaque = BTPageGetOpaque(page);
359
360 /* Requesting nextkey semantics while using scantid seems nonsensical */
361 Assert(!key->nextkey || key->scantid == NULL);
362 /* scantid-set callers must use _bt_binsrch_insert() on leaf pages */
363 Assert(!P_ISLEAF(opaque) || key->scantid == NULL);
364
365 low = P_FIRSTDATAKEY(opaque);
366 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 if (unlikely(high < low))
376 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 high++; /* establish the loop invariant for high */
391
392 cmpval = key->nextkey ? 0 : 1; /* select comparison value */
393
394 while (high > low)
395 {
396 OffsetNumber mid = low + ((high - low) / 2);
397
398 /* We have low <= mid < high, so mid points at a real slot */
399
400 result = _bt_compare(rel, key, page, mid);
401
402 if (result >= cmpval)
403 low = mid + 1;
404 else
405 high = mid;
406 }
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 if (P_ISLEAF(opaque))
416 {
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 if (key->backward)
427 return OffsetNumberPrev(low);
428
429 return low;
430 }
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 Assert(low > P_FIRSTDATAKEY(opaque));
450
451 return OffsetNumberPrev(low);
452}
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 */
478{
479 BTScanInsert key = insertstate->itup_key;
480 Page page;
481 BTPageOpaque opaque;
482 OffsetNumber low,
483 high,
484 stricthigh;
486 cmpval;
487
488 page = BufferGetPage(insertstate->buf);
489 opaque = BTPageGetOpaque(page);
490
491 Assert(P_ISLEAF(opaque));
492 Assert(!key->nextkey);
493 Assert(insertstate->postingoff == 0);
494
495 if (!insertstate->bounds_valid)
496 {
497 /* Start new binary search */
498 low = P_FIRSTDATAKEY(opaque);
499 high = PageGetMaxOffsetNumber(page);
500 }
501 else
502 {
503 /* Restore result of previous binary search against same page */
504 low = insertstate->low;
505 high = insertstate->stricthigh;
506 }
507
508 /* If there are no keys on the page, return the first available slot */
509 if (unlikely(high < low))
510 {
511 /* Caller can't reuse bounds */
513 insertstate->stricthigh = InvalidOffsetNumber;
514 insertstate->bounds_valid = false;
515 return low;
516 }
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 if (!insertstate->bounds_valid)
529 high++; /* establish the loop invariant for high */
530 stricthigh = high; /* high initially strictly higher */
531
532 cmpval = 1; /* !nextkey comparison value */
533
534 while (high > low)
535 {
536 OffsetNumber mid = low + ((high - low) / 2);
537
538 /* We have low <= mid < high, so mid points at a real slot */
539
540 result = _bt_compare(rel, key, page, mid);
541
542 if (result >= cmpval)
543 low = mid + 1;
544 else
545 {
546 high = mid;
547 if (result != 0)
548 stricthigh = high;
549 }
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 if (unlikely(result == 0 && key->scantid != NULL))
559 {
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 if (insertstate->postingoff != 0)
568 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 ItemPointerGetBlockNumber(key->scantid),
570 ItemPointerGetOffsetNumber(key->scantid),
571 low, stricthigh,
574
575 insertstate->postingoff = _bt_binsrch_posting(key, page, mid);
576 }
577 }
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 insertstate->low = low;
590 insertstate->stricthigh = stricthigh;
591 insertstate->bounds_valid = true;
592
593 return low;
594}
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 */
604static int
606{
607 IndexTuple itup;
608 ItemId itemid;
609 int low,
610 high,
611 mid,
612 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 itemid = PageGetItemId(page, offnum);
625 itup = (IndexTuple) PageGetItem(page, itemid);
626 if (!BTreeTupleIsPosting(itup))
627 return 0;
628
629 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 if (ItemIdIsDead(itemid))
638 return -1;
639
640 /* "high" is past end of posting list for loop invariant */
641 low = 0;
642 high = BTreeTupleGetNPosting(itup);
643 Assert(high >= 2);
644
645 while (high > low)
646 {
647 mid = low + ((high - low) / 2);
648 res = ItemPointerCompare(key->scantid,
649 BTreeTupleGetPostingN(itup, mid));
650
651 if (res > 0)
652 low = mid + 1;
653 else if (res < 0)
654 high = mid;
655 else
656 return mid;
657 }
658
659 /* Exact match not found */
660 return low;
661}
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 */
690int32
692 BTScanInsert key,
693 Page page,
694 OffsetNumber offnum)
695{
697 BTPageOpaque opaque = BTPageGetOpaque(page);
698 IndexTuple itup;
699 ItemPointer heapTid;
701 int ncmpkey;
702 int ntupatts;
704
705 Assert(_bt_check_natts(rel, key->heapkeyspace, page, offnum));
707 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 if (!P_ISLEAF(opaque) && offnum == P_FIRSTDATAKEY(opaque))
714 return 1;
715
716 itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offnum));
717 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 ncmpkey = Min(ntupatts, key->keysz);
732 Assert(key->heapkeyspace || ncmpkey == key->keysz);
733 Assert(!BTreeTupleIsPosting(itup) || key->allequalimage);
734 scankey = key->scankeys;
735 for (int i = 1; i <= ncmpkey; i++)
736 {
737 Datum datum;
738 bool isNull;
739
740 datum = index_getattr(itup, scankey->sk_attno, itupdesc, &isNull);
741
742 if (scankey->sk_flags & SK_ISNULL) /* key is NULL */
743 {
744 if (isNull)
745 result = 0; /* NULL "=" NULL */
746 else if (scankey->sk_flags & SK_BT_NULLS_FIRST)
747 result = -1; /* NULL "<" NOT_NULL */
748 else
749 result = 1; /* NULL ">" NOT_NULL */
750 }
751 else if (isNull) /* key is NOT_NULL and item is NULL */
752 {
753 if (scankey->sk_flags & SK_BT_NULLS_FIRST)
754 result = 1; /* NOT_NULL ">" NULL */
755 else
756 result = -1; /* NOT_NULL "<" NULL */
757 }
758 else
759 {
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 */
769 scankey->sk_collation,
770 datum,
771 scankey->sk_argument));
772
773 if (!(scankey->sk_flags & SK_BT_DESC))
775 }
776
777 /* if the keys are unequal, return the difference */
778 if (result != 0)
779 return result;
780
781 scankey++;
782 }
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 if (key->keysz > ntupatts)
794 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 heapTid = BTreeTupleGetHeapTID(itup);
802 if (key->scantid == NULL)
803 {
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 if (!key->backward && key->keysz == ntupatts && heapTid == NULL &&
828 key->heapkeyspace)
829 return 1;
830
831 /* All provided scankey arguments found to be equal */
832 return 0;
833 }
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 */
840 if (heapTid == NULL)
841 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 */
850 result = ItemPointerCompare(key->scantid, heapTid);
851 if (result <= 0 || !BTreeTupleIsPosting(itup))
852 return result;
853 else
854 {
855 result = ItemPointerCompare(key->scantid,
857 if (result > 0)
858 return 1;
859 }
860
861 return 0;
862}
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 */
884bool
886{
887 Relation rel = scan->indexRelation;
889 OffsetNumber offnum;
890 BTScanInsertData inskey;
893 int keysz = 0;
897
898 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 */
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 if (!so->qual_ok)
911 {
912 Assert(!so->needPrimScan);
913 _bt_parallel_done(scan);
914 return false;
915 }
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 if (scan->parallel_scan != NULL &&
922 !_bt_parallel_seize(scan, &blkno, &lastcurrblkno, true))
923 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 if (so->numArrayKeys && !so->needPrimScan)
931 _bt_start_array_keys(scan, dir);
932
933 if (blkno != InvalidBlockNumber)
934 {
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 Assert(scan->parallel_scan != NULL);
940 Assert(!so->needPrimScan);
941 Assert(blkno != P_NONE);
942
943 if (!_bt_readnextpage(scan, blkno, lastcurrblkno, dir, true))
944 return false;
945
946 _bt_returnitem(scan, so);
947 return true;
948 }
949
950 /*
951 * Count an indexscan for stats, now that we know that we'll call
952 * _bt_search/_bt_endpoint below
953 */
955 if (scan->instrument)
956 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 if (so->numberOfKeys > 0)
1035 {
1037 ScanKey bkey;
1039 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 cur = so->keyData;
1046 curattr = 1;
1047 bkey = NULL;
1048 /* Also remember any scankey that implies a NOT NULL constraint */
1049 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 for (int i = 0;; cur++, i++)
1057 {
1058 if (i >= so->numberOfKeys || cur->sk_attno != curattr)
1059 {
1060 /* Done looking for the curattr boundary key */
1061 Assert(bkey == NULL ||
1062 (bkey->sk_attno == curattr &&
1063 (bkey->sk_flags & (SK_BT_REQFWD | SK_BT_REQBKWD))));
1064 Assert(impliesNN == NULL ||
1065 (impliesNN->sk_attno == curattr &&
1066 (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 if (bkey != NULL &&
1079 (bkey->sk_flags & (SK_BT_MINVAL | SK_BT_MAXVAL)))
1080 {
1081 int ikey = bkey - so->keyData;
1083 BTArrayKeyInfo *array = NULL;
1084
1085 for (int arridx = 0; arridx < so->numArrayKeys; arridx++)
1086 {
1087 array = &so->arrayKeys[arridx];
1088 if (array->scan_key == ikey)
1089 break;
1090 }
1091
1092 if (ScanDirectionIsForward(dir))
1093 {
1094 Assert(!(skipequalitykey->sk_flags & SK_BT_MAXVAL));
1095 bkey = array->low_compare;
1096 }
1097 else
1098 {
1099 Assert(!(skipequalitykey->sk_flags & SK_BT_MINVAL));
1100 bkey = array->high_compare;
1101 }
1102
1103 Assert(bkey == NULL ||
1104 bkey->sk_attno == skipequalitykey->sk_attno);
1105
1106 if (!array->null_elem)
1108 else
1109 Assert(bkey == NULL && impliesNN == NULL);
1110 }
1111
1112 /*
1113 * If we didn't find a usable boundary key, see if we can
1114 * deduce a NOT NULL key
1115 */
1116 if (bkey == NULL && impliesNN != NULL &&
1117 ((impliesNN->sk_flags & SK_BT_NULLS_FIRST) ?
1120 {
1121 /* Final startKeys[] entry will be deduced NOT NULL key */
1122 bkey = &notnullkey;
1125 (impliesNN->sk_flags &
1127 curattr,
1130 InvalidOid,
1131 InvalidOid,
1132 InvalidOid,
1133 (Datum) 0);
1134 }
1135
1136 /*
1137 * If preprocessing didn't leave a usable boundary key, quit;
1138 * else save the boundary key pointer in startKeys[]
1139 */
1140 if (bkey == NULL)
1141 break;
1142 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 strat_total = bkey->sk_strategy;
1153 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 if (bkey->sk_flags & (SK_BT_NEXT | SK_BT_PRIOR))
1162 {
1163 Assert(bkey->sk_flags & SK_BT_SKIP);
1165
1166 if (ScanDirectionIsForward(dir))
1167 {
1168 Assert(!(bkey->sk_flags & SK_BT_PRIOR));
1170 }
1171 else
1172 {
1173 Assert(!(bkey->sk_flags & SK_BT_NEXT));
1175 }
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 break;
1183 }
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 if (i >= so->numberOfKeys ||
1190 !(cur->sk_flags & (SK_BT_REQFWD | SK_BT_REQBKWD)))
1191 break;
1192
1193 /*
1194 * Reset for next attr.
1195 */
1196 Assert(cur->sk_attno == curattr + 1);
1197 curattr = cur->sk_attno;
1198 bkey = NULL;
1199 impliesNN = NULL;
1200 }
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 if (bkey != NULL)
1207 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 switch (cur->sk_strategy)
1217 {
1220 if (ScanDirectionIsBackward(dir))
1221 bkey = cur;
1222 else if (impliesNN == NULL)
1223 impliesNN = cur;
1224 break;
1226 bkey = cur;
1227 break;
1230 if (ScanDirectionIsForward(dir))
1231 bkey = cur;
1232 else if (impliesNN == NULL)
1233 impliesNN = cur;
1234 break;
1235 }
1236 }
1237 }
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 if (keysz == 0)
1247 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 Assert(keysz <= INDEX_MAX_KEYS);
1257 for (int i = 0; i < keysz; i++)
1258 {
1260
1261 Assert(bkey->sk_attno == i + 1);
1262
1263 if (bkey->sk_flags & SK_ROW_HEADER)
1264 {
1265 /*
1266 * Row comparison header: look to the first row member instead
1267 */
1268 ScanKey subkey = (ScanKey) DatumGetPointer(bkey->sk_argument);
1269 bool loosen_strat = false,
1270 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 Assert(subkey->sk_flags & SK_ROW_MEMBER);
1278 Assert(subkey->sk_attno == bkey->sk_attno);
1279 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 Assert(subkey->sk_flags & (SK_BT_REQFWD | SK_BT_REQBKWD));
1288 Assert(subkey->sk_strategy == bkey->sk_strategy);
1289 Assert(subkey->sk_strategy == strat_total);
1290 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 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 Assert(!(subkey->sk_flags & SK_ROW_END));
1317 for (;;)
1318 {
1319 subkey++;
1320 Assert(subkey->sk_flags & SK_ROW_MEMBER);
1321
1322 if (subkey->sk_flags & SK_ISNULL)
1323 {
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 tighten_strat = true;
1332 break;
1333 }
1334
1335 if (!(subkey->sk_flags & (SK_BT_REQFWD | SK_BT_REQBKWD)))
1336 {
1337 /* nonrequired member key, can only use earlier keys */
1338 loosen_strat = true;
1339 break;
1340 }
1341
1342 Assert(subkey->sk_attno == keysz + 1);
1343 Assert(subkey->sk_strategy == bkey->sk_strategy);
1344 Assert(keysz < INDEX_MAX_KEYS);
1345
1346 memcpy(inskey.scankeys + keysz, subkey, sizeof(ScanKeyData));
1347 keysz++;
1348
1349 if (subkey->sk_flags & SK_ROW_END)
1350 break;
1351 }
1353 if (loosen_strat)
1354 {
1355 /* Use less restrictive strategy (and fewer member keys) */
1356 switch (strat_total)
1357 {
1360 break;
1363 break;
1364 }
1365 }
1366 if (tighten_strat)
1367 {
1368 /* Use more restrictive strategy (and fewer member keys) */
1369 switch (strat_total)
1370 {
1373 break;
1376 break;
1377 }
1378 }
1379
1380 /* Done (row compare header key is always last startKeys[] key) */
1381 break;
1382 }
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 if (bkey->sk_subtype == rel->rd_opcintype[i] ||
1401 bkey->sk_subtype == InvalidOid)
1402 {
1404
1405 procinfo = index_getprocinfo(rel, bkey->sk_attno, BTORDER_PROC);
1407 bkey->sk_flags,
1408 bkey->sk_attno,
1410 bkey->sk_subtype,
1411 bkey->sk_collation,
1412 procinfo,
1413 bkey->sk_argument);
1414 }
1415 else
1416 {
1417 RegProcedure cmp_proc;
1418
1419 cmp_proc = get_opfamily_proc(rel->rd_opfamily[i],
1420 rel->rd_opcintype[i],
1421 bkey->sk_subtype, BTORDER_PROC);
1422 if (!RegProcedureIsValid(cmp_proc))
1423 elog(ERROR, "missing support function %d(%u,%u) for attribute %d of index \"%s\"",
1424 BTORDER_PROC, rel->rd_opcintype[i], bkey->sk_subtype,
1425 bkey->sk_attno, RelationGetRelationName(rel));
1427 bkey->sk_flags,
1428 bkey->sk_attno,
1430 bkey->sk_subtype,
1431 bkey->sk_collation,
1432 cmp_proc,
1433 bkey->sk_argument);
1434 }
1435 }
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 _bt_metaversion(rel, &inskey.heapkeyspace, &inskey.allequalimage);
1445 inskey.anynullkeys = false; /* unused */
1446 inskey.scantid = NULL;
1447 inskey.keysz = keysz;
1448 switch (strat_total)
1449 {
1451
1452 inskey.nextkey = false;
1453 inskey.backward = true;
1454 break;
1455
1457
1458 inskey.nextkey = true;
1459 inskey.backward = true;
1460 break;
1461
1463
1464 /*
1465 * If a backward scan was specified, need to start with last equal
1466 * item not first one.
1467 */
1468 if (ScanDirectionIsBackward(dir))
1469 {
1470 /*
1471 * This is the same as the <= strategy
1472 */
1473 inskey.nextkey = true;
1474 inskey.backward = true;
1475 }
1476 else
1477 {
1478 /*
1479 * This is the same as the >= strategy
1480 */
1481 inskey.nextkey = false;
1482 inskey.backward = false;
1483 }
1484 break;
1485
1487
1488 /*
1489 * Find first item >= scankey
1490 */
1491 inskey.nextkey = false;
1492 inskey.backward = false;
1493 break;
1494
1496
1497 /*
1498 * Find first item > scankey
1499 */
1500 inskey.nextkey = true;
1501 inskey.backward = false;
1502 break;
1503
1504 default:
1505 /* can't get here, but keep compiler quiet */
1506 elog(ERROR, "unrecognized strat_total: %d", (int) strat_total);
1507 return false;
1508 }
1509
1510 /*
1511 * Use the manufactured insertion scan key to descend the tree and
1512 * position ourselves on the target leaf page.
1513 */
1514 Assert(ScanDirectionIsBackward(dir) == inskey.backward);
1515 _bt_search(rel, NULL, &inskey, &so->currPos.buf, BT_READ, false);
1516
1517 if (!BufferIsValid(so->currPos.buf))
1518 {
1519 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 */
1536 {
1538 _bt_search(rel, NULL, &inskey, &so->currPos.buf, BT_READ, false);
1539 }
1540
1541 if (!BufferIsValid(so->currPos.buf))
1542 {
1543 _bt_parallel_done(scan);
1544 return false;
1545 }
1546 }
1547
1548 /* position to the precise item on the page */
1549 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 if (!_bt_readfirstpage(scan, offnum, dir))
1572 return false;
1573
1574 _bt_returnitem(scan, so);
1575 return true;
1576}
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 */
1592bool
1594{
1596
1597 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 if (ScanDirectionIsForward(dir))
1604 {
1605 if (++so->currPos.itemIndex > so->currPos.lastItem)
1606 {
1607 if (!_bt_steppage(scan, dir))
1608 return false;
1609 }
1610 }
1611 else
1612 {
1613 if (--so->currPos.itemIndex < so->currPos.firstItem)
1614 {
1615 if (!_bt_steppage(scan, dir))
1616 return false;
1617 }
1618 }
1619
1620 _bt_returnitem(scan, so);
1621 return true;
1622}
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 */
1628static inline void
1630{
1631 BTScanPosItem *currItem = &so->currPos.items[so->currPos.itemIndex];
1632
1633 /* Most recent _bt_readpage must have succeeded */
1634 Assert(BTScanPosIsValid(so->currPos));
1635 Assert(so->currPos.itemIndex >= so->currPos.firstItem);
1636 Assert(so->currPos.itemIndex <= so->currPos.lastItem);
1637
1638 /* Return next item, per amgettuple contract */
1639 scan->xs_heaptid = currItem->heapTid;
1640 if (so->currTuples)
1641 scan->xs_itup = (IndexTuple) (so->currTuples + currItem->tupleOffset);
1642}
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 */
1653static bool
1655{
1657 BlockNumber blkno,
1659
1660 Assert(BTScanPosIsValid(so->currPos));
1661
1662 /* Before leaving current page, deal with any killed items */
1663 if (so->numKilled > 0)
1664 _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 if (so->markItemIndex >= 0)
1671 {
1672 /* bump pin on current buffer for assignment to mark buffer */
1673 if (BTScanPosIsPinned(so->currPos))
1674 IncrBufferRefCount(so->currPos.buf);
1675 memcpy(&so->markPos, &so->currPos,
1677 so->currPos.lastItem * sizeof(BTScanPosItem));
1678 if (so->markTuples)
1679 memcpy(so->markTuples, so->currTuples,
1680 so->currPos.nextTupleOffset);
1681 so->markPos.itemIndex = so->markItemIndex;
1682 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 if (so->needPrimScan)
1701 {
1702 if (ScanDirectionIsForward(so->currPos.dir))
1703 so->markPos.moreRight = true;
1704 else
1705 so->markPos.moreLeft = true;
1706 }
1707
1708 /* mark/restore not supported by parallel scans */
1709 Assert(!scan->parallel_scan);
1710 }
1711
1712 BTScanPosUnpinIfPinned(so->currPos);
1713
1714 /* Walk to the next page with data */
1715 if (ScanDirectionIsForward(dir))
1716 blkno = so->currPos.nextPage;
1717 else
1718 blkno = so->currPos.prevPage;
1719 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 if (so->currPos.dir != dir)
1728 so->needPrimScan = false;
1729
1730 return _bt_readnextpage(scan, blkno, lastcurrblkno, dir, false);
1731}
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 */
1753static bool
1755{
1757
1758 so->numKilled = 0; /* just paranoia */
1759 so->markItemIndex = -1; /* ditto */
1760
1761 /* Initialize so->currPos for the first page (page in so->currPos.buf) */
1762 if (so->needPrimScan)
1763 {
1764 Assert(so->numArrayKeys);
1765
1766 so->currPos.moreLeft = true;
1767 so->currPos.moreRight = true;
1768 so->needPrimScan = false;
1769 }
1770 else if (ScanDirectionIsForward(dir))
1771 {
1772 so->currPos.moreLeft = false;
1773 so->currPos.moreRight = true;
1774 }
1775 else
1776 {
1777 so->currPos.moreLeft = true;
1778 so->currPos.moreRight = false;
1779 }
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 if (_bt_readpage(scan, dir, offnum, true))
1788 {
1789 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 Assert(BTScanPosIsPinned(so->currPos));
1797 return true;
1798 }
1799
1800 /* There's no actually-matching data on the page in so->currPos.buf */
1801 _bt_unlockbuf(scan->indexRelation, so->currPos.buf);
1802
1803 /* Call _bt_readnextpage using its _bt_steppage wrapper function */
1804 if (!_bt_steppage(scan, dir))
1805 return false;
1806
1807 /* _bt_readpage for a later page (now in so->currPos) succeeded */
1808 return true;
1809}
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 */
1846static bool
1849{
1850 Relation rel = scan->indexRelation;
1852
1853 Assert(so->currPos.currPage == lastcurrblkno || seized);
1854 Assert(!(blkno == P_NONE && seized));
1855 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 if (ScanDirectionIsForward(dir))
1862 so->currPos.moreLeft = true;
1863 else
1864 so->currPos.moreRight = true;
1865
1866 for (;;)
1867 {
1868 Page page;
1869 BTPageOpaque opaque;
1870
1871 if (blkno == P_NONE ||
1873 !so->currPos.moreRight : !so->currPos.moreLeft))
1874 {
1875 /* most recent _bt_readpage call (for lastcurrblkno) ended scan */
1876 Assert(so->currPos.currPage == lastcurrblkno && !seized);
1877 BTScanPosInvalidate(so->currPos);
1878 _bt_parallel_done(scan); /* iff !so->needPrimScan */
1879 return false;
1880 }
1881
1882 Assert(!so->needPrimScan);
1883
1884 /* parallel scan must never actually visit so->currPos blkno */
1885 if (!seized && scan->parallel_scan != NULL &&
1886 !_bt_parallel_seize(scan, &blkno, &lastcurrblkno, false))
1887 {
1888 /* whole scan is now done (or another primitive scan required) */
1889 BTScanPosInvalidate(so->currPos);
1890 return false;
1891 }
1892
1893 if (ScanDirectionIsForward(dir))
1894 {
1895 /* read blkno, but check for interrupts first */
1897 so->currPos.buf = _bt_getbuf(rel, blkno, BT_READ);
1898 }
1899 else
1900 {
1901 /* read blkno, avoiding race (also checks for interrupts) */
1902 so->currPos.buf = _bt_lock_and_validate_left(rel, &blkno,
1904 if (so->currPos.buf == InvalidBuffer)
1905 {
1906 /* must have been a concurrent deletion of leftmost page */
1907 BTScanPosInvalidate(so->currPos);
1908 _bt_parallel_done(scan);
1909 return false;
1910 }
1911 }
1912
1913 page = BufferGetPage(so->currPos.buf);
1914 opaque = BTPageGetOpaque(page);
1915 lastcurrblkno = blkno;
1916 if (likely(!P_IGNORE(opaque)))
1917 {
1918 /* see if there are any matches on this page */
1919 if (ScanDirectionIsForward(dir))
1920 {
1921 /* note that this will clear moreRight if we can stop */
1922 if (_bt_readpage(scan, dir, P_FIRSTDATAKEY(opaque), seized))
1923 break;
1924 blkno = so->currPos.nextPage;
1925 }
1926 else
1927 {
1928 /* note that this will clear moreLeft if we can stop */
1929 if (_bt_readpage(scan, dir, PageGetMaxOffsetNumber(page), seized))
1930 break;
1931 blkno = so->currPos.prevPage;
1932 }
1933 }
1934 else
1935 {
1936 /* _bt_readpage not called, so do all this for ourselves */
1937 if (ScanDirectionIsForward(dir))
1938 blkno = opaque->btpo_next;
1939 else
1940 blkno = opaque->btpo_prev;
1941 if (scan->parallel_scan != NULL)
1942 _bt_parallel_release(scan, blkno, lastcurrblkno);
1943 }
1944
1945 /* no matching tuples on this page */
1946 _bt_relbuf(rel, so->currPos.buf);
1947 seized = false; /* released by _bt_readpage (or by us) */
1948 }
1949
1950 /*
1951 * _bt_readpage succeeded. Drop the lock (and maybe the pin) on
1952 * so->currPos.buf in preparation for btgettuple returning tuples.
1953 */
1954 Assert(so->currPos.currPage == blkno);
1955 Assert(BTScanPosIsPinned(so->currPos));
1957
1958 return true;
1959}
1960
1961/*
1962 * _bt_lock_and_validate_left() -- lock caller's left sibling blkno,
1963 * recovering from concurrent page splits/page deletions when necessary
1964 *
1965 * Called during backwards scans, to deal with their unique concurrency rules.
1966 *
1967 * blkno points to the block number of the page that we expect to move the
1968 * scan to. We'll successfully move the scan there when we find that its
1969 * right sibling link still points to lastcurrblkno (the page we just read).
1970 * Otherwise, we have to figure out which page is the correct one for the scan
1971 * to now read the hard way, reasoning about concurrent splits and deletions.
1972 * See nbtree/README.
1973 *
1974 * On return, we have both a pin and a read lock on the returned page, whose
1975 * block number will be set in *blkno. Returns InvalidBuffer if there is no
1976 * page to the left (no lock or pin is held in that case).
1977 *
1978 * It is possible for the returned leaf page to be half-dead; caller must
1979 * check that condition and step left again when required.
1980 */
1981static Buffer
1984{
1985 BlockNumber origblkno = *blkno; /* detects circular links */
1986
1987#ifdef USE_INJECTION_POINTS
1988 if (!IsCatalogRelation(rel))
1989 INJECTION_POINT("nbtree-walk-left", NULL);
1990#endif
1991
1992 for (;;)
1993 {
1994 Buffer buf;
1995 Page page;
1996 BTPageOpaque opaque;
1997 int tries;
1998
1999 /* check for interrupts while we're not holding any buffer lock */
2001 buf = _bt_getbuf(rel, *blkno, BT_READ);
2002 page = BufferGetPage(buf);
2003 opaque = BTPageGetOpaque(page);
2004
2005 /*
2006 * If this isn't the page we want, walk right till we find what we
2007 * want --- but go no more than four hops (an arbitrary limit). If we
2008 * don't find the correct page by then, the most likely bet is that
2009 * lastcurrblkno got deleted and isn't in the sibling chain at all
2010 * anymore, not that its left sibling got split more than four times.
2011 *
2012 * Note that it is correct to test P_ISDELETED not P_IGNORE here,
2013 * because half-dead pages are still in the sibling chain.
2014 */
2015 tries = 0;
2016 for (;;)
2017 {
2018 if (likely(!P_ISDELETED(opaque) &&
2019 opaque->btpo_next == lastcurrblkno))
2020 {
2021 /* Found desired page, return it */
2022 return buf;
2023 }
2024 if (P_RIGHTMOST(opaque) || ++tries > 4)
2025 break;
2026
2027#ifdef USE_INJECTION_POINTS
2028 if (!IsCatalogRelation(rel))
2029 INJECTION_POINT("nbtree-walk-left-step-right", NULL);
2030#endif
2031
2032 /* step right */
2033 *blkno = opaque->btpo_next;
2034 buf = _bt_relandgetbuf(rel, buf, *blkno, BT_READ);
2035 page = BufferGetPage(buf);
2036 opaque = BTPageGetOpaque(page);
2037 }
2038
2039 /*
2040 * Return to the original page (usually the page most recently read by
2041 * _bt_readpage, which is passed by caller as lastcurrblkno) to see
2042 * what's up with its prev sibling link
2043 */
2045 page = BufferGetPage(buf);
2046 opaque = BTPageGetOpaque(page);
2047 if (P_ISDELETED(opaque))
2048 {
2049#ifdef USE_INJECTION_POINTS
2050 if (!IsCatalogRelation(rel))
2051 INJECTION_POINT("nbtree-walk-left-deleted", NULL);
2052#endif
2053
2054 /*
2055 * It was deleted. Move right to first nondeleted page (there
2056 * must be one); that is the page that has acquired the deleted
2057 * one's keyspace, so stepping left from it will take us where we
2058 * want to be.
2059 */
2060 for (;;)
2061 {
2062 if (P_RIGHTMOST(opaque))
2063 elog(ERROR, "fell off the end of index \"%s\"",
2065 lastcurrblkno = opaque->btpo_next;
2067 page = BufferGetPage(buf);
2068 opaque = BTPageGetOpaque(page);
2069 if (!P_ISDELETED(opaque))
2070 break;
2071 }
2072 }
2073 else
2074 {
2075 /*
2076 * Original lastcurrblkno wasn't deleted; the explanation had
2077 * better be that the page to the left got split or deleted.
2078 * Without this check, we risk going into an infinite loop.
2079 */
2080 if (opaque->btpo_prev == origblkno)
2081 elog(ERROR, "could not find left sibling of block %u in index \"%s\"",
2083 /* Okay to try again, since left sibling link changed */
2084 }
2085
2086 /*
2087 * Original lastcurrblkno from caller was concurrently deleted (could
2088 * also have been a great many concurrent left sibling page splits).
2089 * Found a non-deleted page that should now act as our lastcurrblkno.
2090 */
2091 if (P_LEFTMOST(opaque))
2092 {
2093 /* New lastcurrblkno has no left sibling (concurrently deleted) */
2094 _bt_relbuf(rel, buf);
2095 break;
2096 }
2097
2098 /* Start from scratch with new lastcurrblkno's blkno/prev link */
2099 *blkno = origblkno = opaque->btpo_prev;
2100 _bt_relbuf(rel, buf);
2101
2102#ifdef USE_INJECTION_POINTS
2103 if (!IsCatalogRelation(rel))
2104 INJECTION_POINT("nbtree-walk-left-restart", NULL);
2105#endif
2106 }
2107
2108 return InvalidBuffer;
2109}
2110
2111/*
2112 * _bt_get_endpoint() -- Find the first or last page on a given tree level
2113 *
2114 * If the index is empty, we will return InvalidBuffer; any other failure
2115 * condition causes ereport(). We will not return a dead page.
2116 *
2117 * The returned buffer is pinned and read-locked.
2118 */
2119Buffer
2120_bt_get_endpoint(Relation rel, uint32 level, bool rightmost)
2121{
2122 Buffer buf;
2123 Page page;
2124 BTPageOpaque opaque;
2125 OffsetNumber offnum;
2126 BlockNumber blkno;
2127 IndexTuple itup;
2128
2129 /*
2130 * If we are looking for a leaf page, okay to descend from fast root;
2131 * otherwise better descend from true root. (There is no point in being
2132 * smarter about intermediate levels.)
2133 */
2134 if (level == 0)
2135 buf = _bt_getroot(rel, NULL, BT_READ);
2136 else
2137 buf = _bt_gettrueroot(rel);
2138
2139 if (!BufferIsValid(buf))
2140 return InvalidBuffer;
2141
2142 page = BufferGetPage(buf);
2143 opaque = BTPageGetOpaque(page);
2144
2145 for (;;)
2146 {
2147 /*
2148 * If we landed on a deleted page, step right to find a live page
2149 * (there must be one). Also, if we want the rightmost page, step
2150 * right if needed to get to it (this could happen if the page split
2151 * since we obtained a pointer to it).
2152 */
2153 while (P_IGNORE(opaque) ||
2154 (rightmost && !P_RIGHTMOST(opaque)))
2155 {
2156 blkno = opaque->btpo_next;
2157 if (blkno == P_NONE)
2158 elog(ERROR, "fell off the end of index \"%s\"",
2160 buf = _bt_relandgetbuf(rel, buf, blkno, BT_READ);
2161 page = BufferGetPage(buf);
2162 opaque = BTPageGetOpaque(page);
2163 }
2164
2165 /* Done? */
2166 if (opaque->btpo_level == level)
2167 break;
2168 if (opaque->btpo_level < level)
2169 ereport(ERROR,
2171 errmsg_internal("btree level %u not found in index \"%s\"",
2172 level, RelationGetRelationName(rel))));
2173
2174 /* Descend to leftmost or rightmost child page */
2175 if (rightmost)
2176 offnum = PageGetMaxOffsetNumber(page);
2177 else
2178 offnum = P_FIRSTDATAKEY(opaque);
2179
2181 elog(PANIC, "offnum out of range");
2182
2183 itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offnum));
2184 blkno = BTreeTupleGetDownLink(itup);
2185
2186 buf = _bt_relandgetbuf(rel, buf, blkno, BT_READ);
2187 page = BufferGetPage(buf);
2188 opaque = BTPageGetOpaque(page);
2189 }
2190
2191 return buf;
2192}
2193
2194/*
2195 * _bt_endpoint() -- Find the first or last page in the index, and scan
2196 * from there to the first key satisfying all the quals.
2197 *
2198 * This is used by _bt_first() to set up a scan when we've determined
2199 * that the scan must start at the beginning or end of the index (for
2200 * a forward or backward scan respectively).
2201 *
2202 * Parallel scan callers must have seized the scan before calling here.
2203 * Exit conditions are the same as for _bt_first().
2204 */
2205static bool
2207{
2208 Relation rel = scan->indexRelation;
2210 Page page;
2211 BTPageOpaque opaque;
2213
2214 Assert(!BTScanPosIsValid(so->currPos));
2215 Assert(!so->needPrimScan);
2216
2217 /*
2218 * Scan down to the leftmost or rightmost leaf page. This is a simplified
2219 * version of _bt_search().
2220 */
2221 so->currPos.buf = _bt_get_endpoint(rel, 0, ScanDirectionIsBackward(dir));
2222
2223 if (!BufferIsValid(so->currPos.buf))
2224 {
2225#ifdef USE_INJECTION_POINTS
2226 if (!IsCatalogRelation(rel))
2227 INJECTION_POINT("nbtree-endpoint-empty", NULL);
2228#endif
2229
2230 /*
2231 * Empty index. Lock the whole relation using the approach explained
2232 * at the same point in the _bt_first path.
2233 */
2235 {
2237 so->currPos.buf = _bt_get_endpoint(rel, 0,
2239 }
2240
2241 if (!BufferIsValid(so->currPos.buf))
2242 {
2243 _bt_parallel_done(scan);
2244 return false;
2245 }
2246 }
2247
2248 page = BufferGetPage(so->currPos.buf);
2249 opaque = BTPageGetOpaque(page);
2250 Assert(P_ISLEAF(opaque));
2251
2252 if (ScanDirectionIsForward(dir))
2253 {
2254 /* There could be dead pages to the left, so not this: */
2255 /* Assert(P_LEFTMOST(opaque)); */
2256
2257 start = P_FIRSTDATAKEY(opaque);
2258 }
2259 else if (ScanDirectionIsBackward(dir))
2260 {
2261 Assert(P_RIGHTMOST(opaque));
2262
2264 }
2265 else
2266 {
2267 elog(ERROR, "invalid scan direction: %d", (int) dir);
2268 start = 0; /* keep compiler quiet */
2269 }
2270
2271 /*
2272 * Now load data from the first page of the scan.
2273 */
2274 if (!_bt_readfirstpage(scan, start, dir))
2275 return false;
2276
2277 _bt_returnitem(scan, so);
2278 return true;
2279}
int16 AttrNumber
Definition attnum.h:21
uint32 BlockNumber
Definition block.h:31
#define InvalidBlockNumber
Definition block.h:33
int Buffer
Definition buf.h:23
#define InvalidBuffer
Definition buf.h:25
void IncrBufferRefCount(Buffer buffer)
Definition bufmgr.c:5693
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition bufmgr.c:4469
XLogRecPtr BufferGetLSNAtomic(Buffer buffer)
Definition bufmgr.c:4736
static Page BufferGetPage(Buffer buffer)
Definition bufmgr.h:468
static bool BufferIsValid(Buffer bufnum)
Definition bufmgr.h:419
static ItemId PageGetItemId(Page page, OffsetNumber offsetNumber)
Definition bufpage.h:268
static void * PageGetItem(PageData *page, const ItemIdData *itemId)
Definition bufpage.h:378
PageData * Page
Definition bufpage.h:81
static OffsetNumber PageGetMaxOffsetNumber(const PageData *page)
Definition bufpage.h:396
#define RegProcedureIsValid(p)
Definition c.h:921
#define Min(x, y)
Definition c.h:1131
#define INVERT_COMPARE_RESULT(var)
Definition c.h:1233
#define likely(x)
Definition c.h:496
#define Assert(condition)
Definition c.h:1002
regproc RegProcedure
Definition c.h:793
int32_t int32
Definition c.h:679
#define unlikely(x)
Definition c.h:497
uint32_t uint32
Definition c.h:683
bool IsCatalogRelation(Relation relation)
Definition catalog.c:106
uint32 result
memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets))
struct cursor * cur
Definition ecpg.c:29
int errcode(int sqlerrcode)
Definition elog.c:875
int int errmsg_internal(const char *fmt,...) pg_attribute_printf(1
#define PANIC
Definition elog.h:44
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define ereport(elevel,...)
Definition elog.h:152
#define palloc_object(type)
Definition fe_memutils.h:89
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition fmgr.c:1151
return str start
FmgrInfo * index_getprocinfo(Relation irel, AttrNumber attnum, uint16 procnum)
Definition indexam.c:885
#define INJECTION_POINT(name, arg)
int i
Definition isn.c:77
#define ItemIdIsDead(itemId)
Definition itemid.h:113
int32 ItemPointerCompare(const ItemPointerData *arg1, const ItemPointerData *arg2)
Definition itemptr.c:51
static OffsetNumber ItemPointerGetOffsetNumber(const ItemPointerData *pointer)
Definition itemptr.h:124
static BlockNumber ItemPointerGetBlockNumber(const ItemPointerData *pointer)
Definition itemptr.h:103
IndexTupleData * IndexTuple
Definition itup.h:53
static Datum index_getattr(IndexTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition itup.h:131
Oid get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum)
Definition lsyscache.c:1022
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:125
void _bt_finish_split(Relation rel, Relation heaprel, Buffer lbuf, BTStack stack)
Definition nbtinsert.c:2272
Buffer _bt_relandgetbuf(Relation rel, Buffer obuf, BlockNumber blkno, int access)
Definition nbtpage.c:988
void _bt_relbuf(Relation rel, Buffer buf)
Definition nbtpage.c:1024
Buffer _bt_gettrueroot(Relation rel)
Definition nbtpage.c:585
void _bt_metaversion(Relation rel, bool *heapkeyspace, bool *allequalimage)
Definition nbtpage.c:724
Buffer _bt_getbuf(Relation rel, BlockNumber blkno, int access)
Definition nbtpage.c:830
void _bt_unlockbuf(Relation rel, Buffer buf)
Definition nbtpage.c:1078
void _bt_lockbuf(Relation rel, Buffer buf, int access)
Definition nbtpage.c:1047
Buffer _bt_getroot(Relation rel, Relation heaprel, int access)
Definition nbtpage.c:347
void _bt_preprocess_keys(IndexScanDesc scan)
bool _bt_readpage(IndexScanDesc scan, ScanDirection dir, OffsetNumber offnum, bool firstpage)
void _bt_start_array_keys(IndexScanDesc scan, ScanDirection dir)
bool _bt_parallel_seize(IndexScanDesc scan, BlockNumber *next_scan_page, BlockNumber *last_curr_page, bool first)
Definition nbtree.c:873
void _bt_parallel_done(IndexScanDesc scan)
Definition nbtree.c:1038
void _bt_parallel_release(IndexScanDesc scan, BlockNumber next_scan_page, BlockNumber curr_page)
Definition nbtree.c:1011
#define BTScanPosIsPinned(scanpos)
Definition nbtree.h:1004
static uint16 BTreeTupleGetNPosting(IndexTuple posting)
Definition nbtree.h:519
static bool BTreeTupleIsPivot(IndexTuple itup)
Definition nbtree.h:481
BTStackData * BTStack
Definition nbtree.h:750
#define P_ISLEAF(opaque)
Definition nbtree.h:221
#define SK_BT_SKIP
Definition nbtree.h:1106
#define P_HIKEY
Definition nbtree.h:368
#define BTORDER_PROC
Definition nbtree.h:717
#define P_LEFTMOST(opaque)
Definition nbtree.h:219
#define BTPageGetOpaque(page)
Definition nbtree.h:74
#define SK_BT_PRIOR
Definition nbtree.h:1112
#define P_ISDELETED(opaque)
Definition nbtree.h:223
#define SK_BT_NEXT
Definition nbtree.h:1111
#define BTScanPosIsValid(scanpos)
Definition nbtree.h:1021
#define P_FIRSTDATAKEY(opaque)
Definition nbtree.h:370
#define P_NONE
Definition nbtree.h:213
#define SK_BT_REQBKWD
Definition nbtree.h:1105
#define P_RIGHTMOST(opaque)
Definition nbtree.h:220
#define SK_BT_NULLS_FIRST
Definition nbtree.h:1117
#define P_INCOMPLETE_SPLIT(opaque)
Definition nbtree.h:228
static ItemPointer BTreeTupleGetPostingN(IndexTuple posting, int n)
Definition nbtree.h:545
#define SK_BT_MAXVAL
Definition nbtree.h:1110
#define BT_READ
Definition nbtree.h:730
#define SK_BT_REQFWD
Definition nbtree.h:1104
static BlockNumber BTreeTupleGetDownLink(IndexTuple pivot)
Definition nbtree.h:557
#define SK_BT_DESC
Definition nbtree.h:1116
#define P_IGNORE(opaque)
Definition nbtree.h:226
static ItemPointer BTreeTupleGetMaxHeapTID(IndexTuple itup)
Definition nbtree.h:665
static bool BTreeTupleIsPosting(IndexTuple itup)
Definition nbtree.h:493
#define BTScanPosInvalidate(scanpos)
Definition nbtree.h:1027
#define BTScanPosUnpinIfPinned(scanpos)
Definition nbtree.h:1015
static ItemPointer BTreeTupleGetHeapTID(IndexTuple itup)
Definition nbtree.h:639
#define BT_WRITE
Definition nbtree.h:731
#define BTreeTupleGetNAtts(itup, rel)
Definition nbtree.h:578
#define SK_BT_MINVAL
Definition nbtree.h:1109
BTScanOpaqueData * BTScanOpaque
Definition nbtree.h:1097
Buffer _bt_get_endpoint(Relation rel, uint32 level, bool rightmost)
Definition nbtsearch.c:2120
static Buffer _bt_moveright(Relation rel, Relation heaprel, BTScanInsert key, Buffer buf, bool forupdate, BTStack stack, int access)
Definition nbtsearch.c:244
static int _bt_binsrch_posting(BTScanInsert key, Page page, OffsetNumber offnum)
Definition nbtsearch.c:605
bool _bt_first(IndexScanDesc scan, ScanDirection dir)
Definition nbtsearch.c:885
static bool _bt_readnextpage(IndexScanDesc scan, BlockNumber blkno, BlockNumber lastcurrblkno, ScanDirection dir, bool seized)
Definition nbtsearch.c:1847
static OffsetNumber _bt_binsrch(Relation rel, BTScanInsert key, Buffer buf)
Definition nbtsearch.c:346
static bool _bt_endpoint(IndexScanDesc scan, ScanDirection dir)
Definition nbtsearch.c:2206
static bool _bt_steppage(IndexScanDesc scan, ScanDirection dir)
Definition nbtsearch.c:1654
static bool _bt_readfirstpage(IndexScanDesc scan, OffsetNumber offnum, ScanDirection dir)
Definition nbtsearch.c:1754
static Buffer _bt_lock_and_validate_left(Relation rel, BlockNumber *blkno, BlockNumber lastcurrblkno)
Definition nbtsearch.c:1982
OffsetNumber _bt_binsrch_insert(Relation rel, BTInsertState insertstate)
Definition nbtsearch.c:477
bool _bt_next(IndexScanDesc scan, ScanDirection dir)
Definition nbtsearch.c:1593
static void _bt_returnitem(IndexScanDesc scan, BTScanOpaque so)
Definition nbtsearch.c:1629
int32 _bt_compare(Relation rel, BTScanInsert key, Page page, OffsetNumber offnum)
Definition nbtsearch.c:691
BTStack _bt_search(Relation rel, Relation heaprel, BTScanInsert key, Buffer *bufP, int access, bool returnstack)
Definition nbtsearch.c:102
static void _bt_drop_lock_and_maybe_pin(Relation rel, BTScanOpaque so)
Definition nbtsearch.c:57
void _bt_killitems(IndexScanDesc scan)
Definition nbtutils.c:191
bool _bt_check_natts(Relation rel, bool heapkeyspace, Page page, OffsetNumber offnum)
Definition nbtutils.c:958
#define InvalidOffsetNumber
Definition off.h:26
uint16 OffsetNumber
Definition off.h:24
#define OffsetNumberPrev(offsetNumber)
Definition off.h:54
#define INDEX_MAX_KEYS
static char buf[DEFAULT_XLOG_SEG_SIZE]
#define pgstat_count_index_scan(rel)
Definition pgstat.h:745
uint64_t Datum
Definition postgres.h:70
static Pointer DatumGetPointer(Datum X)
Definition postgres.h:332
static int32 DatumGetInt32(Datum X)
Definition postgres.h:202
#define InvalidOid
void PredicateLockRelation(Relation relation, Snapshot snapshot)
Definition predicate.c:2505
static int fb(int x)
short access
#define RelationGetDescr(relation)
Definition rel.h:542
#define RelationGetRelationName(relation)
Definition rel.h:550
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition rel.h:535
void ScanKeyEntryInitialize(ScanKey entry, int flags, AttrNumber attributeNumber, StrategyNumber strategy, Oid subtype, Oid collation, RegProcedure procedure, Datum argument)
Definition scankey.c:32
void ScanKeyEntryInitializeWithInfo(ScanKey entry, int flags, AttrNumber attributeNumber, StrategyNumber strategy, Oid subtype, Oid collation, FmgrInfo *finfo, Datum argument)
Definition scankey.c:101
#define ScanDirectionIsForward(direction)
Definition sdir.h:64
#define ScanDirectionIsBackward(direction)
Definition sdir.h:50
ScanDirection
Definition sdir.h:25
#define SK_ROW_HEADER
Definition skey.h:117
#define SK_ROW_MEMBER
Definition skey.h:118
#define SK_SEARCHNOTNULL
Definition skey.h:122
#define SK_ROW_END
Definition skey.h:119
ScanKeyData * ScanKey
Definition skey.h:75
#define SK_ISNULL
Definition skey.h:115
uint16 StrategyNumber
Definition stratnum.h:22
#define BTGreaterStrategyNumber
Definition stratnum.h:33
#define InvalidStrategy
Definition stratnum.h:24
#define BTLessStrategyNumber
Definition stratnum.h:29
#define BTEqualStrategyNumber
Definition stratnum.h:31
#define BTLessEqualStrategyNumber
Definition stratnum.h:30
#define BTGreaterEqualStrategyNumber
Definition stratnum.h:32
ScanKey high_compare
Definition nbtree.h:1050
ScanKey low_compare
Definition nbtree.h:1049
BlockNumber btpo_next
Definition nbtree.h:66
BlockNumber btpo_prev
Definition nbtree.h:65
uint32 btpo_level
Definition nbtree.h:67
ItemPointer scantid
Definition nbtree.h:802
bool allequalimage
Definition nbtree.h:798
bool heapkeyspace
Definition nbtree.h:797
ScanKeyData scankeys[INDEX_MAX_KEYS]
Definition nbtree.h:804
struct ParallelIndexScanDescData * parallel_scan
Definition relscan.h:204
struct IndexScanInstrumentation * instrument
Definition relscan.h:172
IndexTuple xs_itup
Definition relscan.h:180
Relation indexRelation
Definition relscan.h:150
ItemPointerData xs_heaptid
Definition relscan.h:185
struct SnapshotData * xs_snapshot
Definition relscan.h:151
Oid * rd_opcintype
Definition rel.h:208
Oid * rd_opfamily
Definition rel.h:207
int sk_flags
Definition skey.h:66
static ItemArray items
#define IsolationIsSerializable()
Definition xact.h:53