mirror of
https://github.com/postgres/postgres.git
synced 2025-09-11 00:12:06 +03:00
CREATE INDEX ... INCLUDING (column[, ...])
Now indexes (but only B-tree for now) can contain "extra" column(s) which doesn't participate in index structure, they are just stored in leaf tuples. It allows to use index only scan by using single index instead of two or more indexes. Author: Anastasia Lubennikova with minor editorializing by me Reviewers: David Rowley, Peter Geoghegan, Jeff Janes
This commit is contained in:
@@ -213,7 +213,7 @@ CheckIndexCompatible(Oid oldId,
|
||||
}
|
||||
|
||||
/* Any change in operator class or collation breaks compatibility. */
|
||||
old_natts = indexForm->indnatts;
|
||||
old_natts = indexForm->indnkeyatts;
|
||||
Assert(old_natts == numberOfAttributes);
|
||||
|
||||
d = SysCacheGetAttr(INDEXRELID, tuple, Anum_pg_index_indcollation, &isnull);
|
||||
@@ -327,6 +327,7 @@ DefineIndex(Oid relationId,
|
||||
int16 *coloptions;
|
||||
IndexInfo *indexInfo;
|
||||
int numberOfAttributes;
|
||||
int numberOfKeyAttributes;
|
||||
TransactionId limitXmin;
|
||||
VirtualTransactionId *old_snapshots;
|
||||
ObjectAddress address;
|
||||
@@ -337,14 +338,27 @@ DefineIndex(Oid relationId,
|
||||
Snapshot snapshot;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* count attributes in index
|
||||
*/
|
||||
numberOfAttributes = list_length(stmt->indexParams);
|
||||
if (numberOfAttributes <= 0)
|
||||
if(list_intersection(stmt->indexParams, stmt->indexIncludingParams) != NIL)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
||||
errmsg("must specify at least one column")));
|
||||
errmsg("included columns must not intersect with key columns")));
|
||||
/*
|
||||
* count key attributes in index
|
||||
*/
|
||||
numberOfKeyAttributes = list_length(stmt->indexParams);
|
||||
|
||||
/*
|
||||
* We append any INCLUDING columns onto the indexParams list so that
|
||||
* we have one list with all columns. Later we can determine which of these
|
||||
* are key columns, and which are just part of the INCLUDING list by check
|
||||
* the list position. A list item in a position less than
|
||||
* ii_NumIndexKeyAttrs is part of the key columns, and anything equal to
|
||||
* and over is part of the INCLUDING columns.
|
||||
*/
|
||||
stmt->indexParams = list_concat(stmt->indexParams,
|
||||
stmt->indexIncludingParams);
|
||||
numberOfAttributes = list_length(stmt->indexParams);
|
||||
|
||||
if (numberOfAttributes > INDEX_MAX_KEYS)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_TOO_MANY_COLUMNS),
|
||||
@@ -507,6 +521,11 @@ DefineIndex(Oid relationId,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("access method \"%s\" does not support unique indexes",
|
||||
accessMethodName)));
|
||||
if (list_length(stmt->indexIncludingParams) > 0 && !amRoutine->amcaninclude)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("access method \"%s\" does not support included columns",
|
||||
accessMethodName)));
|
||||
if (numberOfAttributes > 1 && !amRoutine->amcanmulticol)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
@@ -544,6 +563,7 @@ DefineIndex(Oid relationId,
|
||||
*/
|
||||
indexInfo = makeNode(IndexInfo);
|
||||
indexInfo->ii_NumIndexAttrs = numberOfAttributes;
|
||||
indexInfo->ii_NumIndexKeyAttrs = numberOfKeyAttributes;
|
||||
indexInfo->ii_Expressions = NIL; /* for now */
|
||||
indexInfo->ii_ExpressionsState = NIL;
|
||||
indexInfo->ii_Predicate = make_ands_implicit((Expr *) stmt->whereClause);
|
||||
@@ -559,7 +579,7 @@ DefineIndex(Oid relationId,
|
||||
|
||||
typeObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
|
||||
collationObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
|
||||
classObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
|
||||
classObjectId = (Oid *) palloc(numberOfKeyAttributes * sizeof(Oid));
|
||||
coloptions = (int16 *) palloc(numberOfAttributes * sizeof(int16));
|
||||
ComputeIndexAttrs(indexInfo,
|
||||
typeObjectId, collationObjectId, classObjectId,
|
||||
@@ -966,16 +986,15 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
|
||||
ListCell *nextExclOp;
|
||||
ListCell *lc;
|
||||
int attn;
|
||||
int nkeycols = indexInfo->ii_NumIndexKeyAttrs;
|
||||
|
||||
/* Allocate space for exclusion operator info, if needed */
|
||||
if (exclusionOpNames)
|
||||
{
|
||||
int ncols = list_length(attList);
|
||||
|
||||
Assert(list_length(exclusionOpNames) == ncols);
|
||||
indexInfo->ii_ExclusionOps = (Oid *) palloc(sizeof(Oid) * ncols);
|
||||
indexInfo->ii_ExclusionProcs = (Oid *) palloc(sizeof(Oid) * ncols);
|
||||
indexInfo->ii_ExclusionStrats = (uint16 *) palloc(sizeof(uint16) * ncols);
|
||||
Assert(list_length(exclusionOpNames) == nkeycols);
|
||||
indexInfo->ii_ExclusionOps = (Oid *) palloc(sizeof(Oid) * nkeycols);
|
||||
indexInfo->ii_ExclusionProcs = (Oid *) palloc(sizeof(Oid) * nkeycols);
|
||||
indexInfo->ii_ExclusionStrats = (uint16 *) palloc(sizeof(uint16) * nkeycols);
|
||||
nextExclOp = list_head(exclusionOpNames);
|
||||
}
|
||||
else
|
||||
@@ -1028,6 +1047,11 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
|
||||
Node *expr = attribute->expr;
|
||||
|
||||
Assert(expr != NULL);
|
||||
|
||||
if (attn >= nkeycols)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("expressions are not supported in included columns")));
|
||||
atttype = exprType(expr);
|
||||
attcollation = exprCollation(expr);
|
||||
|
||||
@@ -1105,6 +1129,16 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
|
||||
|
||||
collationOidP[attn] = attcollation;
|
||||
|
||||
/*
|
||||
* Skip opclass and ordering options for included columns.
|
||||
*/
|
||||
if (attn >= nkeycols)
|
||||
{
|
||||
colOptionP[attn] = 0;
|
||||
attn++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Identify the opclass to use.
|
||||
*/
|
||||
|
@@ -612,7 +612,7 @@ refresh_by_match_merge(Oid matviewOid, Oid tempOid, Oid relowner,
|
||||
RelationGetRelationName(tempRel));
|
||||
diffname = make_temptable_name_n(tempname, 2);
|
||||
|
||||
relnatts = matviewRel->rd_rel->relnatts;
|
||||
relnatts = RelationGetNumberOfAttributes(matviewRel);
|
||||
usedForQual = (bool *) palloc0(sizeof(bool) * relnatts);
|
||||
|
||||
/* Open SPI context. */
|
||||
@@ -698,11 +698,11 @@ refresh_by_match_merge(Oid matviewOid, Oid tempOid, Oid relowner,
|
||||
RelationGetIndexExpressions(indexRel) == NIL &&
|
||||
RelationGetIndexPredicate(indexRel) == NIL)
|
||||
{
|
||||
int numatts = indexStruct->indnatts;
|
||||
int indnkeyatts = indexStruct->indnkeyatts;
|
||||
int i;
|
||||
|
||||
/* Add quals for all columns from this index. */
|
||||
for (i = 0; i < numatts; i++)
|
||||
for (i = 0; i < indnkeyatts; i++)
|
||||
{
|
||||
int attnum = indexStruct->indkey.values[i];
|
||||
Oid type;
|
||||
|
@@ -5234,7 +5234,7 @@ ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode)
|
||||
* Loop over each attribute in the primary key and see if it
|
||||
* matches the to-be-altered attribute
|
||||
*/
|
||||
for (i = 0; i < indexStruct->indnatts; i++)
|
||||
for (i = 0; i < indexStruct->indnkeyatts; i++)
|
||||
{
|
||||
if (indexStruct->indkey.values[i] == attnum)
|
||||
ereport(ERROR,
|
||||
@@ -6576,6 +6576,7 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
|
||||
RelationGetRelid(rel),
|
||||
fkattnum,
|
||||
numfks,
|
||||
numfks,
|
||||
InvalidOid, /* not a domain
|
||||
* constraint */
|
||||
indexOid,
|
||||
@@ -7083,7 +7084,7 @@ transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid,
|
||||
* assume a primary key cannot have expressional elements)
|
||||
*/
|
||||
*attnamelist = NIL;
|
||||
for (i = 0; i < indexStruct->indnatts; i++)
|
||||
for (i = 0; i < indexStruct->indnkeyatts; i++)
|
||||
{
|
||||
int pkattno = indexStruct->indkey.values[i];
|
||||
|
||||
@@ -7161,7 +7162,7 @@ transformFkeyCheckAttrs(Relation pkrel,
|
||||
* partial index; forget it if there are any expressions, too. Invalid
|
||||
* indexes are out as well.
|
||||
*/
|
||||
if (indexStruct->indnatts == numattrs &&
|
||||
if (indexStruct->indnkeyatts == numattrs &&
|
||||
indexStruct->indisunique &&
|
||||
IndexIsValid(indexStruct) &&
|
||||
heap_attisnull(indexTuple, Anum_pg_index_indpred) &&
|
||||
@@ -11045,7 +11046,7 @@ ATExecReplicaIdentity(Relation rel, ReplicaIdentityStmt *stmt, LOCKMODE lockmode
|
||||
RelationGetRelationName(indexRel))));
|
||||
|
||||
/* Check index for nullable columns. */
|
||||
for (key = 0; key < indexRel->rd_index->indnatts; key++)
|
||||
for (key = 0; key < IndexRelationGetNumberOfKeyAttributes(indexRel); key++)
|
||||
{
|
||||
int16 attno = indexRel->rd_index->indkey.values[key];
|
||||
Form_pg_attribute attr;
|
||||
|
@@ -479,6 +479,7 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
|
||||
RelationGetRelid(rel),
|
||||
NULL, /* no conkey */
|
||||
0,
|
||||
0,
|
||||
InvalidOid, /* no domain */
|
||||
InvalidOid, /* no index */
|
||||
InvalidOid, /* no foreign key */
|
||||
|
@@ -3078,6 +3078,7 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
|
||||
InvalidOid, /* not a relation constraint */
|
||||
NULL,
|
||||
0,
|
||||
0,
|
||||
domainOid, /* domain constraint */
|
||||
InvalidOid, /* no associated index */
|
||||
InvalidOid, /* Foreign key fields */
|
||||
|
Reference in New Issue
Block a user