diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index a674401e464b3e66733815709f1ae2d823815646..41c00565569546c3b3e801e4eedb471b00e6d02f 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -586,9 +586,10 @@ CheckAttributeType(const char *attname,
  * attribute to insert (but we ignore attacl and attoptions, which are always
  * initialized to NULL).
  *
- * indstate is the index state for CatalogIndexInsert.  It can be passed as
- * NULL, in which case we'll fetch the necessary info.  (Don't do this when
- * inserting multiple attributes, because it's a tad more expensive.)
+ * indstate is the index state for CatalogTupleInsertWithInfo.  It can be
+ * passed as NULL, in which case we'll fetch the necessary info.  (Don't do
+ * this when inserting multiple attributes, because it's a tad more
+ * expensive.)
  */
 void
 InsertPgAttributeTuple(Relation pg_attribute_rel,
@@ -630,18 +631,10 @@ InsertPgAttributeTuple(Relation pg_attribute_rel,
 	tup = heap_form_tuple(RelationGetDescr(pg_attribute_rel), values, nulls);
 
 	/* finally insert the new tuple, update the indexes, and clean up */
-	simple_heap_insert(pg_attribute_rel, tup);
-
 	if (indstate != NULL)
-		CatalogIndexInsert(indstate, tup);
+		CatalogTupleInsertWithInfo(pg_attribute_rel, tup, indstate);
 	else
-	{
-		CatalogIndexState indstate;
-
-		indstate = CatalogOpenIndexes(pg_attribute_rel);
-		CatalogIndexInsert(indstate, tup);
-		CatalogCloseIndexes(indstate);
-	}
+		CatalogTupleInsert(pg_attribute_rel, tup);
 
 	heap_freetuple(tup);
 }
diff --git a/src/backend/catalog/indexing.c b/src/backend/catalog/indexing.c
index 02f64813ec54cb2fd3460c8ee8e6d8faaf2c3ed0..76268e1d2a27a5898bfc5038494d555defbf91ea 100644
--- a/src/backend/catalog/indexing.c
+++ b/src/backend/catalog/indexing.c
@@ -68,7 +68,7 @@ CatalogCloseIndexes(CatalogIndexState indstate)
  *
  * This is effectively a cut-down version of ExecInsertIndexTuples.
  */
-void
+static void
 CatalogIndexInsert(CatalogIndexState indstate, HeapTuple heapTuple)
 {
 	int			i;
@@ -148,18 +148,20 @@ CatalogIndexInsert(CatalogIndexState indstate, HeapTuple heapTuple)
 /*
  * CatalogTupleInsert - do heap and indexing work for a new catalog tuple
  *
+ * Insert the tuple data in "tup" into the specified catalog relation.
+ * The Oid of the inserted tuple is returned.
+ *
  * This is a convenience routine for the common case of inserting a single
  * tuple in a system catalog; it inserts a new heap tuple, keeping indexes
- * current.  Avoid using it for multiple tuples, since opening the indexes and
- * building the index info structures is moderately expensive.
- *
- * The Oid of the inserted tuple is returned.
+ * current.  Avoid using it for multiple tuples, since opening the indexes
+ * and building the index info structures is moderately expensive.
+ * (Use CatalogTupleInsertWithInfo in such cases.)
  */
 Oid
 CatalogTupleInsert(Relation heapRel, HeapTuple tup)
 {
 	CatalogIndexState indstate;
-	Oid		oid;
+	Oid			oid;
 
 	indstate = CatalogOpenIndexes(heapRel);
 
@@ -171,14 +173,37 @@ CatalogTupleInsert(Relation heapRel, HeapTuple tup)
 	return oid;
 }
 
+/*
+ * CatalogTupleInsertWithInfo - as above, but with caller-supplied index info
+ *
+ * This should be used when it's important to amortize CatalogOpenIndexes/
+ * CatalogCloseIndexes work across multiple insertions.  At some point we
+ * might cache the CatalogIndexState data somewhere (perhaps in the relcache)
+ * so that callers needn't trouble over this ... but we don't do so today.
+ */
+Oid
+CatalogTupleInsertWithInfo(Relation heapRel, HeapTuple tup,
+						   CatalogIndexState indstate)
+{
+	Oid			oid;
+
+	oid = simple_heap_insert(heapRel, tup);
+
+	CatalogIndexInsert(indstate, tup);
+
+	return oid;
+}
+
 /*
  * CatalogTupleUpdate - do heap and indexing work for updating a catalog tuple
  *
+ * Update the tuple identified by "otid", replacing it with the data in "tup".
+ *
  * This is a convenience routine for the common case of updating a single
- * tuple in a system catalog; it updates one heap tuple (identified by otid)
- * with tup, keeping indexes current.  Avoid using it for multiple tuples,
- * since opening the indexes and building the index info structures is
- * moderately expensive.
+ * tuple in a system catalog; it updates one heap tuple, keeping indexes
+ * current.  Avoid using it for multiple tuples, since opening the indexes
+ * and building the index info structures is moderately expensive.
+ * (Use CatalogTupleUpdateWithInfo in such cases.)
  */
 void
 CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
@@ -193,15 +218,37 @@ CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
 	CatalogCloseIndexes(indstate);
 }
 
+/*
+ * CatalogTupleUpdateWithInfo - as above, but with caller-supplied index info
+ *
+ * This should be used when it's important to amortize CatalogOpenIndexes/
+ * CatalogCloseIndexes work across multiple updates.  At some point we
+ * might cache the CatalogIndexState data somewhere (perhaps in the relcache)
+ * so that callers needn't trouble over this ... but we don't do so today.
+ */
+void
+CatalogTupleUpdateWithInfo(Relation heapRel, ItemPointer otid, HeapTuple tup,
+						   CatalogIndexState indstate)
+{
+	simple_heap_update(heapRel, otid, tup);
+
+	CatalogIndexInsert(indstate, tup);
+}
+
 /*
  * CatalogTupleDelete - do heap and indexing work for deleting a catalog tuple
  *
- * Delete the tuple identified by tid in the specified catalog.
+ * Delete the tuple identified by "tid" in the specified catalog.
  *
  * With Postgres heaps, there is no index work to do at deletion time;
  * cleanup will be done later by VACUUM.  However, callers of this function
  * shouldn't have to know that; we'd like a uniform abstraction for all
  * catalog tuple changes.  Hence, provide this currently-trivial wrapper.
+ *
+ * The abstraction is a bit leaky in that we don't provide an optimized
+ * CatalogTupleDeleteWithInfo version, because there is currently nothing to
+ * optimize.  If we ever need that, rather than touching a lot of call sites,
+ * it might be better to do something about caching CatalogIndexState.
  */
 void
 CatalogTupleDelete(Relation heapRel, ItemPointer tid)
diff --git a/src/backend/catalog/pg_depend.c b/src/backend/catalog/pg_depend.c
index 722df67bda038f64d68ecbb7299c2eccefe7e557..d0ee851215d1477cc88d25b34219b87993945f84 100644
--- a/src/backend/catalog/pg_depend.c
+++ b/src/backend/catalog/pg_depend.c
@@ -107,13 +107,11 @@ recordMultipleDependencies(const ObjectAddress *depender,
 
 			tup = heap_form_tuple(dependDesc->rd_att, values, nulls);
 
-			simple_heap_insert(dependDesc, tup);
-
-			/* keep indexes current */
+			/* fetch index info only when we know we need it */
 			if (indstate == NULL)
 				indstate = CatalogOpenIndexes(dependDesc);
 
-			CatalogIndexInsert(indstate, tup);
+			CatalogTupleInsertWithInfo(dependDesc, tup, indstate);
 
 			heap_freetuple(tup);
 		}
diff --git a/src/backend/catalog/pg_shdepend.c b/src/backend/catalog/pg_shdepend.c
index ef50b854d4d9d00081abfef2d7e2cb1e6d9f7d03..8d946ff44ccb341172fe4fa562a49ec46382f46a 100644
--- a/src/backend/catalog/pg_shdepend.c
+++ b/src/backend/catalog/pg_shdepend.c
@@ -753,7 +753,7 @@ copyTemplateDependencies(Oid templateDbId, Oid newDbId)
 		HeapTuple	newtup;
 
 		newtup = heap_modify_tuple(tup, sdepDesc, values, nulls, replace);
-		CatalogTupleInsert(sdepRel, newtup);
+		CatalogTupleInsertWithInfo(sdepRel, newtup, indstate);
 
 		heap_freetuple(newtup);
 	}
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index e60e6133155aad81300f26a73df17c92305a8bc9..330385ba0a69183007187c4f517f18a9bf294724 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -1141,7 +1141,6 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
 				relfilenode2;
 	Oid			swaptemp;
 	char		swptmpchr;
