diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index d47d2d37fcb089d210e2457db4d6adf882ccf508..2810b35eea1aa056d9fa20663882aac7ccd8ee73 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -1601,6 +1601,7 @@ RelationIdGetRelation(Oid relationId)
 				RelationReloadIndexInfo(rd);
 			else
 				RelationClearRelation(rd, true);
+			Assert(rd->rd_isvalid);
 		}
 		return rd;
 	}
@@ -1712,8 +1713,9 @@ RelationReloadIndexInfo(Relation relation)
 	/* Should be called only for invalidated indexes */
 	Assert(relation->rd_rel->relkind == RELKIND_INDEX &&
 		   !relation->rd_isvalid);
-	/* Should be closed at smgr level */
-	Assert(relation->rd_smgr == NULL);
+
+	/* Ensure it's closed at smgr level */
+	RelationCloseSmgr(relation);
 
 	/* Must free any AM cached data upon relcache flush */
 	if (relation->rd_amcache)
@@ -1892,12 +1894,11 @@ RelationClearRelation(Relation relation, bool rebuild)
 	 * be unable to recover.  However, we must redo RelationInitPhysicalAddr
 	 * in case it is a mapped relation whose mapping changed.
 	 *
-	 * If it's a nailed index, then we need to re-read the pg_class row to see
-	 * if its relfilenode changed.	We can't necessarily do that here, because
-	 * we might be in a failed transaction.  We assume it's okay to do it if
-	 * there are open references to the relcache entry (cf notes for
-	 * AtEOXact_RelationCache).  Otherwise just mark the entry as possibly
-	 * invalid, and it'll be fixed when next opened.
+	 * If it's a nailed-but-not-mapped index, then we need to re-read the
+	 * pg_class row to see if its relfilenode changed. We do that immediately
+	 * if we're inside a valid transaction and the relation is open (not
+	 * counting the nailed refcount).  Otherwise just mark the entry as
+	 * possibly invalid, and it'll be fixed when next opened.
 	 */
 	if (relation->rd_isnailed)
 	{
@@ -1906,7 +1907,7 @@ RelationClearRelation(Relation relation, bool rebuild)
 		if (relation->rd_rel->relkind == RELKIND_INDEX)
 		{
 			relation->rd_isvalid = false;		/* needs to be revalidated */
-			if (relation->rd_refcnt > 1)
+			if (relation->rd_refcnt > 1 && IsTransactionState())
 				RelationReloadIndexInfo(relation);
 		}
 		return;
@@ -1924,7 +1925,8 @@ RelationClearRelation(Relation relation, bool rebuild)
 		relation->rd_indexcxt != NULL)
 	{
 		relation->rd_isvalid = false;	/* needs to be revalidated */
-		RelationReloadIndexInfo(relation);
+		if (IsTransactionState())
+			RelationReloadIndexInfo(relation);
 		return;
 	}
 
@@ -1945,6 +1947,29 @@ RelationClearRelation(Relation relation, bool rebuild)
 		/* And release storage */
 		RelationDestroyRelation(relation);
 	}
+	else if (!IsTransactionState())
+	{
+		/*
+		 * If we're not inside a valid transaction, we can't do any catalog
+		 * access so it's not possible to rebuild yet.  Just exit, leaving
+		 * rd_isvalid = false so that the rebuild will occur when the entry is
+		 * next opened.
+		 *
+		 * Note: it's possible that we come here during subtransaction abort,
+		 * and the reason for wanting to rebuild is that the rel is open in
+		 * the outer transaction.  In that case it might seem unsafe to not
+		 * rebuild immediately, since whatever code has the rel already open
+		 * will keep on using the relcache entry as-is.  However, in such a
+		 * case the outer transaction should be holding a lock that's
+		 * sufficient to prevent any significant change in the rel's schema,
+		 * so the existing entry contents should be good enough for its
+		 * purposes; at worst we might be behind on statistics updates or the
+		 * like.  (See also CheckTableNotInUse() and its callers.)	These same
+		 * remarks also apply to the cases above where we exit without having
+		 * done RelationReloadIndexInfo() yet.
+		 */
+		return;
+	}
 	else
 	{
 		/*
@@ -2057,6 +2082,7 @@ RelationClearRelation(Relation relation, bool rebuild)
  * RelationFlushRelation
  *
  *	 Rebuild the relation if it is open (refcount > 0), else blow it away.
+ *	 This is used when we receive a cache invalidation event for the rel.
  */
 static void
 RelationFlushRelation(Relation relation)
diff --git a/src/test/regress/expected/transactions.out b/src/test/regress/expected/transactions.out
index 5c84ec50ca23df4f5086cfd36f6a16dc77ede720..5d70863866fad2ff60f7dde318d4c8678e038a0d 100644
--- a/src/test/regress/expected/transactions.out
+++ b/src/test/regress/expected/transactions.out
@@ -552,6 +552,20 @@ ROLLBACK;
 DROP TABLE foo;
 DROP TABLE baz;
 DROP TABLE barbaz;
+-- test case for problems with revalidating an open relation during abort
+create function inverse(int) returns float8 as
+$$
+begin
+  analyze revalidate_bug;
+  return 1::float8/$1;
+exception
+  when division_by_zero then return 0;
+end$$ language plpgsql volatile;
+create table revalidate_bug (c float8 unique);
+insert into revalidate_bug values (1);
+insert into revalidate_bug values (inverse(0));
+drop table revalidate_bug;
+drop function inverse(int);
 -- verify that cursors created during an aborted subtransaction are
 -- closed, but that we do not rollback the effect of any FETCHs
 -- performed in the aborted subtransaction
diff --git a/src/test/regress/sql/transactions.sql b/src/test/regress/sql/transactions.sql
index faf6a9bf9380444c9ab38bf642fc0a7f6e68e539..9fac4a3f71f7205c020c171a98c2dd188e8d4742 100644
--- a/src/test/regress/sql/transactions.sql
+++ b/src/test/regress/sql/transactions.sql
@@ -333,6 +333,25 @@ DROP TABLE foo;
 DROP TABLE baz;
 DROP TABLE barbaz;
 
+
+-- test case for problems with revalidating an open relation during abort
+create function inverse(int) returns float8 as
+$$
+begin
+  analyze revalidate_bug;
+  return 1::float8/$1;
+exception
+  when division_by_zero then return 0;
+end$$ language plpgsql volatile;
+
+create table revalidate_bug (c float8 unique);
+insert into revalidate_bug values (1);
+insert into revalidate_bug values (inverse(0));
+
+drop table revalidate_bug;
+drop function inverse(int);
+
+
 -- verify that cursors created during an aborted subtransaction are
 -- closed, but that we do not rollback the effect of any FETCHs
 -- performed in the aborted subtransaction