@@ -2782,6 +2782,9 @@ index_update_stats(Relation rel,
2782
2782
bool hasindex ,
2783
2783
double reltuples )
2784
2784
{
2785
+ bool update_stats ;
2786
+ BlockNumber relpages ;
2787
+ BlockNumber relallvisible ;
2785
2788
Oid relid = RelationGetRelid (rel );
2786
2789
Relation pg_class ;
2787
2790
ScanKeyData key [1 ];
@@ -2790,6 +2793,42 @@ index_update_stats(Relation rel,
2790
2793
Form_pg_class rd_rel ;
2791
2794
bool dirty ;
2792
2795
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
+
2793
2832
/*
2794
2833
* We always update the pg_class row using a non-transactional,
2795
2834
* overwrite-in-place update. There are several reasons for this:
@@ -2834,15 +2873,6 @@ index_update_stats(Relation rel,
2834
2873
/* Should this be a more comprehensive test? */
2835
2874
Assert (rd_rel -> relkind != RELKIND_PARTITIONED_INDEX );
2836
2875
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
-
2846
2876
/* Apply required updates, if any, to copied tuple */
2847
2877
2848
2878
dirty = false;
@@ -2852,20 +2882,8 @@ index_update_stats(Relation rel,
2852
2882
dirty = true;
2853
2883
}
2854
2884
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 )
2860
2886
{
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
-
2869
2887
if (rd_rel -> relpages != (int32 ) relpages )
2870
2888
{
2871
2889
rd_rel -> relpages = (int32 ) relpages ;
0 commit comments