diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index ba185431bec595e739c28b834936762cc6aba153..18047a53889576f2caf074f8b611309a187ca48e 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.157 2007/03/13 00:33:39 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.158 2007/05/02 21:08:45 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -41,6 +41,7 @@
 #include "utils/acl.h"
 #include "utils/builtins.h"
 #include "utils/fmgroids.h"
+#include "utils/inval.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
 #include "utils/relcache.h"
@@ -514,7 +515,9 @@ DefineIndex(RangeVar *heapRelation,
 	for (ixcnt = 0; ixcnt < snapshot->xcnt; ixcnt++)
 		XactLockTableWait(snapshot->xip[ixcnt]);
 
-	/* Index can now be marked valid -- update its pg_index entry */
+	/*
+	 * Index can now be marked valid -- update its pg_index entry
+	 */
 	pg_index = heap_open(IndexRelationId, RowExclusiveLock);
 
 	indexTuple = SearchSysCacheCopy(INDEXRELID,
@@ -534,6 +537,15 @@ DefineIndex(RangeVar *heapRelation,
 
 	heap_close(pg_index, RowExclusiveLock);
 
+	/*
+	 * The pg_index update will cause backends (including this one) to update
+	 * relcache entries for the index itself, but we should also send a
+	 * relcache inval on the parent table to force replanning of cached plans.
+	 * Otherwise existing sessions might fail to use the new index where it
+	 * would be useful.
+	 */
+	CacheInvalidateRelcacheByRelid(heaprelid.relId);
+
 	/*
 	 * Last thing to do is release the session-level lock on the parent table.
 	 */
diff --git a/src/backend/utils/cache/inval.c b/src/backend/utils/cache/inval.c
index a5668bcbcb0093c479ddcda4326fa3e341dc16f1..a9b5bd4b1ca8ac1a5347c87faa99ccfd729285bb 100644
--- a/src/backend/utils/cache/inval.c
+++ b/src/backend/utils/cache/inval.c
@@ -80,7 +80,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/cache/inval.c,v 1.79 2007/01/05 22:19:43 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/cache/inval.c,v 1.80 2007/05/02 21:08:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -590,12 +590,27 @@ PrepareForTupleInvalidation(Relation relation, HeapTuple tuple)
 		 * KLUGE ALERT: we always send the relcache event with MyDatabaseId,
 		 * even if the rel in question is shared (which we can't easily tell).
 		 * This essentially means that only backends in this same database
-		 * will react to the relcache flush request. This is in fact
+		 * will react to the relcache flush request.  This is in fact
 		 * appropriate, since only those backends could see our pg_attribute
-		 * change anyway.  It looks a bit ugly though.
+		 * change anyway.  It looks a bit ugly though.  (In practice, shared
+		 * relations can't have schema changes after bootstrap, so we should
+		 * never come here for a shared rel anyway.)
 		 */
 		databaseId = MyDatabaseId;
 	}
+	else if (tupleRelId == IndexRelationId)
+	{
+		Form_pg_index indextup = (Form_pg_index) GETSTRUCT(tuple);
+
+		/*
+		 * When a pg_index row is updated, we should send out a relcache inval
+		 * for the index relation.  As above, we don't know the shared status
+		 * of the index, but in practice it doesn't matter since indexes of
+		 * shared catalogs can't have such updates.
+		 */
+		relationId = indextup->indexrelid;
+		databaseId = MyDatabaseId;
+	}
 	else
 		return;
 
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index d8bd36bc94f6d9dc50b23f45c90031c37be613f7..7d554c2ada2e040cb818096d0d33df26314d5c7e 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.259 2007/03/29 00:15:38 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.260 2007/05/02 21:08:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -181,7 +181,7 @@ static HTAB *OpClassCache = NULL;
 
 static void RelationClearRelation(Relation relation, bool rebuild);
 
-static void RelationReloadClassinfo(Relation relation);
+static void RelationReloadIndexInfo(Relation relation);
 static void RelationFlushRelation(Relation relation);
 static bool load_relcache_init_file(void);
 static void write_relcache_init_file(void);
@@ -1504,7 +1504,7 @@ RelationIdGetRelation(Oid relationId)
 		RelationIncrementReferenceCount(rd);
 		/* revalidate nailed index if necessary */
 		if (!rd->rd_isvalid)
-			RelationReloadClassinfo(rd);
+			RelationReloadIndexInfo(rd);
 		return rd;
 	}
 
@@ -1579,24 +1579,24 @@ RelationClose(Relation relation)
 }
 
 /*
- * RelationReloadClassinfo - reload the pg_class row (only)
+ * RelationReloadIndexInfo - reload minimal information for an open index
  *
- *	This function is used only for indexes.  We currently allow only the
- *	pg_class row of an existing index to change (to support changes of
- *	owner, tablespace, or relfilenode), not its pg_index row or other
- *	subsidiary index schema information.  Therefore it's sufficient to do
- *	this when we get an SI invalidation.  Furthermore, there are cases
- *	where it's necessary not to throw away the index information, especially
- *	for "nailed" indexes which we are unable to rebuild on-the-fly.
+ *	This function is used only for indexes.  A relcache inval on an index
+ *	can mean that its pg_class or pg_index row changed.  There are only
+ *	very limited changes that are allowed to an existing index's schema,
+ *	so we can update the relcache entry without a complete rebuild; which
+ *	is fortunate because we can't rebuild an index entry that is "nailed"
+ *	and/or in active use.  We support full replacement of the pg_class row,
+ *	as well as updates of a few simple fields of the pg_index row.
  *
- *	We can't necessarily reread the pg_class row right away; we might be
+ *	We can't necessarily reread the catalog rows right away; we might be
  *	in a failed transaction when we receive the SI notification.  If so,
  *	RelationClearRelation just marks the entry as invalid by setting
  *	rd_isvalid to false.  This routine is called to fix the entry when it
  *	is next needed.
  */
 static void
-RelationReloadClassinfo(Relation relation)
+RelationReloadIndexInfo(Relation relation)
 {
 	bool		indexOK;
 	HeapTuple	pg_class_tuple;
@@ -1635,6 +1635,33 @@ RelationReloadClassinfo(Relation relation)
 	if (relation->rd_amcache)
 		pfree(relation->rd_amcache);
 	relation->rd_amcache = NULL;
+
+	/*
+	 * For a non-system index, there are fields of the pg_index row that are
+	 * allowed to change, so re-read that row and update the relcache entry.
+	 * Most of the info derived from pg_index (such as support function lookup
+	 * info) cannot change, and indeed the whole point of this routine is to
+	 * update the relcache entry without clobbering that data; so wholesale
+	 * replacement is not appropriate.
+	 */
+	if (!IsSystemRelation(relation))
+	{
+		HeapTuple	tuple;
+		Form_pg_index index;
+
+		tuple = SearchSysCache(INDEXRELID,
+							   ObjectIdGetDatum(RelationGetRelid(relation)),
+							   0, 0, 0);
+		if (!HeapTupleIsValid(tuple))
+				elog(ERROR, "cache lookup failed for index %u",
+					 RelationGetRelid(relation));
+		index = (Form_pg_index) GETSTRUCT(tuple);
+
+		relation->rd_index->indisvalid = index->indisvalid;
+
+		ReleaseSysCache(tuple);
+	}
+
 	/* Okay, now it's valid again */
 	relation->rd_isvalid = true;
 }
@@ -1683,7 +1710,7 @@ RelationClearRelation(Relation relation, bool rebuild)
 		{
 			relation->rd_isvalid = false;		/* needs to be revalidated */
 			if (relation->rd_refcnt > 1)
-				RelationReloadClassinfo(relation);
+				RelationReloadIndexInfo(relation);
 		}
 		return;
 	}
@@ -1693,14 +1720,14 @@ RelationClearRelation(Relation relation, bool rebuild)
 	 * have valid index support information.  This avoids problems with active
 	 * use of the index support information.  As with nailed indexes, we
 	 * re-read the pg_class row to handle possible physical relocation of the
-	 * index.
+	 * index, and we check for pg_index updates too.
 	 */
 	if (relation->rd_rel->relkind == RELKIND_INDEX &&
 		relation->rd_refcnt > 0 &&
 		relation->rd_indexcxt != NULL)
 	{
 		relation->rd_isvalid = false;	/* needs to be revalidated */
-		RelationReloadClassinfo(relation);
+		RelationReloadIndexInfo(relation);
 		return;
 	}