diff --git a/src/backend/commands/statscmds.c b/src/backend/commands/statscmds.c index 6d8f4822b46..df6cb4a6f49 100644 --- a/src/backend/commands/statscmds.c +++ b/src/backend/commands/statscmds.c @@ -722,20 +722,14 @@ AlterStatistics(AlterStatsStmt *stmt) } /* - * Guts of statistics object deletion. - */ -void -RemoveStatisticsById(Oid statsOid) + * Delete entry in pg_statistic_ext_data catalog. +*/ +static void +RemoveStatisticsDataById(Oid statsOid) { Relation relation; HeapTuple tup; - Form_pg_statistic_ext statext; - Oid relid; - /* - * First delete the pg_statistic_ext_data tuple holding the actual - * statistical data. - */ relation = table_open(StatisticExtDataRelationId, RowExclusiveLock); tup = SearchSysCache1(STATEXTDATASTXOID, ObjectIdGetDatum(statsOid)); @@ -748,6 +742,19 @@ RemoveStatisticsById(Oid statsOid) ReleaseSysCache(tup); table_close(relation, RowExclusiveLock); +} + +/* + * Guts of statistics object deletion. + */ +void +RemoveStatisticsById(Oid statsOid) +{ + Relation relation; + Relation rel; + HeapTuple tup; + Form_pg_statistic_ext statext; + Oid relid; /* * Delete the pg_statistic_ext tuple. Also send out a cache inval on the @@ -763,12 +770,24 @@ RemoveStatisticsById(Oid statsOid) statext = (Form_pg_statistic_ext) GETSTRUCT(tup); relid = statext->stxrelid; + /* + * Delete the pg_statistic_ext_data tuple holding the actual statistical + * data. We lock the user table first, to prevent other processes (e.g. + * DROP STATISTICS) from removing the row concurrently. + */ + rel = table_open(relid, ShareUpdateExclusiveLock); + + RemoveStatisticsDataById(statsOid); + CacheInvalidateRelcacheByRelid(relid); CatalogTupleDelete(relation, &tup->t_self); ReleaseSysCache(tup); + /* Keep lock until the end of the transaction. */ + table_close(rel, NoLock); + table_close(relation, RowExclusiveLock); }