30#define LOOK_AHEAD_REQUIRED_RECHECKS 3
31#define LOOK_AHEAD_DEFAULT_DISTANCE 5
32#define NSKIPADVANCES_THRESHOLD 3
35 Datum tupdatum,
bool tupnull,
38 Datum tupdatum,
bool tupnull,
40 int32 *set_elem_result);
42 int32 set_elem_result,
Datum tupdatum,
bool tupnull);
49 bool *skip_array_set);
52 bool readpagetup,
int sktrig,
bool *scanBehind);
55 int sktrig,
bool sktrig_required);
56#ifdef USE_ASSERT_CHECKING
57static bool _bt_verify_keys_with_arraykeys(
IndexScanDesc scan);
63 bool advancenonrequired,
bool forcenonrequired,
64 bool *continuescan,
int *ikey);
68 ScanDirection dir,
bool forcenonrequired,
bool *continuescan);
126 key->heapkeyspace =
true;
127 key->allequalimage =
false;
129 key->anynullkeys =
false;
130 key->nextkey =
false;
131 key->backward =
false;
132 key->keysz =
Min(indnkeyatts, tupnatts);
133 key->scantid =
key->heapkeyspace && itup ?
135 skey =
key->scankeys;
136 for (
i = 0;
i < indnkeyatts;
i++)
172 key->anynullkeys =
true;
179 if (rel->
rd_index->indnullsnotdistinct)
180 key->anynullkeys =
false;
193 while (stack != NULL)
219 Datum tupdatum,
bool tupnull,
250 tupdatum, arrdatum));
291 Datum tupdatum,
bool tupnull,
293 int32 *set_elem_result)
335 if (high_elem >= low_elem)
344 *set_elem_result = result;
351 if (high_elem < low_elem)
354 *set_elem_result = 1;
363 if (high_elem >= low_elem)
372 *set_elem_result = result;
375 mid_elem = high_elem;
379 if (high_elem < low_elem)
382 *set_elem_result = -1;
388 while (high_elem > low_elem)
390 mid_elem = low_elem + ((high_elem - low_elem) / 2);
407 low_elem = mid_elem + 1;
409 high_elem = mid_elem;
417 if (low_elem != mid_elem)
421 *set_elem_result = result;
446 Datum tupdatum,
bool tupnull,
448 int32 *set_elem_result)
460 *set_elem_result = 0;
467 *set_elem_result = -1;
469 *set_elem_result = 1;
477 *set_elem_result = 0;
489 *set_elem_result = -1;
495 *set_elem_result = 1;
508 *set_elem_result = 1;
514 *set_elem_result = -1;
521#ifdef USE_ASSERT_CHECKING
553 int32 set_elem_result,
Datum tupdatum,
bool tupnull)
686 else if (low_not_high)
708 Datum dec_sk_argument;
841 Datum inc_sk_argument;
978 bool *skip_array_set)
994 *skip_array_set =
true;
1084 bool readpagetup,
int sktrig,
bool *scanBehind)
1090 Assert(sktrig == 0 || readpagetup);
1091 Assert(!readpagetup || scanBehind == NULL);
1094 *scanBehind =
false;
1096 for (
int ikey = sktrig; ikey < so->
numberOfKeys; ikey++)
1104 Assert(!readpagetup || ikey == sktrig);
1116 Assert(ikey > sktrig || ikey == 0);
1120 if (
cur->sk_attno > tupnatts)
1205 for (
int arrayidx = 0; arrayidx < so->
numArrayKeys; arrayidx++)
1213 array,
cur, &result);
1244 if (readpagetup || result != 0)
1395 int sktrig,
bool sktrig_required)
1401 bool beyond_end_advance =
false,
1402 skip_array_advanced =
false,
1403 has_required_opposite_direction_only =
false,
1404 all_required_satisfied =
true,
1405 all_satisfied =
true;
1408 Assert(_bt_verify_keys_with_arraykeys(scan));
1410 if (sktrig_required)
1416 tupnatts,
false, 0, NULL));
1425 else if (sktrig < so->numberOfKeys - 1 &&
1441 false, &continuescan,
1475 has_required_opposite_direction_only =
true;
1486 if (
cur->sk_attno > tupnatts)
1515 if (ikey == sktrig && !array)
1520 beyond_end_advance =
true;
1521 all_satisfied = all_required_satisfied =
false;
1551 if (beyond_end_advance)
1578 if (!all_required_satisfied ||
cur->sk_attno > tupnatts)
1595 bool cur_elem_trig = (sktrig_required && ikey == sktrig);
1603 tupdatum, tupnull, array,
cur,
1612 tupdatum, tupnull, array,
cur,
1662 beyond_end_advance =
true;
1664 Assert(all_required_satisfied && all_satisfied);
1673 all_satisfied =
false;
1675 all_required_satisfied =
false;
1697 skip_array_advanced =
true;
1699 else if (array->
cur_elem != set_elem)
1714 if (beyond_end_advance &&
1716 goto end_toplevel_scan;
1718 Assert(_bt_verify_keys_with_arraykeys(scan));
1724 if (sktrig_required && skip_array_advanced)
1750 if ((sktrig_required && all_required_satisfied) ||
1751 (!sktrig_required && all_satisfied))
1753 int nsktrig = sktrig + 1;
1756 Assert(all_required_satisfied);
1760 !sktrig_required, &continuescan,
1765 Assert(all_satisfied && continuescan);
1800 Assert(!beyond_end_advance);
1804 tupdesc, nsktrig,
true);
1823 if (!sktrig_required)
1846 !all_required_satisfied);
1856 if (!all_required_satisfied && pstate->
finaltup == tuple)
1867 if (!all_required_satisfied && pstate->
finaltup &&
1939 else if (has_required_opposite_direction_only && pstate->
finaltup &&
2066#ifdef USE_ASSERT_CHECKING
2077 bool nonrequiredseen =
false;
2103 if (last_sk_attno >
cur->sk_attno)
2105 if (nonrequiredseen)
2109 nonrequiredseen =
true;
2111 last_sk_attno =
cur->sk_attno;
2175#ifdef USE_ASSERT_CHECKING
2194 Assert(arrayKeys || ikey == dikey);
2290 nfinaltupatts,
false, 0, &scanBehind))
2347 false, &continuescan,
2401 firstchangingattnum;
2402 bool start_past_saop_eq =
false;
2444 bool satisfied =
false;
2449 bool firstsatisfies =
false;
2451 if (subkey->
sk_attno > firstchangingattnum)
2459 tupdesc, &firstnull);
2461 tupdesc, &lastnull);
2463 if (firstnull || lastnull)
2480 if (!firstsatisfies)
2499 if (!firstsatisfies)
2553 if (
key->sk_attno > firstchangingattnum)
2565 if (firstnull || lastnull)
2575 key->sk_collation, firstdatum,
2582 key->sk_collation, lastdatum,
2603 if (
key->sk_attno >= firstchangingattnum)
2621 key->sk_collation, firstdatum,
2640 if (
key->sk_attno >= firstchangingattnum)
2647 firstdatum, firstnull, array,
key,
2653 start_past_saop_eq =
true;
2678 if (
key->sk_attno > firstchangingattnum)
2687 firstdatum, firstnull, array,
key,
2694 lastdatum, lastnull, array,
key,
2787 bool advancenonrequired,
bool forcenonrequired,
2788 bool *continuescan,
int *ikey)
2792 *continuescan =
true;
2799 bool requiredSameDir =
false,
2800 requiredOppositeDirOnly =
false;
2807 if (forcenonrequired)
2813 requiredSameDir =
true;
2816 requiredOppositeDirOnly =
true;
2818 if (
key->sk_attno > tupnatts)
2839 Assert(requiredSameDir || forcenonrequired);
2846 if (forcenonrequired)
2848 tupdesc, *ikey,
false);
2850 *continuescan =
false;
2858 forcenonrequired, continuescan))
2889 if (requiredSameDir)
2890 *continuescan =
false;
2899 Assert(forcenonrequired && *ikey > 0);
2920 tupdesc, *ikey,
false);
2936 if ((requiredSameDir || requiredOppositeDirOnly) &&
2938 *continuescan =
false;
2954 if ((requiredSameDir || requiredOppositeDirOnly) &&
2956 *continuescan =
false;
2966 datum,
key->sk_argument)))
2973 if (requiredSameDir)
2974 *continuescan =
false;
2982 else if (advancenonrequired &&
2986 tupdesc, *ikey,
false);
3016 satisfied = (cmpresult < 0);
3019 satisfied = (cmpresult <= 0);
3022 satisfied = (cmpresult >= 0);
3025 satisfied = (cmpresult > 0);
3092 bool forcenonrequired,
bool *continuescan)
3095 int32 cmpresult = 0;
3123 if (forcenonrequired)
3129 *continuescan =
false;
3132 *continuescan =
false;
3157 if (forcenonrequired)
3195 if ((subkey->
sk_flags & reqflags) &&
3197 *continuescan =
false;
3233 if ((subkey->
sk_flags & reqflags) &&
3235 *continuescan =
false;
3265 if (!result && !forcenonrequired)
3275 *continuescan =
false;
3278 *continuescan =
false;
3353 pstate->
skip = aheadoffnum + 1;
3355 pstate->
skip = aheadoffnum - 1;
3410 bool killedsomething =
false;
3456 for (
int i = 0;
i < numKilled;
i++)
3463 itemIndex <= so->currPos.lastItem);
3464 if (offnum < minoff)
3466 while (offnum <= maxoff)
3470 bool killtuple =
false;
3492 for (
j = 0;
j < nposting;
j++)
3551 killedsomething =
true;
3565 if (killedsomething)
3684 elog(
ERROR,
"multiple active vacuums for index \"%s\"",
3794 offsetof(
BTOptions, vacuum_cleanup_index_scale_factor)},
3814 bool *res,
bool *isnull)
3840 return "initializing";
3842 return "scanning table";
3844 return "sorting live tuples";
3846 return "sorting dead tuples";
3848 return "loading tuples in tree";
3903#ifdef DEBUG_NO_TRUNCATE
3905 keepnatts = nkeyatts + 1;
3909 Min(keepnatts, nkeyatts));
3918 Assert(keepnatts == nkeyatts || keepnatts == nkeyatts + 1);
3920 pivot->
t_info &= ~INDEX_SIZE_MASK;
3928 if (keepnatts <= nkeyatts)
3957 tidpivot->
t_info &= ~INDEX_SIZE_MASK;
3958 tidpivot->
t_info |= newsize;
3981#ifndef DEBUG_NO_TRUNCATE
4056 if (isNull1 != isNull2)
4121 if (isNull1 != isNull2)
4201 return tupnatts == natts;
4217 return tupnatts == nkeyatts;
4233 return tupnatts == 0;
4247 return tupnatts == 0 ||
4259 return tupnatts == nkeyatts;
4293 return tupnatts > 0 && tupnatts <= nkeyatts;
4335 elog(
ERROR,
"cannot insert oversized tuple of size %zu on internal page of index \"%s\"",
4339 (
errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
4340 errmsg(
"index row size %zu exceeds btree version %u maximum %zu for index \"%s\"",
4345 errdetail(
"Index row references tuple (%u,%u) in relation \"%s\".",
4349 errhint(
"Values larger than 1/3 of a buffer page cannot be indexed.\n"
4350 "Consider a function index of an MD5 hash of the value, "
4351 "or use full text indexing."),
4368 bool allequalimage =
true;
4393 allequalimage =
false;
4401 elog(
DEBUG1,
"index \"%s\" can safely use deduplication",
4404 elog(
DEBUG1,
"index \"%s\" cannot use deduplication",
4408 return allequalimage;
#define InvalidAttrNumber
static bool validate(Port *port, const char *auth)
XLogRecPtr BufferGetLSNAtomic(Buffer buffer)
void MarkBufferDirtyHint(Buffer buffer, bool buffer_std)
static Page BufferGetPage(Buffer buffer)
static void * PageGetItem(const PageData *page, const ItemIdData *itemId)
static ItemId PageGetItemId(Page page, OffsetNumber offsetNumber)
static OffsetNumber PageGetMaxOffsetNumber(const PageData *page)
#define INVERT_COMPARE_RESULT(var)
#define PG_USED_FOR_ASSERTS_ONLY
#define FLEXIBLE_ARRAY_MEMBER
#define OidIsValid(objectId)
Datum datumCopy(Datum value, bool typByVal, int typLen)
bool datum_image_eq(Datum value1, Datum value2, bool typByVal, int typLen)
int errdetail(const char *fmt,...)
int errhint(const char *fmt,...)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Datum OidFunctionCall1Coll(Oid functionId, Oid collation, Datum arg1)
Assert(PointerIsAligned(start, uint64))
FmgrInfo * index_getprocinfo(Relation irel, AttrNumber attnum, uint16 procnum)
IndexTuple index_truncate_tuple(TupleDesc sourceDescriptor, IndexTuple source, int leavenatts)
if(TABLE==NULL||TABLE_index==NULL)
#define ItemIdMarkDead(itemId)
#define ItemIdIsDead(itemId)
int32 ItemPointerCompare(const ItemPointerData *arg1, const ItemPointerData *arg2)
bool ItemPointerEquals(const ItemPointerData *pointer1, const ItemPointerData *pointer2)
static void ItemPointerSetOffsetNumber(ItemPointerData *pointer, OffsetNumber offsetNumber)
static OffsetNumber ItemPointerGetOffsetNumber(const ItemPointerData *pointer)
static OffsetNumber ItemPointerGetOffsetNumberNoCheck(const ItemPointerData *pointer)
static BlockNumber ItemPointerGetBlockNumber(const ItemPointerData *pointer)
static void ItemPointerCopy(const ItemPointerData *fromPointer, ItemPointerData *toPointer)
IndexTupleData * IndexTuple
static Datum index_getattr(IndexTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
static Size IndexTupleSize(const IndexTupleData *itup)
#define MaxIndexTuplesPerPage
Oid get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum)
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
void LWLockRelease(LWLock *lock)
void pfree(void *pointer)
void * palloc0(Size size)
void _bt_relbuf(Relation rel, Buffer buf)
void _bt_metaversion(Relation rel, bool *heapkeyspace, bool *allequalimage)
Buffer _bt_getbuf(Relation rel, BlockNumber blkno, int access)
void _bt_unlockbuf(Relation rel, Buffer buf)
void _bt_lockbuf(Relation rel, Buffer buf, int access)
void _bt_parallel_primscan_schedule(IndexScanDesc scan, BlockNumber curr_page)
void _bt_parallel_done(IndexScanDesc scan)
#define BTScanPosIsPinned(scanpos)
#define BT_PIVOT_HEAP_TID_ATTR
static uint16 BTreeTupleGetNPosting(IndexTuple posting)
static bool BTreeTupleIsPivot(IndexTuple itup)
#define PROGRESS_BTREE_PHASE_PERFORMSORT_2
#define PROGRESS_BTREE_PHASE_LEAF_LOAD
#define BTEQUALIMAGE_PROC
#define P_LEFTMOST(opaque)
#define BTPageGetOpaque(page)
#define BTScanPosIsValid(scanpos)
#define PROGRESS_BTREE_PHASE_INDEXBUILD_TABLESCAN
#define SK_BT_INDOPTION_SHIFT
#define P_FIRSTDATAKEY(opaque)
#define PROGRESS_BTREE_PHASE_PERFORMSORT_1
static uint32 BTreeTupleGetPostingOffset(IndexTuple posting)
#define P_RIGHTMOST(opaque)
#define SK_BT_NULLS_FIRST
static ItemPointer BTreeTupleGetPostingN(IndexTuple posting, int n)
static ItemPointer BTreeTupleGetMaxHeapTID(IndexTuple itup)
static bool BTreeTupleIsPosting(IndexTuple itup)
#define BTREE_NOVAC_VERSION
#define BTMaxItemSizeNoHeapTid
static ItemPointer BTreeTupleGetHeapTID(IndexTuple itup)
static void BTreeTupleSetNAtts(IndexTuple itup, uint16 nkeyatts, bool heaptid)
#define BTreeTupleGetNAtts(itup, rel)
BTScanOpaqueData * BTScanOpaque
void _bt_check_third_page(Relation rel, Relation heap, bool needheaptidspace, Page page, IndexTuple newtup)
bool _bt_scanbehind_checkkeys(IndexScanDesc scan, ScanDirection dir, IndexTuple finaltup)
void _bt_end_vacuum(Relation rel)
static void _bt_binsrch_skiparray_skey(bool cur_elem_trig, ScanDirection dir, Datum tupdatum, bool tupnull, BTArrayKeyInfo *array, ScanKey cur, int32 *set_elem_result)
static void _bt_array_set_low_or_high(Relation rel, ScanKey skey, BTArrayKeyInfo *array, bool low_not_high)
bool _bt_checkkeys(IndexScanDesc scan, BTReadPageState *pstate, bool arrayKeys, IndexTuple tuple, int tupnatts)
static void _bt_skiparray_set_element(Relation rel, ScanKey skey, BTArrayKeyInfo *array, int32 set_elem_result, Datum tupdatum, bool tupnull)
void _bt_end_vacuum_callback(int code, Datum arg)
#define NSKIPADVANCES_THRESHOLD
int _bt_binsrch_array_skey(FmgrInfo *orderproc, bool cur_elem_trig, ScanDirection dir, Datum tupdatum, bool tupnull, BTArrayKeyInfo *array, ScanKey cur, int32 *set_elem_result)
void _bt_freestack(BTStack stack)
void BTreeShmemInit(void)
struct BTVacInfo BTVacInfo
BTCycleId _bt_vacuum_cycleid(Relation rel)
BTScanInsert _bt_mkscankey(Relation rel, IndexTuple itup)
void _bt_killitems(IndexScanDesc scan)
static bool _bt_advance_array_keys(IndexScanDesc scan, BTReadPageState *pstate, IndexTuple tuple, int tupnatts, TupleDesc tupdesc, int sktrig, bool sktrig_required)
bool _bt_start_prim_scan(IndexScanDesc scan, ScanDirection dir)
bool _bt_check_natts(Relation rel, bool heapkeyspace, Page page, OffsetNumber offnum)
IndexTuple _bt_truncate(Relation rel, IndexTuple lastleft, IndexTuple firstright, BTScanInsert itup_key)
#define LOOK_AHEAD_REQUIRED_RECHECKS
static bool _bt_rowcompare_cmpresult(ScanKey subkey, int cmpresult)
static bool _bt_oppodir_checkkeys(IndexScanDesc scan, ScanDirection dir, IndexTuple finaltup)
int _bt_keep_natts_fast(Relation rel, IndexTuple lastleft, IndexTuple firstright)
#define LOOK_AHEAD_DEFAULT_DISTANCE
static bool _bt_check_rowcompare(ScanKey header, IndexTuple tuple, int tupnatts, TupleDesc tupdesc, ScanDirection dir, bool forcenonrequired, bool *continuescan)
static BTVacInfo * btvacinfo
static bool _bt_check_compare(IndexScanDesc scan, ScanDirection dir, IndexTuple tuple, int tupnatts, TupleDesc tupdesc, bool advancenonrequired, bool forcenonrequired, bool *continuescan, int *ikey)
void _bt_set_startikey(IndexScanDesc scan, BTReadPageState *pstate)
static bool _bt_array_decrement(Relation rel, ScanKey skey, BTArrayKeyInfo *array)
char * btbuildphasename(int64 phasenum)
static bool _bt_tuple_before_array_skeys(IndexScanDesc scan, ScanDirection dir, IndexTuple tuple, TupleDesc tupdesc, int tupnatts, bool readpagetup, int sktrig, bool *scanBehind)
bytea * btoptions(Datum reloptions, bool validate)
Size BTreeShmemSize(void)
static int _bt_keep_natts(Relation rel, IndexTuple lastleft, IndexTuple firstright, BTScanInsert itup_key)
bool btproperty(Oid index_oid, int attno, IndexAMProperty prop, const char *propname, bool *res, bool *isnull)
static void _bt_skiparray_set_isnull(Relation rel, ScanKey skey, BTArrayKeyInfo *array)
bool _bt_allequalimage(Relation rel, bool debugmessage)
static bool _bt_advance_array_keys_increment(IndexScanDesc scan, ScanDirection dir, bool *skip_array_set)
static void _bt_checkkeys_look_ahead(IndexScanDesc scan, BTReadPageState *pstate, int tupnatts, TupleDesc tupdesc)
static int32 _bt_compare_array_skey(FmgrInfo *orderproc, Datum tupdatum, bool tupnull, Datum arrdatum, ScanKey cur)
struct BTOneVacInfo BTOneVacInfo
void _bt_start_array_keys(IndexScanDesc scan, ScanDirection dir)
BTCycleId _bt_start_vacuum(Relation rel)
static bool _bt_array_increment(Relation rel, ScanKey skey, BTArrayKeyInfo *array)
#define OffsetNumberNext(offsetNumber)
#define FirstOffsetNumber
#define OffsetNumberPrev(offsetNumber)
static bool DatumGetBool(Datum X)
static Datum ObjectIdGetDatum(Oid X)
static Pointer DatumGetPointer(Datum X)
static int32 DatumGetInt32(Datum X)
#define PROGRESS_CREATEIDX_SUBPHASE_INITIALIZE
#define RelationGetDescr(relation)
#define RelationGetRelationName(relation)
#define RelationNeedsWAL(relation)
#define IndexRelationGetNumberOfAttributes(relation)
#define IndexRelationGetNumberOfKeyAttributes(relation)
int errtableconstraint(Relation rel, const char *conname)
void * build_reloptions(Datum reloptions, bool validate, relopt_kind kind, Size relopt_struct_size, const relopt_parse_elt *relopt_elems, int num_relopt_elems)
void ScanKeyEntryInitializeWithInfo(ScanKey entry, int flags, AttrNumber attributeNumber, StrategyNumber strategy, Oid subtype, Oid collation, FmgrInfo *finfo, Datum argument)
#define ScanDirectionIsForward(direction)
#define ScanDirectionIsBackward(direction)
#define ScanDirectionIsNoMovement(direction)
@ NoMovementScanDirection
Size add_size(Size s1, Size s2)
Size mul_size(Size s1, Size s2)
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
#define BTGreaterStrategyNumber
#define BTLessStrategyNumber
#define BTEqualStrategyNumber
#define BTLessEqualStrategyNumber
#define BTGreaterEqualStrategyNumber
ScanKeyData scankeys[INDEX_MAX_KEYS]
BTArrayKeyInfo * arrayKeys
BTScanPosItem items[MaxTIDsPerBTreePage]
struct BTStackData * bts_parent
BTOneVacInfo vacuums[FLEXIBLE_ARRAY_MEMBER]
struct ParallelIndexScanDescData * parallel_scan
StrategyNumber sk_strategy
SkipSupportIncDec decrement
SkipSupportIncDec increment
static CompactAttribute * TupleDescCompactAttr(TupleDesc tupdesc, int i)