mirror of
https://github.com/postgres/postgres.git
synced 2025-08-31 17:02:12 +03:00
Fix assorted bugs in CREATE INDEX CONCURRENTLY.
This patch changes CREATE INDEX CONCURRENTLY so that the pg_index flag changes it makes without exclusive lock on the index are made via heap_inplace_update() rather than a normal transactional update. The latter is not very safe because moving the pg_index tuple could result in concurrent SnapshotNow scans finding it twice or not at all, thus possibly resulting in index corruption. In addition, fix various places in the code that ought to check to make sure that the indexes they are manipulating are valid and/or ready as appropriate. These represent bugs that have existed since 8.2, since a failed CREATE INDEX CONCURRENTLY could leave a corrupt or invalid index behind, and we ought not try to do anything that might fail with such an index. Also fix RelationReloadIndexInfo to ensure it copies all the pg_index columns that are allowed to change after initial creation. Previously we could have been left with stale values of some fields in an index relcache entry. It's not clear whether this actually had any user-visible consequences, but it's at least a bug waiting to happen. This is a subset of a patch already applied in 9.2 and HEAD. Back-patch into all earlier supported branches. Tom Lane and Andres Freund
This commit is contained in:
21
src/backend/utils/cache/relcache.c
vendored
21
src/backend/utils/cache/relcache.c
vendored
@@ -1731,9 +1731,22 @@ RelationReloadIndexInfo(Relation relation)
|
||||
RelationGetRelid(relation));
|
||||
index = (Form_pg_index) GETSTRUCT(tuple);
|
||||
|
||||
/*
|
||||
* Basically, let's just copy all the bool fields. There are one or
|
||||
* two of these that can't actually change in the current code, but
|
||||
* it's not worth it to track exactly which ones they are. None of
|
||||
* the array fields are allowed to change, though.
|
||||
*/
|
||||
relation->rd_index->indisunique = index->indisunique;
|
||||
relation->rd_index->indisprimary = index->indisprimary;
|
||||
relation->rd_index->indisexclusion = index->indisexclusion;
|
||||
relation->rd_index->indimmediate = index->indimmediate;
|
||||
relation->rd_index->indisclustered = index->indisclustered;
|
||||
relation->rd_index->indisvalid = index->indisvalid;
|
||||
relation->rd_index->indcheckxmin = index->indcheckxmin;
|
||||
relation->rd_index->indisready = index->indisready;
|
||||
|
||||
/* Copy xmin too, as that is needed to make sense of indcheckxmin */
|
||||
HeapTupleHeaderSetXmin(relation->rd_indextuple->t_data,
|
||||
HeapTupleHeaderGetXmin(tuple->t_data));
|
||||
|
||||
@@ -3355,7 +3368,8 @@ RelationGetIndexList(Relation relation)
|
||||
result = insert_ordered_oid(result, index->indexrelid);
|
||||
|
||||
/* Check to see if it is a unique, non-partial btree index on OID */
|
||||
if (index->indnatts == 1 &&
|
||||
if (IndexIsValid(index) &&
|
||||
index->indnatts == 1 &&
|
||||
index->indisunique && index->indimmediate &&
|
||||
index->indkey.values[0] == ObjectIdAttributeNumber &&
|
||||
index->indclass.values[0] == OID_BTREE_OPS_OID &&
|
||||
@@ -3662,6 +3676,11 @@ RelationGetIndexAttrBitmap(Relation relation)
|
||||
|
||||
/*
|
||||
* For each index, add referenced attributes to indexattrs.
|
||||
*
|
||||
* Note: we consider all indexes returned by RelationGetIndexList, even if
|
||||
* they are not indisready or indisvalid. This is important because an
|
||||
* index for which CREATE INDEX CONCURRENTLY has just started must be
|
||||
* included in HOT-safety decisions (see README.HOT).
|
||||
*/
|
||||
indexattrs = NULL;
|
||||
foreach(l, indexoidlist)
|
||||
|
Reference in New Issue
Block a user