diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index 9b5e5ab9c251020442c2efc09d85473a4ec9804b..e05654d1babc4fe581c28d90cd8d8a8c1a64bb95 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -6909,33 +6909,34 @@ gincostestimate(PG_FUNCTION_ARGS)
 	GinStatsData ginStats;
 
 	/*
-	 * Obtain statistic information from the meta page
+	 * Obtain statistical information from the meta page, if possible.  Else
+	 * set ginStats to zeroes, and we'll cope below.
 	 */
-	indexRel = index_open(index->indexoid, AccessShareLock);
-	ginGetStats(indexRel, &ginStats);
-	index_close(indexRel, AccessShareLock);
-
-	numEntryPages = ginStats.nEntryPages;
-	numDataPages = ginStats.nDataPages;
-	numPendingPages = ginStats.nPendingPages;
-	numEntries = ginStats.nEntries;
-
-	/*
-	 * nPendingPages can be trusted, but the other fields are as of the last
-	 * VACUUM.  Scale them by the ratio numPages / nTotalPages to account for
-	 * growth since then.  If the fields are zero (implying no VACUUM at all,
-	 * and an index created pre-9.1), assume all pages are entry pages.
-	 */
-	if (ginStats.nTotalPages == 0 || ginStats.nEntryPages == 0)
+	if (!index->hypothetical)
 	{
-		numEntryPages = numPages;
-		numDataPages = 0;
-		numEntries = numTuples; /* bogus, but no other info available */
+		indexRel = index_open(index->indexoid, AccessShareLock);
+		ginGetStats(indexRel, &ginStats);
+		index_close(indexRel, AccessShareLock);
 	}
 	else
 	{
+		memset(&ginStats, 0, sizeof(ginStats));
+	}
+
+	if (ginStats.nTotalPages > 0 && ginStats.nEntryPages > 0 && numPages > 0)
+	{
+		/*
+		 * We got valid stats.  nPendingPages can be trusted, but the other
+		 * fields are data as of the last VACUUM.  Scale them by the ratio
+		 * numPages / nTotalPages to account for growth since then.
+		 */
 		double		scale = numPages / ginStats.nTotalPages;
 
+		numEntryPages = ginStats.nEntryPages;
+		numDataPages = ginStats.nDataPages;
+		numPendingPages = ginStats.nPendingPages;
+		numEntries = ginStats.nEntries;
+
 		numEntryPages = ceil(numEntryPages * scale);
 		numDataPages = ceil(numDataPages * scale);
 		numEntries = ceil(numEntries * scale);
@@ -6943,6 +6944,23 @@ gincostestimate(PG_FUNCTION_ARGS)
 		numEntryPages = Min(numEntryPages, numPages);
 		numDataPages = Min(numDataPages, numPages - numEntryPages);
 	}
+	else
+	{
+		/*
+		 * It's a hypothetical index, or perhaps an index created pre-9.1 and
+		 * never vacuumed since upgrading.  Invent some plausible internal
+		 * statistics based on the index page count.  We estimate that 90% of
+		 * the index is entry pages, and the rest is data pages.  Estimate 100
+		 * entries per entry page; this is rather bogus since it'll depend on
+		 * the size of the keys, but it's more robust than trying to predict
+		 * the number of entries per heap tuple.
+		 */
+		numPages = Max(numPages, 10);
+		numEntryPages = floor(numPages * 0.90);
+		numDataPages = numPages - numEntryPages;
+		numPendingPages = 0;
+		numEntries = floor(numEntryPages * 100);
+	}
 
 	/* In an empty index, numEntries could be zero.  Avoid divide-by-zero */
 	if (numEntries < 1)