From eca1388629facd9e65d2c7ce405e079ba2bc60c4 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Sun, 10 Aug 2008 19:02:33 +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        |  8 ++++++--
 src/backend/utils/cache/relcache.c | 10 ++++++++--
 2 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 3c50d8c5ed2..f06307a7722 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.300 2008/06/19 00:46:04 alvherre Exp $
+ *	  $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.301 2008/08/10 19:02:33 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -2380,9 +2380,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 723e9657d5b..7bfb23aaf08 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.272 2008/05/12 00:00:52 alvherre Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.273 2008/08/10 19:02:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2986,6 +2986,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)
@@ -3004,7 +3011,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 */
 }
 
 /*
-- 
GitLab