aboutsummaryrefslogtreecommitdiff
path: root/src/backend/access/nbtree/nbtutils.c
diff options
context:
space:
mode:
authorPeter Geoghegan <pg@bowt.ie>2019-03-20 09:30:57 -0700
committerPeter Geoghegan <pg@bowt.ie>2019-03-20 09:30:57 -0700
commite5adcb789d80ba565ccacb1ed4341a7c29085238 (patch)
tree3393597468587cf5906dea6a4ae41e0a01db9ca5 /src/backend/access/nbtree/nbtutils.c
parent550b9d26f80fa3048f2d5883f0779ed29465960a (diff)
downloadpostgresql-e5adcb789d80ba565ccacb1ed4341a7c29085238.tar.gz
postgresql-e5adcb789d80ba565ccacb1ed4341a7c29085238.zip
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
Diffstat (limited to 'src/backend/access/nbtree/nbtutils.c')
-rw-r--r--src/backend/access/nbtree/nbtutils.c94
1 files changed, 26 insertions, 68 deletions
diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c
index 2c05fb5e451..0250e089a65 100644
--- a/src/backend/access/nbtree/nbtutils.c
+++ b/src/backend/access/nbtree/nbtutils.c
@@ -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,56 +99,20 @@ _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);
- flags = (null ? SK_ISNULL : 0) | (indoption[i] << SK_BT_INDOPTION_SHIFT);
- ScanKeyEntryInitializeWithInfo(&skey[i],
- flags,
- (AttrNumber) (i + 1),
- InvalidStrategy,
- InvalidOid,
- rel->rd_indcollation[i],
- procinfo,
- 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.
+ * Key arguments built when caller provides no tuple are
+ * defensively represented as NULL values. They should never be
+ * used.
*/
- procinfo = index_getprocinfo(rel, i + 1, BTORDER_PROC);
- flags = SK_ISNULL | (indoption[i] << SK_BT_INDOPTION_SHIFT);
+ 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,
(AttrNumber) (i + 1),
@@ -153,19 +120,10 @@ _bt_mkscankey_nodata(Relation rel)
InvalidOid,
rel->rd_indcollation[i],
procinfo,
- (Datum) 0);
+ arg);
}
- return skey;
-}
-
-/*
- * free a scan key made by either _bt_mkscankey or _bt_mkscankey_nodata.
- */
-void
-_bt_freeskey(ScanKey skey)
-{
- pfree(skey);
+ return key;
}
/*