1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-08 11:42:09 +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:
Tom Lane
2012-11-29 14:50:46 -05:00
parent f22a6edad8
commit 518d58daa5
11 changed files with 177 additions and 58 deletions

View File

@ -3763,6 +3763,8 @@ ATExecDropNotNull(Relation rel, const char *colName)
/*
* Check that the attribute is not in a primary key
*
* Note: we'll throw error even if the pkey index is not valid.
*/
/* Loop over all indexes on the relation */
@ -4869,7 +4871,7 @@ transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid,
/*
* Get the list of index OIDs for the table from the relcache, and look up
* each one in the pg_index syscache until we find one marked primary key
* (hopefully there isn't more than one such).
* (hopefully there isn't more than one such). Insist it's valid, too.
*/
*indexOid = InvalidOid;
@ -4885,7 +4887,7 @@ transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid,
if (!HeapTupleIsValid(indexTuple))
elog(ERROR, "cache lookup failed for index %u", indexoid);
indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
if (indexStruct->indisprimary)
if (indexStruct->indisprimary && IndexIsValid(indexStruct))
{
*indexOid = indexoid;
break;
@ -4973,10 +4975,12 @@ transformFkeyCheckAttrs(Relation pkrel,
/*
* Must have the right number of columns; must be unique and not a
* partial index; forget it if there are any expressions, too
* partial index; forget it if there are any expressions, too. Invalid
* indexes are out as well.
*/
if (indexStruct->indnatts == numattrs &&
indexStruct->indisunique &&
IndexIsValid(indexStruct) &&
heap_attisnull(indexTuple, Anum_pg_index_indpred) &&
heap_attisnull(indexTuple, Anum_pg_index_indexprs))
{