@@ -2806,6 +2806,9 @@ index_update_stats(Relation rel,
28062806 bool hasindex ,
28072807 double reltuples )
28082808{
2809+ bool update_stats ;
2810+ BlockNumber relpages ;
2811+ BlockNumber relallvisible ;
28092812 Oid relid = RelationGetRelid (rel );
28102813 Relation pg_class ;
28112814 ScanKeyData key [1 ];
@@ -2814,6 +2817,42 @@ index_update_stats(Relation rel,
28142817 Form_pg_class rd_rel ;
28152818 bool dirty ;
28162819
2820+ /*
2821+ * As a special hack, if we are dealing with an empty table and the
2822+ * existing reltuples is -1, we leave that alone. This ensures that
2823+ * creating an index as part of CREATE TABLE doesn't cause the table to
2824+ * prematurely look like it's been vacuumed. The rd_rel we modify may
2825+ * differ from rel->rd_rel due to e.g. commit of concurrent GRANT, but the
2826+ * commands that change reltuples take locks conflicting with ours. (Even
2827+ * if a command changed reltuples under a weaker lock, this affects only
2828+ * statistics for an empty table.)
2829+ */
2830+ if (reltuples == 0 && rel -> rd_rel -> reltuples < 0 )
2831+ reltuples = -1 ;
2832+
2833+ /*
2834+ * Don't update statistics during binary upgrade, because the indexes are
2835+ * created before the data is moved into place.
2836+ */
2837+ update_stats = reltuples >= 0 && !IsBinaryUpgrade ;
2838+
2839+ /*
2840+ * Finish I/O and visibility map buffer locks before
2841+ * systable_inplace_update_begin() locks the pg_class buffer. The rd_rel
2842+ * we modify may differ from rel->rd_rel due to e.g. commit of concurrent
2843+ * GRANT, but no command changes a relkind from non-index to index. (Even
2844+ * if one did, relallvisible doesn't break functionality.)
2845+ */
2846+ if (update_stats )
2847+ {
2848+ relpages = RelationGetNumberOfBlocks (rel );
2849+
2850+ if (rel -> rd_rel -> relkind != RELKIND_INDEX )
2851+ visibilitymap_count (rel , & relallvisible , NULL );
2852+ else /* don't bother for indexes */
2853+ relallvisible = 0 ;
2854+ }
2855+
28172856 /*
28182857 * We always update the pg_class row using a non-transactional,
28192858 * overwrite-in-place update. There are several reasons for this:
@@ -2858,15 +2897,6 @@ index_update_stats(Relation rel,
28582897 /* Should this be a more comprehensive test? */
28592898 Assert (rd_rel -> relkind != RELKIND_PARTITIONED_INDEX );
28602899
2861- /*
2862- * As a special hack, if we are dealing with an empty table and the
2863- * existing reltuples is -1, we leave that alone. This ensures that
2864- * creating an index as part of CREATE TABLE doesn't cause the table to
2865- * prematurely look like it's been vacuumed.
2866- */
2867- if (reltuples == 0 && rd_rel -> reltuples < 0 )
2868- reltuples = -1 ;
2869-
28702900 /* Apply required updates, if any, to copied tuple */
28712901
28722902 dirty = false;
@@ -2876,20 +2906,8 @@ index_update_stats(Relation rel,
28762906 dirty = true;
28772907 }
28782908
2879- /*
2880- * Avoid updating statistics during binary upgrade, because the indexes
2881- * are created before the data is moved into place.
2882- */
2883- if (reltuples >= 0 && !IsBinaryUpgrade )
2909+ if (update_stats )
28842910 {
2885- BlockNumber relpages = RelationGetNumberOfBlocks (rel );
2886- BlockNumber relallvisible ;
2887-
2888- if (rd_rel -> relkind != RELKIND_INDEX )
2889- visibilitymap_count (rel , & relallvisible , NULL );
2890- else /* don't bother for indexes */
2891- relallvisible = 0 ;
2892-
28932911 if (rd_rel -> relpages != (int32 ) relpages )
28942912 {
28952913 rd_rel -> relpages = (int32 ) relpages ;
0 commit comments