@@ -2782,6 +2782,9 @@ index_update_stats(Relation rel,
27822782bool hasindex ,
27832783double reltuples )
27842784{
2785+ bool update_stats ;
2786+ BlockNumber relpages ;
2787+ BlockNumber relallvisible ;
27852788Oid relid = RelationGetRelid (rel );
27862789Relation pg_class ;
27872790ScanKeyData key [1 ];
@@ -2790,6 +2793,42 @@ index_update_stats(Relation rel,
27902793Form_pg_class rd_rel ;
27912794bool dirty ;
27922795
2796+ /*
2797+ * As a special hack, if we are dealing with an empty table and the
2798+ * existing reltuples is -1, we leave that alone. This ensures that
2799+ * creating an index as part of CREATE TABLE doesn't cause the table to
2800+ * prematurely look like it's been vacuumed. The rd_rel we modify may
2801+ * differ from rel->rd_rel due to e.g. commit of concurrent GRANT, but the
2802+ * commands that change reltuples take locks conflicting with ours. (Even
2803+ * if a command changed reltuples under a weaker lock, this affects only
2804+ * statistics for an empty table.)
2805+ */
2806+ if (reltuples == 0 && rel -> rd_rel -> reltuples < 0 )
2807+ reltuples = -1 ;
2808+
2809+ /*
2810+ * Don't update statistics during binary upgrade, because the indexes are
2811+ * created before the data is moved into place.
2812+ */
2813+ update_stats = reltuples >=0 && !IsBinaryUpgrade ;
2814+
2815+ /*
2816+ * Finish I/O and visibility map buffer locks before
2817+ * systable_inplace_update_begin() locks the pg_class buffer. The rd_rel
2818+ * we modify may differ from rel->rd_rel due to e.g. commit of concurrent
2819+ * GRANT, but no command changes a relkind from non-index to index. (Even
2820+ * if one did, relallvisible doesn't break functionality.)
2821+ */
2822+ if (update_stats )
2823+ {
2824+ relpages = RelationGetNumberOfBlocks (rel );
2825+
2826+ if (rel -> rd_rel -> relkind != RELKIND_INDEX )
2827+ visibilitymap_count (rel ,& relallvisible ,NULL );
2828+ else /* don't bother for indexes */
2829+ relallvisible = 0 ;
2830+ }
2831+
27932832/*
27942833 * We always update the pg_class row using a non-transactional,
27952834 * overwrite-in-place update. There are several reasons for this:
@@ -2834,15 +2873,6 @@ index_update_stats(Relation rel,
28342873/* Should this be a more comprehensive test? */
28352874Assert (rd_rel -> relkind != RELKIND_PARTITIONED_INDEX );
28362875
2837- /*
2838- * As a special hack, if we are dealing with an empty table and the
2839- * existing reltuples is -1, we leave that alone. This ensures that
2840- * creating an index as part of CREATE TABLE doesn't cause the table to
2841- * prematurely look like it's been vacuumed.
2842- */
2843- if (reltuples == 0 && rd_rel -> reltuples < 0 )
2844- reltuples = -1 ;
2845-
28462876/* Apply required updates, if any, to copied tuple */
28472877
28482878dirty = false;
@@ -2852,20 +2882,8 @@ index_update_stats(Relation rel,
28522882dirty = true;
28532883}
28542884
2855- /*
2856- * Avoid updating statistics during binary upgrade, because the indexes
2857- * are created before the data is moved into place.
2858- */
2859- if (reltuples >=0 && !IsBinaryUpgrade )
2885+ if (update_stats )
28602886{
2861- BlockNumber relpages = RelationGetNumberOfBlocks (rel );
2862- BlockNumber relallvisible ;
2863-
2864- if (rd_rel -> relkind != RELKIND_INDEX )
2865- visibilitymap_count (rel ,& relallvisible ,NULL );
2866- else /* don't bother for indexes */
2867- relallvisible = 0 ;
2868-
28692887if (rd_rel -> relpages != (int32 )relpages )
28702888{
28712889rd_rel -> relpages = (int32 )relpages ;