-	CatalogIndexState indstate;
 
 	/* We need writable copies of both pg_class tuples. */
 	relRelation = heap_open(RelationRelationId, RowExclusiveLock);
@@ -1285,13 +1284,13 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
 	 */
 	if (!target_is_pg_class)
 	{
-		simple_heap_update(relRelation, &reltup1->t_self, reltup1);
-		simple_heap_update(relRelation, &reltup2->t_self, reltup2);
+		CatalogIndexState indstate;
 
-		/* Keep system catalogs current */
 		indstate = CatalogOpenIndexes(relRelation);
-		CatalogIndexInsert(indstate, reltup1);
-		CatalogIndexInsert(indstate, reltup2);
+		CatalogTupleUpdateWithInfo(relRelation, &reltup1->t_self, reltup1,
+								   indstate);
+		CatalogTupleUpdateWithInfo(relRelation, &reltup2->t_self, reltup2,
+								   indstate);
 		CatalogCloseIndexes(indstate);
 	}
 	else
diff --git a/src/backend/storage/large_object/inv_api.c b/src/backend/storage/large_object/inv_api.c
index 8eb5b3b08e36830ac48cfeaedc8c167756b3ba56..6597b36b1725ebda8a7ef8bd50638fdd8cc67729 100644
--- a/src/backend/storage/large_object/inv_api.c
+++ b/src/backend/storage/large_object/inv_api.c
@@ -678,7 +678,8 @@ inv_write(LargeObjectDesc *obj_desc, const char *buf, int nbytes)
 			replace[Anum_pg_largeobject_data - 1] = true;
 			newtup = heap_modify_tuple(oldtuple, RelationGetDescr(lo_heap_r),
 									   values, nulls, replace);
