Author: Noah Misch Commit: Noah Misch diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index 74d0f30..bef1af6 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -2806,6 +2806,9 @@ index_update_stats(Relation rel, bool hasindex, double reltuples) { + bool update_stats; + BlockNumber relpages; + BlockNumber relallvisible; Oid relid = RelationGetRelid(rel); Relation pg_class; ScanKeyData key[1]; @@ -2815,6 +2818,42 @@ index_update_stats(Relation rel, bool dirty; /* + * As a special hack, if we are dealing with an empty table and the + * existing reltuples is -1, we leave that alone. This ensures that + * creating an index as part of CREATE TABLE doesn't cause the table to + * prematurely look like it's been vacuumed. The final rd_rel may be + * different from rel->rd_rel due to e.g. commit of concurrent GRANT, but + * the commands that change reltuples take locks conflicting with ours. + * (Even if a command changed reltuples under a weaker lock, this affects + * only statistics for an empty table.) + */ + if (reltuples == 0 && rel->rd_rel->reltuples < 0) + reltuples = -1; + + /* + * Don't update statistics during binary upgrade, because the indexes are + * created before the data is moved into place. + */ + update_stats = reltuples >= 0 && !IsBinaryUpgrade; + + /* + * Finish I/O and visibility map buffer locks before + * systable_inplace_update_begin() locks the pg_class buffer. The final + * rd_rel may be different from rel->rd_rel due to e.g. commit of + * concurrent GRANT, but no command changes a relkind from non-index to + * index. (Even if one did, relallvisible doesn't break functionality.) + */ + if (update_stats) + { + relpages = RelationGetNumberOfBlocks(rel); + + if (rel->rd_rel->relkind != RELKIND_INDEX) + visibilitymap_count(rel, &relallvisible, NULL); + else /* don't bother for indexes */ + relallvisible = 0; + } + + /* * We always update the pg_class row using a non-transactional, * overwrite-in-place update. There are several reasons for this: * @@ -2858,15 +2897,6 @@ index_update_stats(Relation rel, /* Should this be a more comprehensive test? */ Assert(rd_rel->relkind != RELKIND_PARTITIONED_INDEX); - /* - * As a special hack, if we are dealing with an empty table and the - * existing reltuples is -1, we leave that alone. This ensures that - * creating an index as part of CREATE TABLE doesn't cause the table to - * prematurely look like it's been vacuumed. - */ - if (reltuples == 0 && rd_rel->reltuples < 0) - reltuples = -1; - /* Apply required updates, if any, to copied tuple */ dirty = false; @@ -2876,20 +2906,8 @@ index_update_stats(Relation rel, dirty = true; } - /* - * Avoid updating statistics during binary upgrade, because the indexes - * are created before the data is moved into place. - */ - if (reltuples >= 0 && !IsBinaryUpgrade) + if (update_stats) { - BlockNumber relpages = RelationGetNumberOfBlocks(rel); - BlockNumber relallvisible; - - if (rd_rel->relkind != RELKIND_INDEX) - visibilitymap_count(rel, &relallvisible, NULL); - else /* don't bother for indexes */ - relallvisible = 0; - if (rd_rel->relpages != (int32) relpages) { rd_rel->relpages = (int32) relpages;