diff --git a/src/backend/utils/cache/catcache.c b/src/backend/utils/cache/catcache.c
index 0d1ae15b39ce1e94d115b91292780ffa29fc2c78..55b9d5baf07334ada84dd0309739049d1ef8b627 100644
--- a/src/backend/utils/cache/catcache.c
+++ b/src/backend/utils/cache/catcache.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/cache/catcache.c,v 1.133 2006/10/04 00:30:00 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/cache/catcache.c,v 1.134 2006/10/06 18:23:35 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -976,7 +976,7 @@ CatalogCacheInitializeCache(CatCache *cache)
 		cache->cc_skey[i].sk_strategy = BTEqualStrategyNumber;
 		cache->cc_skey[i].sk_subtype = InvalidOid;
 
-		CACHE4_elog(DEBUG2, "CatalogCacheInit %s %d %p",
+		CACHE4_elog(DEBUG2, "CatalogCacheInitializeCache %s %d %p",
 					cache->cc_relname,
 					i,
 					cache);
@@ -991,18 +991,20 @@ CatalogCacheInitializeCache(CatCache *cache)
 /*
  * InitCatCachePhase2 -- external interface for CatalogCacheInitializeCache
  *
- * The only reason to call this routine is to ensure that the relcache
- * has created entries for all the catalogs and indexes referenced by
- * catcaches.  Therefore, open the index too.  An exception is the indexes
- * on pg_am, which we don't use (cf. IndexScanOK).
+ * One reason to call this routine is to ensure that the relcache has
+ * created entries for all the catalogs and indexes referenced by catcaches.
+ * Therefore, provide an option to open the index as well as fixing the
+ * cache itself.  An exception is the indexes on pg_am, which we don't use
+ * (cf. IndexScanOK).
  */
 void
-InitCatCachePhase2(CatCache *cache)
+InitCatCachePhase2(CatCache *cache, bool touch_index)
 {
 	if (cache->cc_tupdesc == NULL)
 		CatalogCacheInitializeCache(cache);
 
-	if (cache->id != AMOID &&
+	if (touch_index &&
+		cache->id != AMOID &&
 		cache->id != AMNAME)
 	{
 		Relation	idesc;
diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c
index 79aba4ebc824c3f77c20c4e20dffc32a33039b35..e19fba05840bb1f5dd03156420edb61c36f18fb0 100644
--- a/src/backend/utils/cache/syscache.c
+++ b/src/backend/utils/cache/syscache.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/cache/syscache.c,v 1.107 2006/10/04 00:30:00 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/cache/syscache.c,v 1.108 2006/10/06 18:23:35 tgl Exp $
  *
  * NOTES
  *	  These routines allow the parser/planner/executor to perform
@@ -576,7 +576,7 @@ InitCatalogCachePhase2(void)
 	Assert(CacheInitialized);
 
 	for (cacheId = 0; cacheId < SysCacheSize; cacheId++)
-		InitCatCachePhase2(SysCache[cacheId]);
+		InitCatCachePhase2(SysCache[cacheId], true);
 }
 
 
@@ -773,6 +773,9 @@ SearchSysCacheExistsAttName(Oid relid, const char *attname)
  * As with heap_getattr(), if the attribute is of a pass-by-reference type
  * then a pointer into the tuple data area is returned --- the caller must
  * not modify or pfree the datum!
+ *
+ * Note: it is legal to use SysCacheGetAttr() with a cacheId referencing
+ * a different cache for the same catalog the tuple was fetched from.
  */
 Datum
 SysCacheGetAttr(int cacheId, HeapTuple tup,
@@ -781,15 +784,18 @@ SysCacheGetAttr(int cacheId, HeapTuple tup,
 {
 	/*
 	 * We just need to get the TupleDesc out of the cache entry, and then we
-	 * can apply heap_getattr().  We expect that the cache control data is
-	 * currently valid --- if the caller recently fetched the tuple, then it
-	 * should be.
+	 * can apply heap_getattr().  Normally the cache control data is already
+	 * valid (because the caller recently fetched the tuple via this same
+	 * cache), but there are cases where we have to initialize the cache here.
 	 */
-	if (cacheId < 0 || cacheId >= SysCacheSize)
+	if (cacheId < 0 || cacheId >= SysCacheSize ||
+		!PointerIsValid(SysCache[cacheId]))
 		elog(ERROR, "invalid cache id: %d", cacheId);
-	if (!PointerIsValid(SysCache[cacheId]) ||
-		!PointerIsValid(SysCache[cacheId]->cc_tupdesc))
-		elog(ERROR, "missing cache data for cache id %d", cacheId);
+	if (!PointerIsValid(SysCache[cacheId]->cc_tupdesc))
+	{
+		InitCatCachePhase2(SysCache[cacheId], false);
+		Assert(PointerIsValid(SysCache[cacheId]->cc_tupdesc));
+	}
 
 	return heap_getattr(tup, attributeNumber,
 						SysCache[cacheId]->cc_tupdesc,
diff --git a/src/include/utils/catcache.h b/src/include/utils/catcache.h
index cbd6d9945a426ae6db17e803a45b117d947eafa7..c24133ab5e93715936ccc9d8354214e18ac60053 100644
--- a/src/include/utils/catcache.h
+++ b/src/include/utils/catcache.h
@@ -13,7 +13,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/catcache.h,v 1.62 2006/10/04 00:30:10 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/utils/catcache.h,v 1.63 2006/10/06 18:23:35 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -166,7 +166,7 @@ extern CatCache *InitCatCache(int id, Oid reloid, Oid indexoid,
 			 int reloidattr,
 			 int nkeys, const int *key,
 			 int nbuckets);
-extern void InitCatCachePhase2(CatCache *cache);
+extern void InitCatCachePhase2(CatCache *cache, bool touch_index);
 
 extern HeapTuple SearchCatCache(CatCache *cache,
 			   Datum v1, Datum v2,