diff options
author | Teodor Sigaev <teodor@sigaev.ru> | 2018-04-07 23:00:39 +0300 |
---|---|---|
committer | Teodor Sigaev <teodor@sigaev.ru> | 2018-04-07 23:00:39 +0300 |
commit | 8224de4f42ccf98e08db07b43d52fed72f962ebb (patch) | |
tree | 0c4aae878e522178def568fcd2dd274233780f88 /src/backend/utils/cache/relcache.c | |
parent | 01bb85169afadfe63e2f0e344ff671292080de7e (diff) | |
download | postgresql-8224de4f42ccf98e08db07b43d52fed72f962ebb.tar.gz postgresql-8224de4f42ccf98e08db07b43d52fed72f962ebb.zip |
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
Diffstat (limited to 'src/backend/utils/cache/relcache.c')
-rw-r--r-- | src/backend/utils/cache/relcache.c | 87 |
1 files changed, 50 insertions, 37 deletions
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 40a2c1df049..e81c4691ec2 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -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); } |