From 8ba82796a82354a10ab5adedfec0d823d07eefd8 Mon Sep 17 00:00:00 2001 From: ChangAo Chen Date: Sun, 14 Jun 2026 14:37:12 +0800 Subject: [PATCH v1] Handle concurrent drop when doing whole database vacuum. When doing a whole database vacuum, we scan pg_class to construct a list of vacuumable tables. For each vacuumable table, we call vacuum_is_permitted_for_relation() to check permissions. If a concurrent drop happens, the pg_class_aclcheck() might report an error because of failing to search the syscache. To fix it, we use pg_class_aclcheck_ext() to detect the concurrent drop and report a warning instead. --- src/backend/commands/vacuum.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index a4abb29cf64..4291cb8410c 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -721,6 +721,7 @@ vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple, uint32 options) { char *relname; + bool is_missing = false; Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0); @@ -733,16 +734,21 @@ vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple, */ if ((object_ownercheck(DatabaseRelationId, MyDatabaseId, GetUserId()) && !reltuple->relisshared) || - pg_class_aclcheck(relid, GetUserId(), ACL_MAINTAIN) == ACLCHECK_OK) + pg_class_aclcheck_ext(relid, GetUserId(), ACL_MAINTAIN, &is_missing) == ACLCHECK_OK) return true; relname = NameStr(reltuple->relname); if ((options & VACOPT_VACUUM) != 0) { - ereport(WARNING, - (errmsg("permission denied to vacuum \"%s\", skipping it", - relname))); + if (is_missing) + ereport(WARNING, + (errmsg("skipping vacuum of \"%s\" --- relation no longer exists", + relname))); + else + ereport(WARNING, + (errmsg("permission denied to vacuum \"%s\", skipping it", + relname))); /* * For VACUUM ANALYZE, both logs could show up, but just generate @@ -753,9 +759,16 @@ vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple, } if ((options & VACOPT_ANALYZE) != 0) - ereport(WARNING, - (errmsg("permission denied to analyze \"%s\", skipping it", - relname))); + { + if (is_missing) + ereport(WARNING, + (errmsg("skipping analyze of \"%s\" --- relation no longer exists", + relname))); + else + ereport(WARNING, + (errmsg("permission denied to analyze \"%s\", skipping it", + relname))); + } return false; } -- 2.54.0