Fix corner-case bug introduced with HOT: if REINDEX TABLE pg_class (or a
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 10 Aug 2008 19:02:46 +0000 (19:02 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 10 Aug 2008 19:02:46 +0000 (19:02 +0000)
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
src/backend/utils/cache/relcache.c

index fd45460b62cd0e3f6b868a716eeb3c17758e2982..2d8eb5dc7560f7e7eaede285a3b6b318728fab9e 100644 (file)
@@ -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);
index 4155390f8b6bdfa9313423cc7a00090b30ce930b..3353d6605d7bc82414797037077d37e14db9ad95 100644 (file)
@@ -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 */
 }
 
 /*