From c5d1fab8a144d8cb8a6dae1deca8bbb36fd056e7 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sun, 10 Aug 2008 19:02:46 +0000 Subject: [PATCH] Fix corner-case bug introduced with HOT: if REINDEX TABLE pg_class (or a REINDEX DATABASE including same) is done before a session has done any other update on pg_class, the pg_class relcache entry was left with an incorrect setting of rd_indexattr, because the indexed-attributes set would be first demanded at a time when we'd forced a partial list of indexes into the pg_class entry, and it would remain cached after that. This could result in incorrect decisions about HOT-update safety later in the same session. In practice, since only pg_class_relname_nsp_index would be missed out, only ALTER TABLE RENAME and ALTER TABLE SET SCHEMA could trigger a problem. Per report and test case from Ondrej Jirman. --- src/backend/catalog/index.c | 6 +++++- src/backend/utils/cache/relcache.c | 8 +++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index fd45460b62..2d8eb5dc75 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -2373,9 +2373,13 @@ reindex_relation(Oid relid, bool toast_too) * problem. */ is_pg_class = (RelationGetRelid(rel) == RelationRelationId); - doneIndexes = NIL; + + /* Ensure rd_indexattr is valid; see comments for RelationSetIndexList */ + if (is_pg_class) + (void) RelationGetIndexAttrBitmap(rel); /* Reindex all the indexes. */ + doneIndexes = NIL; foreach(indexId, indexIds) { Oid indexOid = lfirst_oid(indexId); diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 4155390f8b..3353d6605d 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -2994,6 +2994,13 @@ insert_ordered_oid(List *list, Oid datum) * messages. In practice it is only used on pg_class (see REINDEX). * * It is up to the caller to make sure the given list is correctly ordered. + * + * We deliberately do not change rd_indexattr here: even when operating + * with a temporary partial index list, HOT-update decisions must be made + * correctly with respect to the full index set. It is up to the caller + * to ensure that a correct rd_indexattr set has been cached before first + * calling RelationSetIndexList; else a subsequent inquiry might cause a + * wrong rd_indexattr set to get computed and cached. */ void RelationSetIndexList(Relation relation, List *indexIds, Oid oidIndex) @@ -3012,7 +3019,6 @@ RelationSetIndexList(Relation relation, List *indexIds, Oid oidIndex) relation->rd_indexvalid = 2; /* mark list as forced */ /* must flag that we have a forced index list */ need_eoxact_work = true; - /* we deliberately do not change rd_indexattr */ } /* -- 2.39.5