mirror of
https://github.com/postgres/postgres.git
synced 2025-07-05 07:21:24 +03:00
Indexes with INCLUDE columns and their support in B-tree
This patch introduces INCLUDE clause to index definition. This clause specifies a list of columns which will be included as a non-key part in the index. The INCLUDE columns exist solely to allow more queries to benefit from index-only scans. Also, such columns don't need to have appropriate operator classes. Expressions are not supported as INCLUDE columns since they cannot be used in index-only scans. Index access methods supporting INCLUDE are indicated by amcaninclude flag in IndexAmRoutine. For now, only B-tree indexes support INCLUDE clause. In B-tree indexes INCLUDE columns are truncated from pivot index tuples (tuples located in non-leaf pages and high keys). Therefore, B-tree indexes now might have variable number of attributes. This patch also provides generic facility to support that: pivot tuples contain number of their attributes in t_tid.ip_posid. Free 13th bit of t_info is used for indicating that. This facility will simplify further support of index suffix truncation. The changes of above are backward-compatible, pg_upgrade doesn't need special handling of B-tree indexes for that. Bump catalog version Author: Anastasia Lubennikova with contribition by Alexander Korotkov and me Reviewed by: Peter Geoghegan, Tomas Vondra, Antonin Houska, Jeff Janes, David Rowley, Alexander Korotkov Discussion: https://www.postgresql.org/message-id/flat/56168952.4010101@postgrespro.ru
This commit is contained in:
87
src/backend/utils/cache/relcache.c
vendored
87
src/backend/utils/cache/relcache.c
vendored
@ -538,7 +538,7 @@ RelationBuildTupleDesc(Relation relation)
|
||||
/*
|
||||
* add attribute data to relation->rd_att
|
||||
*/
|
||||
need = relation->rd_rel->relnatts;
|
||||
need = RelationGetNumberOfAttributes(relation);
|
||||
|
||||
while (HeapTupleIsValid(pg_attribute_tuple = systable_getnext(pg_attribute_scan)))
|
||||
{
|
||||
@ -548,7 +548,7 @@ RelationBuildTupleDesc(Relation relation)
|
||||
attp = (Form_pg_attribute) GETSTRUCT(pg_attribute_tuple);
|
||||
|
||||
attnum = attp->attnum;
|
||||
if (attnum <= 0 || attnum > relation->rd_rel->relnatts)
|
||||
if (attnum <= 0 || attnum > RelationGetNumberOfAttributes(relation))
|
||||
elog(ERROR, "invalid attribute number %d for %s",
|
||||
attp->attnum, RelationGetRelationName(relation));
|
||||
|
||||
@ -567,7 +567,7 @@ RelationBuildTupleDesc(Relation relation)
|
||||
if (attrdef == NULL)
|
||||
attrdef = (AttrDefault *)
|
||||
MemoryContextAllocZero(CacheMemoryContext,
|
||||
relation->rd_rel->relnatts *
|
||||
RelationGetNumberOfAttributes(relation) *
|
||||
sizeof(AttrDefault));
|
||||
attrdef[ndef].adnum = attnum;
|
||||
attrdef[ndef].adbin = NULL;
|
||||
@ -650,7 +650,7 @@ RelationBuildTupleDesc(Relation relation)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < relation->rd_rel->relnatts; i++)
|
||||
for (i = 0; i < RelationGetNumberOfAttributes(relation); i++)
|
||||
Assert(TupleDescAttr(relation->rd_att, i)->attcacheoff == -1);
|
||||
}
|
||||
#endif
|
||||
@ -660,7 +660,7 @@ RelationBuildTupleDesc(Relation relation)
|
||||
* attribute: it must be zero. This eliminates the need for special cases
|
||||
* for attnum=1 that used to exist in fastgetattr() and index_getattr().
|
||||
*/
|
||||
if (relation->rd_rel->relnatts > 0)
|
||||
if (RelationGetNumberOfAttributes(relation) > 0)
|
||||
TupleDescAttr(relation->rd_att, 0)->attcacheoff = 0;
|
||||
|
||||
/*
|
||||
@ -673,7 +673,7 @@ RelationBuildTupleDesc(Relation relation)
|
||||
|
||||
if (ndef > 0) /* DEFAULTs */
|
||||
{
|
||||
if (ndef < relation->rd_rel->relnatts)
|
||||
if (ndef < RelationGetNumberOfAttributes(relation))
|
||||
constr->defval = (AttrDefault *)
|
||||
repalloc(attrdef, ndef * sizeof(AttrDefault));
|
||||
else
|
||||
@ -1557,7 +1557,8 @@ RelationInitIndexAccessInfo(Relation relation)
|
||||
int2vector *indoption;
|
||||
MemoryContext indexcxt;
|
||||
MemoryContext oldcontext;
|
||||
int natts;
|
||||
int indnatts;
|
||||
int indnkeyatts;
|
||||
uint16 amsupport;
|
||||
|
||||
/*
|
||||
@ -1587,10 +1588,11 @@ RelationInitIndexAccessInfo(Relation relation)
|
||||
relation->rd_amhandler = aform->amhandler;
|
||||
ReleaseSysCache(tuple);
|
||||
|
||||
natts = relation->rd_rel->relnatts;
|
||||
if (natts != relation->rd_index->indnatts)
|
||||
indnatts = RelationGetNumberOfAttributes(relation);
|
||||
if (indnatts != IndexRelationGetNumberOfAttributes(relation))
|
||||
elog(ERROR, "relnatts disagrees with indnatts for index %u",
|
||||
RelationGetRelid(relation));
|
||||
indnkeyatts = IndexRelationGetNumberOfKeyAttributes(relation);
|
||||
|
||||
/*
|
||||
* Make the private context to hold index access info. The reason we need
|
||||
@ -1610,17 +1612,18 @@ RelationInitIndexAccessInfo(Relation relation)
|
||||
InitIndexAmRoutine(relation);
|
||||
|
||||
/*
|
||||
* Allocate arrays to hold data
|
||||
* Allocate arrays to hold data. Opclasses are not used for included
|
||||
* columns, so allocate them for indnkeyatts only.
|
||||
*/
|
||||
relation->rd_opfamily = (Oid *)
|
||||
MemoryContextAllocZero(indexcxt, natts * sizeof(Oid));
|
||||
MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(Oid));
|
||||
relation->rd_opcintype = (Oid *)
|
||||
MemoryContextAllocZero(indexcxt, natts * sizeof(Oid));
|
||||
MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(Oid));
|
||||
|
||||
amsupport = relation->rd_amroutine->amsupport;
|
||||
if (amsupport > 0)
|
||||
{
|
||||
int nsupport = natts * amsupport;
|
||||
int nsupport = indnatts * amsupport;
|
||||
|
||||
relation->rd_support = (RegProcedure *)
|
||||
MemoryContextAllocZero(indexcxt, nsupport * sizeof(RegProcedure));
|
||||
@ -1634,10 +1637,10 @@ RelationInitIndexAccessInfo(Relation relation)
|
||||
}
|
||||
|
||||
relation->rd_indcollation = (Oid *)
|
||||
MemoryContextAllocZero(indexcxt, natts * sizeof(Oid));
|
||||
MemoryContextAllocZero(indexcxt, indnatts * sizeof(Oid));
|
||||
|
||||
relation->rd_indoption = (int16 *)
|
||||
MemoryContextAllocZero(indexcxt, natts * sizeof(int16));
|
||||
MemoryContextAllocZero(indexcxt, indnatts * sizeof(int16));
|
||||
|
||||
/*
|
||||
* indcollation cannot be referenced directly through the C struct,
|
||||
@ -1650,7 +1653,7 @@ RelationInitIndexAccessInfo(Relation relation)
|
||||
&isnull);
|
||||
Assert(!isnull);
|
||||
indcoll = (oidvector *) DatumGetPointer(indcollDatum);
|
||||
memcpy(relation->rd_indcollation, indcoll->values, natts * sizeof(Oid));
|
||||
memcpy(relation->rd_indcollation, indcoll->values, indnatts * sizeof(Oid));
|
||||
|
||||
/*
|
||||
* indclass cannot be referenced directly through the C struct, because it
|
||||
@ -1671,7 +1674,7 @@ RelationInitIndexAccessInfo(Relation relation)
|
||||
*/
|
||||
IndexSupportInitialize(indclass, relation->rd_support,
|
||||
relation->rd_opfamily, relation->rd_opcintype,
|
||||
amsupport, natts);
|
||||
amsupport, indnkeyatts);
|
||||
|
||||
/*
|
||||
* Similarly extract indoption and copy it to the cache entry
|
||||
@ -1682,7 +1685,7 @@ RelationInitIndexAccessInfo(Relation relation)
|
||||
&isnull);
|
||||
Assert(!isnull);
|
||||
indoption = (int2vector *) DatumGetPointer(indoptionDatum);
|
||||
memcpy(relation->rd_indoption, indoption->values, natts * sizeof(int16));
|
||||
memcpy(relation->rd_indoption, indoption->values, indnatts * sizeof(int16));
|
||||
|
||||
/*
|
||||
* expressions, predicate, exclusion caches will be filled later
|
||||
@ -5064,20 +5067,28 @@ restart:
|
||||
{
|
||||
int attrnum = indexInfo->ii_KeyAttrNumbers[i];
|
||||
|
||||
/*
|
||||
* Since we have covering indexes with non-key columns, we must
|
||||
* handle them accurately here. non-key columns must be added into
|
||||
* indexattrs, since they are in index, and HOT-update shouldn't
|
||||
* miss them. Obviously, non-key columns couldn't be referenced by
|
||||
* foreign key or identity key. Hence we do not include them into
|
||||
* uindexattrs, pkindexattrs and idindexattrs bitmaps.
|
||||
*/
|
||||
if (attrnum != 0)
|
||||
{
|
||||
indexattrs = bms_add_member(indexattrs,
|
||||
attrnum - FirstLowInvalidHeapAttributeNumber);
|
||||
|
||||
if (isKey)
|
||||
if (isKey && i < indexInfo->ii_NumIndexKeyAttrs)
|
||||
uindexattrs = bms_add_member(uindexattrs,
|
||||
attrnum - FirstLowInvalidHeapAttributeNumber);
|
||||
|
||||
if (isPK)
|
||||
if (isPK && i < indexInfo->ii_NumIndexKeyAttrs)
|
||||
pkindexattrs = bms_add_member(pkindexattrs,
|
||||
attrnum - FirstLowInvalidHeapAttributeNumber);
|
||||
|
||||
if (isIDKey)
|
||||
if (isIDKey && i < indexInfo->ii_NumIndexKeyAttrs)
|
||||
idindexattrs = bms_add_member(idindexattrs,
|
||||
attrnum - FirstLowInvalidHeapAttributeNumber);
|
||||
}
|
||||
@ -5195,7 +5206,7 @@ RelationGetExclusionInfo(Relation indexRelation,
|
||||
Oid **procs,
|
||||
uint16 **strategies)
|
||||
{
|
||||
int ncols = indexRelation->rd_rel->relnatts;
|
||||
int indnkeyatts;
|
||||
Oid *ops;
|
||||
Oid *funcs;
|
||||
uint16 *strats;
|
||||
@ -5207,17 +5218,19 @@ RelationGetExclusionInfo(Relation indexRelation,
|
||||
MemoryContext oldcxt;
|
||||
int i;
|
||||
|
||||
indnkeyatts = IndexRelationGetNumberOfKeyAttributes(indexRelation);
|
||||
|
||||
/* Allocate result space in caller context */
|
||||
*operators = ops = (Oid *) palloc(sizeof(Oid) * ncols);
|
||||
*procs = funcs = (Oid *) palloc(sizeof(Oid) * ncols);
|
||||
*strategies = strats = (uint16 *) palloc(sizeof(uint16) * ncols);
|
||||
*operators = ops = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
|
||||
*procs = funcs = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
|
||||
*strategies = strats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts);
|
||||
|
||||
/* Quick exit if we have the data cached already */
|
||||
if (indexRelation->rd_exclstrats != NULL)
|
||||
{
|
||||
memcpy(ops, indexRelation->rd_exclops, sizeof(Oid) * ncols);
|
||||
memcpy(funcs, indexRelation->rd_exclprocs, sizeof(Oid) * ncols);
|
||||
memcpy(strats, indexRelation->rd_exclstrats, sizeof(uint16) * ncols);
|
||||
memcpy(ops, indexRelation->rd_exclops, sizeof(Oid) * indnkeyatts);
|
||||
memcpy(funcs, indexRelation->rd_exclprocs, sizeof(Oid) * indnkeyatts);
|
||||
memcpy(strats, indexRelation->rd_exclstrats, sizeof(uint16) * indnkeyatts);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -5266,12 +5279,12 @@ RelationGetExclusionInfo(Relation indexRelation,
|
||||
arr = DatumGetArrayTypeP(val); /* ensure not toasted */
|
||||
nelem = ARR_DIMS(arr)[0];
|
||||
if (ARR_NDIM(arr) != 1 ||
|
||||
nelem != ncols ||
|
||||
nelem != indnkeyatts ||
|
||||
ARR_HASNULL(arr) ||
|
||||
ARR_ELEMTYPE(arr) != OIDOID)
|
||||
elog(ERROR, "conexclop is not a 1-D Oid array");
|
||||
|
||||
memcpy(ops, ARR_DATA_PTR(arr), sizeof(Oid) * ncols);
|
||||
memcpy(ops, ARR_DATA_PTR(arr), sizeof(Oid) * indnkeyatts);
|
||||
}
|
||||
|
||||
systable_endscan(conscan);
|
||||
@ -5282,7 +5295,7 @@ RelationGetExclusionInfo(Relation indexRelation,
|
||||
RelationGetRelationName(indexRelation));
|
||||
|
||||
/* We need the func OIDs and strategy numbers too */
|
||||
for (i = 0; i < ncols; i++)
|
||||
for (i = 0; i < indnkeyatts; i++)
|
||||
{
|
||||
funcs[i] = get_opcode(ops[i]);
|
||||
strats[i] = get_op_opfamily_strategy(ops[i],
|
||||
@ -5295,12 +5308,12 @@ RelationGetExclusionInfo(Relation indexRelation,
|
||||
|
||||
/* Save a copy of the results in the relcache entry. */
|
||||
oldcxt = MemoryContextSwitchTo(indexRelation->rd_indexcxt);
|
||||
indexRelation->rd_exclops = (Oid *) palloc(sizeof(Oid) * ncols);
|
||||
indexRelation->rd_exclprocs = (Oid *) palloc(sizeof(Oid) * ncols);
|
||||
indexRelation->rd_exclstrats = (uint16 *) palloc(sizeof(uint16) * ncols);
|
||||
memcpy(indexRelation->rd_exclops, ops, sizeof(Oid) * ncols);
|
||||
memcpy(indexRelation->rd_exclprocs, funcs, sizeof(Oid) * ncols);
|
||||
memcpy(indexRelation->rd_exclstrats, strats, sizeof(uint16) * ncols);
|
||||
indexRelation->rd_exclops = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
|
||||
indexRelation->rd_exclprocs = (Oid *) palloc(sizeof(Oid) * indnkeyatts);
|
||||
indexRelation->rd_exclstrats = (uint16 *) palloc(sizeof(uint16) * indnkeyatts);
|
||||
memcpy(indexRelation->rd_exclops, ops, sizeof(Oid) * indnkeyatts);
|
||||
memcpy(indexRelation->rd_exclprocs, funcs, sizeof(Oid) * indnkeyatts);
|
||||
memcpy(indexRelation->rd_exclstrats, strats, sizeof(uint16) * indnkeyatts);
|
||||
MemoryContextSwitchTo(oldcxt);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user