-			CatalogTupleUpdate(lo_heap_r, &newtup->t_self, newtup);
+			CatalogTupleUpdateWithInfo(lo_heap_r, &newtup->t_self, newtup,
+									   indstate);
 			heap_freetuple(newtup);
 
 			/*
@@ -720,7 +721,7 @@ inv_write(LargeObjectDesc *obj_desc, const char *buf, int nbytes)
 			values[Anum_pg_largeobject_pageno - 1] = Int32GetDatum(pageno);
 			values[Anum_pg_largeobject_data - 1] = PointerGetDatum(&workbuf);
 			newtup = heap_form_tuple(lo_heap_r->rd_att, values, nulls);
-			CatalogTupleInsert(lo_heap_r, newtup);
+			CatalogTupleInsertWithInfo(lo_heap_r, newtup, indstate);
 			heap_freetuple(newtup);
 		}
 		pageno++;
@@ -848,7 +849,8 @@ inv_truncate(LargeObjectDesc *obj_desc, int64 len)
 		replace[Anum_pg_largeobject_data - 1] = true;
 		newtup = heap_modify_tuple(oldtuple, RelationGetDescr(lo_heap_r),
 								   values, nulls, replace);
-		CatalogTupleUpdate(lo_heap_r, &newtup->t_self, newtup);
+		CatalogTupleUpdateWithInfo(lo_heap_r, &newtup->t_self, newtup,
+								   indstate);
 		heap_freetuple(newtup);
 	}
 	else
@@ -885,7 +887,7 @@ inv_truncate(LargeObjectDesc *obj_desc, int64 len)
 		values[Anum_pg_largeobject_pageno - 1] = Int32GetDatum(pageno);
 		values[Anum_pg_largeobject_data - 1] = PointerGetDatum(&workbuf);
 		newtup = heap_form_tuple(lo_heap_r->rd_att, values, nulls);
-		CatalogTupleInsert(lo_heap_r, newtup);
+		CatalogTupleInsertWithInfo(lo_heap_r, newtup, indstate);
 		heap_freetuple(newtup);
 	}
 
diff --git a/src/include/catalog/indexing.h b/src/include/catalog/indexing.h
index 9d02666ed1bf4c9a624375799ef3105145532ac6..6bce7328a289f1f6b6d949186dde616912ee540f 100644
--- a/src/include/catalog/indexing.h
+++ b/src/include/catalog/indexing.h
@@ -30,11 +30,14 @@ typedef struct ResultRelInfo *CatalogIndexState;
  */
 extern CatalogIndexState CatalogOpenIndexes(Relation heapRel);
 extern void CatalogCloseIndexes(CatalogIndexState indstate);
-extern void CatalogIndexInsert(CatalogIndexState indstate,
-				   HeapTuple heapTuple);
-extern Oid CatalogTupleInsert(Relation heapRel, HeapTuple tup);
+extern Oid	CatalogTupleInsert(Relation heapRel, HeapTuple tup);
+extern Oid CatalogTupleInsertWithInfo(Relation heapRel, HeapTuple tup,
+						   CatalogIndexState indstate);
 extern void CatalogTupleUpdate(Relation heapRel, ItemPointer otid,
 				   HeapTuple tup);
+extern void CatalogTupleUpdateWithInfo(Relation heapRel,
+						   ItemPointer otid, HeapTuple tup,
+						   CatalogIndexState indstate);
 extern void CatalogTupleDelete(Relation heapRel, ItemPointer tid);