mirror of
https://github.com/postgres/postgres.git
synced 2025-07-28 23:42:10 +03:00
Refactor nbtree insertion scankeys.
Use dedicated struct to represent nbtree insertion scan keys. Having a dedicated struct makes the difference between search type scankeys and insertion scankeys a lot clearer, and simplifies the signature of several related functions. This is based on a suggestion by Andrey Lepikhov. Streamline how unique index insertions cache binary search progress. Cache the state of in-progress binary searches within _bt_check_unique() for later instead of having callers avoid repeating the binary search in an ad-hoc manner. This makes it easy to add a new optimization: _bt_check_unique() now falls out of its loop immediately in the common case where it's already clear that there couldn't possibly be a duplicate. The new _bt_check_unique() scheme makes it a lot easier to manage cached binary search effort afterwards, from within _bt_findinsertloc(). This is needed for the upcoming patch to make nbtree tuples unique by treating heap TID as a final tiebreaker column. Unique key binary searches need to restore lower and upper bounds. They cannot simply continue to use the >= lower bound as the offset to insert at, because the heap TID tiebreaker column must be used in comparisons for the restored binary search (unlike the original _bt_check_unique() binary search, where scankey's heap TID column must be omitted). Author: Peter Geoghegan, Heikki Linnakangas Reviewed-By: Heikki Linnakangas, Andrey Lepikhov Discussion: https://postgr.es/m/CAH2-WzmE6AhUdk9NdWBf4K3HjWXZBX3+umC7mH7+WDrKcRtsOw@mail.gmail.com
This commit is contained in:
@ -56,34 +56,37 @@ static bool _bt_check_rowcompare(ScanKey skey,
|
||||
* Build an insertion scan key that contains comparison data from itup
|
||||
* as well as comparator routines appropriate to the key datatypes.
|
||||
*
|
||||
* The result is intended for use with _bt_compare().
|
||||
* Result is intended for use with _bt_compare(). Callers that don't
|
||||
* need to fill out the insertion scankey arguments (e.g. they use an
|
||||
* ad-hoc comparison routine) can pass a NULL index tuple.
|
||||
*/
|
||||
ScanKey
|
||||
BTScanInsert
|
||||
_bt_mkscankey(Relation rel, IndexTuple itup)
|
||||
{
|
||||
BTScanInsert key;
|
||||
ScanKey skey;
|
||||
TupleDesc itupdesc;
|
||||
int indnatts PG_USED_FOR_ASSERTS_ONLY;
|
||||
int indnkeyatts;
|
||||
int16 *indoption;
|
||||
int tupnatts;
|
||||
int i;
|
||||
|
||||
itupdesc = RelationGetDescr(rel);
|
||||
indnatts = IndexRelationGetNumberOfAttributes(rel);
|
||||
indnkeyatts = IndexRelationGetNumberOfKeyAttributes(rel);
|
||||
indoption = rel->rd_indoption;
|
||||
tupnatts = itup ? BTreeTupleGetNAtts(itup, rel) : 0;
|
||||
|
||||
Assert(indnkeyatts > 0);
|
||||
Assert(indnkeyatts <= indnatts);
|
||||
Assert(BTreeTupleGetNAtts(itup, rel) == indnatts ||
|
||||
BTreeTupleGetNAtts(itup, rel) == indnkeyatts);
|
||||
Assert(tupnatts <= IndexRelationGetNumberOfAttributes(rel));
|
||||
|
||||
/*
|
||||
* We'll execute search using scan key constructed on key columns. Non-key
|
||||
* (INCLUDE index) columns are always omitted from scan keys.
|
||||
*/
|
||||
skey = (ScanKey) palloc(indnkeyatts * sizeof(ScanKeyData));
|
||||
|
||||
key = palloc(offsetof(BTScanInsertData, scankeys) +
|
||||
sizeof(ScanKeyData) * indnkeyatts);
|
||||
key->nextkey = false;
|
||||
key->keysz = Min(indnkeyatts, tupnatts);
|
||||
skey = key->scankeys;
|
||||
for (i = 0; i < indnkeyatts; i++)
|
||||
{
|
||||
FmgrInfo *procinfo;
|
||||
@ -96,7 +99,19 @@ _bt_mkscankey(Relation rel, IndexTuple itup)
|
||||
* comparison can be needed.
|
||||
*/
|
||||
procinfo = index_getprocinfo(rel, i + 1, BTORDER_PROC);
|
||||
arg = index_getattr(itup, i + 1, itupdesc, &null);
|
||||
|
||||
/*
|
||||
* Key arguments built when caller provides no tuple are
|
||||
* defensively represented as NULL values. They should never be
|
||||
* used.
|
||||
*/
|
||||
if (i < tupnatts)
|
||||
arg = index_getattr(itup, i + 1, itupdesc, &null);
|
||||
else
|
||||
{
|
||||
arg = (Datum) 0;
|
||||
null = true;
|
||||
}
|
||||
flags = (null ? SK_ISNULL : 0) | (indoption[i] << SK_BT_INDOPTION_SHIFT);
|
||||
ScanKeyEntryInitializeWithInfo(&skey[i],
|
||||
flags,
|
||||
@ -108,64 +123,7 @@ _bt_mkscankey(Relation rel, IndexTuple itup)
|
||||
arg);
|
||||
}
|
||||
|
||||
return skey;
|
||||
}
|
||||
|
||||
/*
|
||||
* _bt_mkscankey_nodata
|
||||
* Build an insertion scan key that contains 3-way comparator routines
|
||||
* appropriate to the key datatypes, but no comparison data. The
|
||||
* comparison data ultimately used must match the key datatypes.
|
||||
*
|
||||
* The result cannot be used with _bt_compare(), unless comparison
|
||||
* data is first stored into the key entries. Currently this
|
||||
* routine is only called by nbtsort.c and tuplesort.c, which have
|
||||
* their own comparison routines.
|
||||
*/
|
||||
ScanKey
|
||||
_bt_mkscankey_nodata(Relation rel)
|
||||
{
|
||||
ScanKey skey;
|
||||
int indnkeyatts;
|
||||
int16 *indoption;
|
||||
int i;
|
||||
|
||||
indnkeyatts = IndexRelationGetNumberOfKeyAttributes(rel);
|
||||
indoption = rel->rd_indoption;
|
||||
|
||||
skey = (ScanKey) palloc(indnkeyatts * sizeof(ScanKeyData));
|
||||
|
||||
for (i = 0; i < indnkeyatts; i++)
|
||||
{
|
||||
FmgrInfo *procinfo;
|
||||
int flags;
|
||||
|
||||
/*
|
||||
* We can use the cached (default) support procs since no cross-type
|
||||
* comparison can be needed.
|
||||
*/
|
||||
procinfo = index_getprocinfo(rel, i + 1, BTORDER_PROC);
|
||||
flags = SK_ISNULL | (indoption[i] << SK_BT_INDOPTION_SHIFT);
|
||||
ScanKeyEntryInitializeWithInfo(&skey[i],
|
||||
flags,
|
||||
(AttrNumber) (i + 1),
|
||||
InvalidStrategy,
|
||||
InvalidOid,
|
||||
rel->rd_indcollation[i],
|
||||
procinfo,
|
||||
(Datum) 0);
|
||||
}
|
||||
|
||||
return skey;
|
||||
}
|
||||
|
||||
/*
|
||||
* free a scan key made by either _bt_mkscankey or _bt_mkscankey_nodata.
|
||||
*/
|
||||
void
|
||||
_bt_freeskey(ScanKey skey)
|
||||
{
|
||||
pfree(skey);
|
||||
return key;
|
||||
}
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user